1
0
mirror of https://github.com/jaandrle/deka-dom-el synced 2025-04-02 20:15:53 +02:00

dde and docs improvements (#27)

*  🎉

*  wip

* 🔤

*  wip

*  wip

*  Refatc signals to .get/.set syntax #26

* 🐛 Better types for on*

* 🔤

* 🔤

* 🐛 coumputed signal

* 🔤  Docs UI/UX

*  🔤 UI enhancements

*  (bs) (un)min

* 🔤 adds debugging

* 🔤 ssr

* 🔤

*  bs/lint

* 🔤

* 🔤 UI

* 🔤 updates texts

* 🔤UI

*  dispatch

* 🔤 events

* 🔤 elements

* 🔤 intro

* 🐛 fixes completitions for el with components

* 🐛 wrong file(s) in git

* 🔤 logo

* 🐛 🔤 types 3ps

* 🔤 ui/ux

* 🔤

* 🔤

* 🔤 scopes

* 🔤

* 🔤 ui/ux

* 🔤

*  issignal

* 🔤 improvemens

*  irelands

* 🔤 UI/UX/wording

* 🐛 npx-hint

[Scrollable region must have keyboard access | Axe Rules | Deque University | Deque Systems](https://dequeuniversity.com/rules/axe/4.10/scrollable-region-focusable?application=axeAPI)

* 🔤 logos

*  better? dts builds

* Update README.md
This commit is contained in:
Jan Andrle 2025-03-07 14:40:45 +01:00 committed by GitHub
parent dba4e93b88
commit 4366027658
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
110 changed files with 16261 additions and 4741 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
dist/docs/ dist/docs/
dist/.*
# Logs # Logs
logs logs
*.log *.log

166
README.md
View File

@ -2,94 +2,120 @@
| [source code on GitHub](https://github.com/jaandrle/deka-dom-el) | [source code on GitHub](https://github.com/jaandrle/deka-dom-el)
| [*mirrored* on Gitea](https://gitea.jaandrle.cz/jaandrle/deka-dom-el) | [*mirrored* on Gitea](https://gitea.jaandrle.cz/jaandrle/deka-dom-el)
<p align="center">
<img src="docs/assets/logo.svg" alt="Deka DOM Elements Logo" width="180" height="180">
</p>
# Deka DOM Elements
***Vanilla for flavouring — a full-fledged feast for large projects*** ***Vanilla for flavouring — a full-fledged feast for large projects***
*…use simple DOM API by default and library tools and logic when you need them* *…use simple DOM API by default and library tools and logic when you need them*
```javascript ```javascript
// 🌟 Reactive component with clear separation of concerns
document.body.append( document.body.append(
el(HelloWorldComponent, { initial: "🚀" }) el(EmojiCounter, { initial: "🚀" })
); );
/** @typedef {"🎉" | "🚀"} Emoji */
/** @param {{ initial: Emoji }} attrs */ function EmojiCounter({ initial }) {
function HelloWorldComponent({ initial }){ // ✨ State - Define reactive data
const clicks= S(0); const count = S(0);
const emoji= S(initial); const emoji = S(initial);
/** @param {HTMLOptionElement} el */ /** @param {HTMLOptionElement} el */
const isSelected= el=> (el.selected= el.value===initial); const isSelected= el=> (el.selected= el.value===initial);
// @ts-expect-error 2339: The <select> has only two options with {@link Emoji}
const onChange= on("change", event=> emoji(event.target.value)); // 🔄 View - UI updates automatically when signals change
return el().append( return el().append(
el("p", { el("p", {
textContent: S(() => `Hello World ${emoji().repeat(clicks())}`), className: "output",
className: "example", textContent: S(() =>
ariaLive: "polite", //OR ariaset: { live: "polite" }, `Hello World ${emoji.get().repeat(clicks.get())}`),
dataset: { example: "Example" }, //OR dataExample: "Example", }),
}),
el("button", // 🎮 Controls - Update state on events
{ textContent: "Fire", type: "button" }, el("button", { textContent: "Add Emoji" },
on("click", ()=> clicks(clicks() + 1)), on("click", () => count.set(count.get() + 1))
on("keyup", ()=> clicks(clicks() - 2)), ),
),
el("select", null, onChange).append( el("select", null, on("change", e => emoji.set(e.target.value)))
el(OptionComponent, "🎉", isSelected),//OR { textContent: "🎉" } .append(
el(OptionComponent, "🚀", isSelected),//OR { textContent: "🚀" } el(Option, "🎉", isSelected),
) el(Option, "🚀", isSelected),
el(Option, "💖", isSelected),
)
); );
} }
function OptionComponent({ textContent }){ function Option({ textContent }){
return el("option", { value: textContent, textContent }) return el("option", { value: textContent, textContent });
} }
``` ```
# Deka DOM Elements
Creating reactive elements, components and Web components using [IDL](https://developer.mozilla.org/en-US/docs/
Glossary/IDL)/JavaScript DOM API and [**signals/observables**](#signals).
## Inspiration and suggested alternatives Creating reactive elements, components, and Web Components using the native
- my previous library (mostly used internaly): [jaandrle/dollar_dom_component: Functional DOM components without [IDL](https://developer.mozilla.org/en-US/docs/Glossary/IDL)/JavaScript DOM API enhanced with
JSX and virtual DOM.](https://github.com/jaandrle/dollar_dom_component) [**signals/observables**](#understanding-signals).
- [vanjs-org/van: 🍦 VanJS: World's smallest reactive UI framework. Incredibly Powerful, Insanely Small -
Everyone can build a useful UI app in an hour.](https://github.com/vanjs-org/van)
- [hyperhype/hyperscript: Create HyperText with JavaScript.](https://github.com/hyperhype/hyperscript)
- [adamhaile/S: S.js - Simple, Clean, Fast Reactive Programming in Javascript](https://github.com/adamhaile/S)
([adamhaile/surplus: High performance JSX web views for S.js applications](https://github.com/adamhaile/surplus))
- [potch/signals: a small reactive signals library](https://github.com/potch/signals)
## Why an another one? ## Features at a Glance
This library falls somewhere between van/hyperscript and [solid-js](https://github.com/solidjs/solid) in terms of size,
complexity, and usability.
Another goal is to proceed in the best spirit of functional programming. This involves starting with - ✅ **No build step required** — use directly in browsers or Node.js
pure JavaScript (DOM API) and gradually adding auxiliary functions, ranging from “minor” improvements - ☑️ **Lightweight** — ~10-15kB minified (original goal 10kB) with zero/minimal dependencies
to the capability of writing complete declarative reactive UI templates. - ✅ **Declarative & functional approach** for clean, maintainable code
- ✅ **Optional signals** with support for custom reactive implementations
- ✅ **Server-side rendering** support via [jsdom](https://github.com/jsdom/jsdom)
- 🔄 **TypeScript support** (work in progress)
- 🔄 **Enhanced Web Components** support (work in progress)
As a result, any “internal” function (`assign`, `classListDeclarative`, `on`, `dispatchEvent`, …, `S`, …) ## Why Another Library?
can be used independently, although they are primarily designed for use in combination. This can also,
hopefully, help in integrating the library into existing projects.
To balance these requirements, numerous compromises have been made. To summarize: This library bridges the gap between minimal solutions like van/hyperscript and more comprehensive frameworks like
- [ ] Library size: 1015kB minified (the original goal was a maximum of 10kB) [solid-js](https://github.com/solidjs/solid), offering a balanced trade-off between size, complexity, and usability.
- [x] Optional use of *signals* with the ability to register *your own signals/observables implementation*
- [x] *No build step required*
- [x] Preference for a *declarative/functional* approach
- [x] Focus on zero/minimal dependencies
- [ ] Support for/enhancement of custom elements (web components)
- [x] Support for SSR ([jsdom](https://github.com/jsdom/jsdom))
- [ ] WIP providing types
## First steps Following functional programming principles, Deka DOM Elements starts with pure JavaScript (DOM API) and gradually adds
- [**Guide**](https://jaandrle.github.io/deka-dom-el) auxiliary functions. These range from minor improvements to advanced features for building complete declarative
- Documentation reactive UI templates.
- Installation
- npm
- [dist/](dist/) (`https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/`…)
## Signals A key advantage: any internal function (`assign`, `classListDeclarative`, `on`, `dispatchEvent`, `S`, etc.) can be used
- [Signals — whats going on behind the scenes | by Ryan Hoffnan | ITNEXT](https://itnext.io/ independently while also working seamlessly together. This modular approach makes it easier to integrate the library
signals-whats-going-on-behind-the-scenes-ec858589ea63) into existing projects.
- [The Evolution of Signals in JavaScript - DEV Community](https://dev.to/this-is-learning/the-evolution-of-signals-in-
javascript-8ob) ## Getting Started
- there is also [tc39/proposal-signals: A proposal to add signals to JavaScript.](https://github.com/tc39/proposal-
signals) ### Installation
- [Observer pattern - Wikipedia](https://en.wikipedia.org/wiki/Observer_pattern)
#### npm
```bash
# TBD
# npm install deka-dom-el
```
#### Direct Script
```html
<script src="https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/dde-with-signals.min.js"></script>
<script type="module">
const { el, S } = dde;
</script>
```
### Documentation
- [**Interactive Guide**](https://jaandrle.github.io/deka-dom-el): WIP
- [Examples](./examples/): TBD/WIP
## Understanding Signals
Signals are the reactive backbone of Deka DOM Elements:
- [Signals — what's going on behind the scenes](https://itnext.io/signals-whats-going-on-behind-the-scenes-ec858589ea63)
- [The Evolution of Signals in JavaScript](https://dev.to/this-is-learning/the-evolution-of-signals-in-javascript-8ob)
- [TC39 Signals Proposal](https://github.com/tc39/proposal-signals) (future standard)
- [Observer pattern](https://en.wikipedia.org/wiki/Observer_pattern) (underlying concept)
## Inspiration and Alternatives
- [vanjs-org/van](https://github.com/vanjs-org/van) - World's smallest reactive UI framework
- [adamhaile/S](https://github.com/adamhaile/S) - Simple, clean, fast reactive programming
- [hyperhype/hyperscript](https://github.com/hyperhype/hyperscript) - Create HyperText with JavaScript
- [potch/signals](https://github.com/potch/signals) - A small reactive signals library
- [jaandrle/dollar_dom_component](https://github.com/jaandrle/dollar_dom_component) -
Functional DOM components without JSX/virtual DOM

View File

@ -1,71 +1,37 @@
#!/usr/bin/env -S npx nodejsscript #!/usr/bin/env -S npx nodejsscript
import { bundle as bundleDTS } from "dts-bundler"; import { build } from "./dev/.build.js"
const files= [ "index", "index-with-signals" ]; const files= [ "index", "index-with-signals" ];
const filesOut= (file, mark= "esm")=> "dist/"+file.replace("index", mark);
const css= echo.css`
.info{ color: gray; }
`;
$.api("", true) $.api("")
.option("--minify", "Level of minification [ no, full, partial (default) ]") .command("main", "Build main files", { default: true })
.action(async function main({ minify= "partial" }){ .action(async function main(){
for(const file_root of files){ const regular = await build({
const file= file_root+".js"; files,
echo("Processing: "+ file); filesOut,
const out= filesOut(file); minify: "no",
const esbuild_output= s.$().run([ });
"npx esbuild '::file::'", const min = await build({
"--platform=neutral", files,
"--bundle", filesOut(file, mark= "esm"){
minifyOption(minify), const out= filesOut(file, mark);
"--legal-comments=inline", const idx= out.lastIndexOf(".");
"--packages=external", return out.slice(0, idx)+".min"+out.slice(idx);
"--outfile='::out::'" },
].filter(Boolean).join(" "), { file, out }); minify: "full",
if(esbuild_output.code) });
return $.exit(esbuild_output.code, echo(esbuild_output.stderr)); return $.exit(regular + min);
echoVariant(esbuild_output.stderr.split("\n")[1].trim()+ " (esbuild)"); })
pipe( .command("signals", "Build only signals (for example for analysis)")
f=> f.replace(/^ +/gm, m=> "\t".repeat(m.length/2)), .action(async function signals(){
f=> s.echo(f).to(out) const regular = await build({
)(s.cat(out)); files: [ "signals" ],
filesOut(file){ return "dist/."+file; },
const file_dts= file_root+".d.ts"; minify: "no",
const file_dts_out= filesOut(file_dts); dde: false,
echoVariant(file_dts_out); });
s.echo(bundleDTS(file_dts)).to(file_dts_out); return $.exit(regular);
await toDDE(out, file_root);
}
$.exit(0);
async function toDDE(file, file_root){
const name= "dde";
const out= filesOut(file_root+".js", name);
echoVariant(`${out} (${file} → globalThis.${name})`)
let content= s.cat(file).toString().split(/export ?{/);
content.splice(1, 0, `\nglobalThis.${name}= {`);
content[2]= content[2]
.replace(/,(?!\n)/g, ",\n")
.replace(/(?<!\n)}/, "\n}")
.replace(/^(\t*)(.*) as ([^,\n]*)(,?)$/mg, "$1$3: $2$4");
s.echo([
`//deka-dom-el library is available via global namespace \`${name}\``,
"(()=> {",
content.join(""),
"})();"
].join("\n")).to(out);
}
}) })
.parse(); .parse();
/** @param {"no"|"full"|"partial"} level */
function minifyOption(level= "partial"){ function filesOut(file, mark= "esm"){ return "dist/"+file.replace("index", mark); }
if("no"===level) return undefined;
if("full"===level) return "--minify";
return "--minify-syntax --minify-identifiers";
}
function echoVariant(name){
return echo("%c✓ "+name, css.info+css);
}

108
bs/dev/.build.js Normal file
View File

@ -0,0 +1,108 @@
#!/usr/bin/env -S npx nodejsscript
import { bundle, bundle as bundleDTS } from "dts-bundler";
const css= echo.css`
.info{ color: gray; }
`;
export async function build({ files, filesOut, minify= "partial", dde= true }){
for(const file_root of files){
const file= file_root+".js";
echo(`Processing ${file} (minified: ${minify})`);
const out= filesOut(file);
const esbuild_output= buildEsbuild({ file, out, minify });
echoVariant(esbuild_output.stderr.split("\n")[1].trim()+ " (esbuild)");
const file_dts= file_root+".d.ts";
const file_dts_out= filesOut(file_dts);
echoVariant(file_dts_out, true);
buildDts({
bundle: out,
entry: file_dts,
});
echoVariant(file_dts_out);
if(dde) toDDE(file, file_root);
}
return 0;
async function toDDE(file, file_root){
const name= "dde";
const out= filesOut(file_root+".js", name);
const params= [
"--format=iife",
"--global-name="+name,
];
const dde_output= buildEsbuild({ file, out, minify, params });
echoVariant(`${out} (${file} → globalThis.${name})`)
const file_dts= file_root+".d.ts";
const file_dts_out= filesOut(file_dts, name);
echoVariant(file_dts_out, true);
buildDts({
name,
bundle: out,
entry: file_dts,
})
echoVariant(file_dts_out);
return dde_output;
}
}
export function buildDts({ bundle, entry, name }){
const out= bundle.slice(0, bundle.lastIndexOf("."))+".d.ts";
const dts_b_g_output= s.run([
"npx dts-bundle-generator",
"--silent",
"-o ::out::",
!name ? false : ("--umd-module-name "+name),
"--inline-declare-global",
"::entry::"
].filter(Boolean).join(" "), { out, entry });
return dts_b_g_output;
}
class ErrorEsbuild extends Error{
constructor({ code, stderr }){
super(stderr);
this.code= code;
this.stderr= stderr;
}
}
function buildEsbuild({ file, out, minify= "partial", params= [] }){
try {
return esbuild({ file, out, minify, params });
} catch(e){
if(e instanceof ErrorEsbuild)
return $.exit(e.code, echo(e.stderr));
throw e;
}
}
export function esbuild({ file, out, minify= "partial", params= [] }){
const esbuild_output= s.$().run([
"npx esbuild '::file::'",
"--platform=neutral",
"--bundle",
minifyOption(minify),
"--legal-comments=inline",
"--packages=external",
...params,
"--outfile='::out::'"
].filter(Boolean).join(" "), { file, out });
if(esbuild_output.code)
throw new ErrorEsbuild(esbuild_output);
pipe(
f=> f.replace(/^ +/gm, m=> "\t".repeat(m.length/2)),
f=> s.echo(f).to(out)
)(s.cat(out));
return esbuild_output;
}
/** @param {"no"|"full"|"partial"} level */
function minifyOption(level= "partial"){
if("no"===level) return undefined;
if("full"===level) return "--minify";
return "--minify-syntax --minify-identifiers";
}
function echoVariant(name, todo= false){
if(todo) return echo.use("-R", "~ "+name);
return echo("%c✓ "+name, css.info);
}

View File

@ -4,7 +4,7 @@ echo("Building static documentation files…");
echo("Preparing…"); echo("Preparing…");
import { path_target, pages as pages_registered, styles, dispatchEvent, t } from "../docs/ssr.js"; import { path_target, pages as pages_registered, styles, dispatchEvent, t } from "../docs/ssr.js";
import { createHTMl } from "./docs/jsdom.js"; import { createHTMl } from "./docs/jsdom.js";
import { register } from "../jsdom.js"; import { register, queue } from "../jsdom.js";
const pkg= s.cat("package.json").xargs(JSON.parse); const pkg= s.cat("package.json").xargs(JSON.parse);
if(s.test("-d", path_target.root)){ if(s.test("-d", path_target.root)){
@ -14,6 +14,10 @@ if(s.test("-d", path_target.root)){
echo("Creating directory…"); echo("Creating directory…");
s.mkdir("-p", path_target.root); s.mkdir("-p", path_target.root);
} }
// Create assets directory in target
echo("Creating assets directory…");
s.mkdir("-p", path_target.root+"assets");
echo("Collecting list of pages…"); echo("Collecting list of pages…");
const pages= s.ls($.xdg.main`../docs/*.html.js`).map(addPage); const pages= s.ls($.xdg.main`../docs/*.html.js`).map(addPage);
for(const { id, info } of pages){ for(const { id, info } of pages){
@ -27,12 +31,20 @@ for(const { id, info } of pages){
serverDOM.document.body.append( serverDOM.document.body.append(
el(page, { pkg, info }), el(page, { pkg, info }),
); );
await queue();
echo.use("-R", `Writing ${id}.html…`); echo.use("-R", `Writing ${id}.html…`);
dispatchEvent("oneachrender", document); dispatchEvent("oneachrender", document);
s.echo(serverDOM.serialize()).to(path_target.root+id+".html"); s.echo(serverDOM.serialize()).to(path_target.root+id+".html");
} }
s.echo(styles.content).to(path_target.css+styles.name); s.echo(styles.content).to(path_target.css+styles.name);
// Copy assets
echo("Copying assets…");
if(s.test("-d", "docs/assets")) {
s.cp("-r", "docs/assets/*", path_target.assets);
}
dispatchEvent("onssrend"); dispatchEvent("onssrend");
echo("Done"); echo("Done");

View File

@ -1,5 +1,5 @@
import { JSDOM } from "jsdom"; import { JSDOM } from "jsdom";
const html_default= "<!doctype html><html><head><meta charset=\"utf-8\"></head><body></body></html>"; const html_default= "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"></head><body></body></html>";
let keys= []; let keys= [];
let dom= null; let dom= null;
import { relative } from 'node:path'; import { relative } from 'node:path';

785
dist/dde-with-signals.d.ts vendored Normal file
View File

@ -0,0 +1,785 @@
// Generated by dts-bundle-generator v9.5.1
export interface Signal<V, A> {
/** The current value of the signal */
get(): V;
/** Set new value of the signal */
set(value: V): V;
toJSON(): V;
valueOf(): V;
}
export type Action<V> = (this: {
value: V;
stopPropagation(): void;
}, ...a: any[]) => typeof signal._ | void;
//type SymbolSignal= Symbol;
export type SymbolOnclear = symbol;
export type Actions<V> = Record<string | SymbolOnclear, Action<V>>;
export type OnListenerOptions = Pick<AddEventListenerOptions, "signal"> & {
first_time?: boolean;
};
export interface signal {
_: Symbol;
/**
* Computations signal. This creates a signal which is computed from other signals.
* */
<V extends () => any>(computation: V): Signal<ReturnType<V>, {}>;
/**
* Simple example:
* ```js
* const hello= S("Hello Signal");
* ```
* simple todo signal:
* ```js
* const todos= S([], {
* add(v){ this.value.push(S(v)); },
* remove(i){ this.value.splice(i, 1); },
* [S.symbols.onclear](){ S.clear(...this.value); },
* });
* ```
* computed signal:
* ```js
* const name= S("Jan");
* const surname= S("Andrle");
* const fullname= S(()=> name.get()+" "+surname.get());
* ```
* @param value Initial signal value. Or function computing value from other signals.
* @param actions Use to define actions on the signal. Such as add item to the array.
* There is also a reserved function `S.symbol.onclear` which is called when the signal is cleared
* by `S.clear`.
* */
<V, A extends Actions<V>>(value: V, actions?: A): Signal<V, A>;
action<S extends Signal<any, Actions<any>>, A extends (S extends Signal<any, infer A> ? A : never), N extends keyof A>(signal: S, name: N, ...params: A[N] extends (...args: infer P) => any ? P : never): void;
clear(...signals: Signal<any, any>[]): void;
on<T>(signal: Signal<T, any>, onchange: (a: T) => void, options?: OnListenerOptions): void;
symbols: {
//signal: SymbolSignal;
onclear: SymbolOnclear;
};
/**
* Reactive element, which is rendered based on the given signal.
* ```js
* S.el(signal, value=> value ? el("b", "True") : el("i", "False"));
* S.el(listS, list=> list.map(li=> el("li", li)));
* ```
* */
el<S extends any>(signal: Signal<S, any>, el: (v: S) => Element | Element[] | DocumentFragment): DocumentFragment;
observedAttributes(custom_element: HTMLElement): Record<string, Signal<string, {}>>;
}
export const signal: signal;
export const S: signal;
declare global {
type ddeSignal<T, A = {}> = Signal<T, A>;
type ddeAction<V> = Action<V>;
type ddeActions<V> = Actions<V>;
}
export type CustomElementTagNameMap = {
"#text": Text;
"#comment": Comment;
};
export type SupportedElement = HTMLElementTagNameMap[keyof HTMLElementTagNameMap] | SVGElementTagNameMap[keyof SVGElementTagNameMap] | MathMLElementTagNameMap[keyof MathMLElementTagNameMap] | CustomElementTagNameMap[keyof CustomElementTagNameMap];
declare global {
type ddeComponentAttributes = Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment | Node> = (element: El) => any;
type ddeString = string | Signal<string, {}>;
type ddeStringable = ddeString | number | Signal<number, {}>;
}
export type PascalCase = `${Capitalize<string>}${string}`;
export type AttrsModified = {
/**
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/
style: Partial<CSSStyleDeclaration> | ddeString | Partial<{
[K in keyof CSSStyleDeclaration]: Signal<CSSStyleDeclaration[K], {}>;
}>;
/**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1.
* In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))`
* for others.
*/
classList: Record<string, -1 | 0 | 1 | boolean | Signal<-1 | 0 | 1 | boolean, {}>>;
/**
* Used by the dataset HTML attribute to represent data for custom attributes added to elements.
* Values are converted to string (see {@link DOMStringMap}).
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMStringMap)
* */
dataset: Record<string, ddeStringable>;
/**
* Sets `aria-*` simiraly to `dataset`
* */
ariaset: Record<string, ddeString>;
} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, ddeString> & Record<`.${string}`, any>;
export type _fromElsInterfaces<EL extends SupportedElement> = Omit<EL, keyof AttrsModified>;
export type IsReadonly<T, K extends keyof T> = T extends {
readonly [P in K]: T[K];
} ? true : false;
/**
* Just element attributtes
*
* In most cases, you can use native propertie such as
* [MDN WEB/API/Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) and so on
* (e.g. [`Text`](https://developer.mozilla.org/en-US/docs/Web/API/Text)).
*
* There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives.
* @private
*/
export type ElementAttributes<T extends SupportedElement> = Partial<{
[K in keyof _fromElsInterfaces<T>]: _fromElsInterfaces<T>[K] extends ((...p: any[]) => any) ? _fromElsInterfaces<T>[K] | ((...p: Parameters<_fromElsInterfaces<T>[K]>) => Signal<ReturnType<_fromElsInterfaces<T>[K]>, {}>) : (IsReadonly<_fromElsInterfaces<T>, K> extends false ? _fromElsInterfaces<T>[K] | Signal<_fromElsInterfaces<T>[K], {}> : ddeStringable);
} & AttrsModified> & Record<string, any>;
export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El;
export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El;
export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT];
export type ExtendedHTMLElementTagNameMap = HTMLElementTagNameMap & CustomElementTagNameMap;
export namespace el {
/**
* Creates a marker comment for elements
*
* @param attrs - Marker attributes
* @param [is_open=false] - Whether the marker is open-ended
* @returns Comment node marker
*/
export function mark(attrs: {
type: "component" | "reactive" | "later";
name?: string;
host?: "this" | "parentElement";
}, is_open?: boolean): Comment;
}
export function el<A extends ddeComponentAttributes, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>, ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
export function el<A extends {
textContent: ddeStringable;
}, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>["textContent"], ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
export function el<TAG extends keyof ExtendedHTMLElementTagNameMap>(tag_name: TAG, attrs?: ElementAttributes<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]> | ddeStringable, ...addons: ddeElementAddon<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]>[]): TAG extends keyof ddeHTMLElementTagNameMap ? ddeHTMLElementTagNameMap[TAG] : ddeHTMLElement;
export function el(tag_name?: "<>"): ddeDocumentFragment;
export function el(tag_name: string, attrs?: ElementAttributes<HTMLElement> | ddeStringable, ...addons: ddeElementAddon<HTMLElement>[]): ddeHTMLElement;
export function elNS(namespace: "http://www.w3.org/2000/svg"): <TAG extends keyof SVGElementTagNameMap & string, EL extends (TAG extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[TAG] : SVGElement)>(tag_name: TAG, attrs?: ElementAttributes<NoInfer<EL>> | ddeStringable, ...addons: ddeElementAddon<NoInfer<EL>>[]) => TAG extends keyof ddeSVGElementTagNameMap ? ddeSVGElementTagNameMap[TAG] : ddeSVGElement;
export function elNS(namespace: "http://www.w3.org/1998/Math/MathML"): <TAG extends keyof MathMLElementTagNameMap & string, EL extends (TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement)>(tag_name: TAG, attrs?: ddeStringable | Partial<{
[key in keyof EL]: EL[key] | Signal<EL[key], {}> | string | number | boolean;
}>, ...addons: ddeElementAddon<NoInfer<EL>>[]) => ddeMathMLElement;
export function elNS(namespace: string): (tag_name: string, attrs?: string | ddeStringable | Record<string, any>, ...addons: ddeElementAddon<SupportedElement>[]) => SupportedElement;
export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
/** Simulate slots for ddeComponents */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(root: EL): EL;
/**
* Simulate slots in Custom Elements without using `shadowRoot`.
* @param el Custom Element root element
* @param body Body of the custom element
* */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: HTMLElement, body: EL): EL;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, element: SupportedElement): (data?: any) => void;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options?: EventInit): (element: SupportedElement, data?: any) => void;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, element: SupportedElement | (() => SupportedElement)): (data?: any) => void;
export interface On {
/** Listens to the DOM event. See {@link Document.addEventListener} */
<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE;
<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[
string,
string
]>) => any, options?: AddEventListenerOptions): EE;
}
export const on: On;
export type Scope = {
scope: Node | Function | Object;
host: ddeElementAddon<any>;
custom_element: false | HTMLElement;
prevent: boolean;
};
/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */
export const scope: {
current: Scope;
/** Stops all automatizations. E. g. signals used as attributes in current scope
* registers removing these listeners (and clean signal if no other listeners are detected)
* on `disconnected` event. */
preventDefault<T extends boolean>(prevent: T): T;
/**
* This represents reference to the current host element `scope.host()`.
* It can be also used to register Addon(s) (functions to be called when component is initized)
* `scope.host(on.connected(console.log))`.
* */
host: (...addons: ddeElementAddon<SupportedElement>[]) => HTMLElement;
state: Scope[];
/** Adds new child scope. All attributes are inherited by default. */
push(scope?: Partial<Scope>): ReturnType<Array<Scope>["push"]>;
/** Adds root scope as a child of the current scope. */
pushRoot(): ReturnType<Array<Scope>["push"]>;
/** Removes last/current child scope. */
pop(): ReturnType<Array<Scope>["pop"]>;
};
export function customElementRender<EL extends HTMLElement, P extends any = Record<string, string | Signal<string, {}>>>(target: ShadowRoot | EL, render: (props: P) => SupportedElement | DocumentFragment, props?: P | ((el: EL) => P)): EL;
export function customElementWithDDE<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
export function lifecyclesToEvents<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
export function observedAttributes(custom_element: HTMLElement): Record<string, string>;
/**
* This is used primarly for server side rendering. To be sure that all async operations
* are finished before the page is sent to the client.
* ```
* // on component
* function component(){
*
* queue(fetch(...).then(...));
* }
*
* // building the page
* async function build(){
* const { component }= await import("./component.js");
* document.body.append(el(component));
* await queue();
* retutn document.body.innerHTML;
* }
* ```
* */
export function queue(promise?: Promise<unknown>): Promise<unknown>;
/* TypeScript MEH */
declare global {
type ddeAppend<el> = (...nodes: (Node | string)[]) => el;
interface ddeDocumentFragment extends DocumentFragment {
append: ddeAppend<ddeDocumentFragment>;
}
interface ddeHTMLElement extends HTMLElement {
append: ddeAppend<ddeHTMLElement>;
}
interface ddeSVGElement extends SVGElement {
append: ddeAppend<ddeSVGElement>;
}
interface ddeMathMLElement extends MathMLElement {
append: ddeAppend<ddeMathMLElement>;
}
interface ddeHTMLElementTagNameMap {
"a": ddeHTMLAnchorElement;
"area": ddeHTMLAreaElement;
"audio": ddeHTMLAudioElement;
"base": ddeHTMLBaseElement;
"blockquote": ddeHTMLQuoteElement;
"body": ddeHTMLBodyElement;
"br": ddeHTMLBRElement;
"button": ddeHTMLButtonElement;
"canvas": ddeHTMLCanvasElement;
"caption": ddeHTMLTableCaptionElement;
"col": ddeHTMLTableColElement;
"colgroup": ddeHTMLTableColElement;
"data": ddeHTMLDataElement;
"datalist": ddeHTMLDataListElement;
"del": ddeHTMLModElement;
"details": ddeHTMLDetailsElement;
"dialog": ddeHTMLDialogElement;
"div": ddeHTMLDivElement;
"dl": ddeHTMLDListElement;
"embed": ddeHTMLEmbedElement;
"fieldset": ddeHTMLFieldSetElement;
"form": ddeHTMLFormElement;
"h1": ddeHTMLHeadingElement;
"h2": ddeHTMLHeadingElement;
"h3": ddeHTMLHeadingElement;
"h4": ddeHTMLHeadingElement;
"h5": ddeHTMLHeadingElement;
"h6": ddeHTMLHeadingElement;
"head": ddeHTMLHeadElement;
"hr": ddeHTMLHRElement;
"html": ddeHTMLHtmlElement;
"iframe": ddeHTMLIFrameElement;
"img": ddeHTMLImageElement;
"input": ddeHTMLInputElement;
"ins": ddeHTMLModElement;
"label": ddeHTMLLabelElement;
"legend": ddeHTMLLegendElement;
"li": ddeHTMLLIElement;
"link": ddeHTMLLinkElement;
"map": ddeHTMLMapElement;
"menu": ddeHTMLMenuElement;
"meta": ddeHTMLMetaElement;
"meter": ddeHTMLMeterElement;
"object": ddeHTMLObjectElement;
"ol": ddeHTMLOListElement;
"optgroup": ddeHTMLOptGroupElement;
"option": ddeHTMLOptionElement;
"output": ddeHTMLOutputElement;
"p": ddeHTMLParagraphElement;
"picture": ddeHTMLPictureElement;
"pre": ddeHTMLPreElement;
"progress": ddeHTMLProgressElement;
"q": ddeHTMLQuoteElement;
"script": ddeHTMLScriptElement;
"select": ddeHTMLSelectElement;
"slot": ddeHTMLSlotElement;
"source": ddeHTMLSourceElement;
"span": ddeHTMLSpanElement;
"style": ddeHTMLStyleElement;
"table": ddeHTMLTableElement;
"tbody": ddeHTMLTableSectionElement;
"td": ddeHTMLTableCellElement;
"template": ddeHTMLTemplateElement;
"textarea": ddeHTMLTextAreaElement;
"tfoot": ddeHTMLTableSectionElement;
"th": ddeHTMLTableCellElement;
"thead": ddeHTMLTableSectionElement;
"time": ddeHTMLTimeElement;
"title": ddeHTMLTitleElement;
"tr": ddeHTMLTableRowElement;
"track": ddeHTMLTrackElement;
"ul": ddeHTMLUListElement;
"video": ddeHTMLVideoElement;
}
interface ddeSVGElementTagNameMap {
"a": ddeSVGAElement;
"animate": ddeSVGAnimateElement;
"animateMotion": ddeSVGAnimateMotionElement;
"animateTransform": ddeSVGAnimateTransformElement;
"circle": ddeSVGCircleElement;
"clipPath": ddeSVGClipPathElement;
"defs": ddeSVGDefsElement;
"desc": ddeSVGDescElement;
"ellipse": ddeSVGEllipseElement;
"feBlend": ddeSVGFEBlendElement;
"feColorMatrix": ddeSVGFEColorMatrixElement;
"feComponentTransfer": ddeSVGFEComponentTransferElement;
"feComposite": ddeSVGFECompositeElement;
"feConvolveMatrix": ddeSVGFEConvolveMatrixElement;
"feDiffuseLighting": ddeSVGFEDiffuseLightingElement;
"feDisplacementMap": ddeSVGFEDisplacementMapElement;
"feDistantLight": ddeSVGFEDistantLightElement;
"feDropShadow": ddeSVGFEDropShadowElement;
"feFlood": ddeSVGFEFloodElement;
"feFuncA": ddeSVGFEFuncAElement;
"feFuncB": ddeSVGFEFuncBElement;
"feFuncG": ddeSVGFEFuncGElement;
"feFuncR": ddeSVGFEFuncRElement;
"feGaussianBlur": ddeSVGFEGaussianBlurElement;
"feImage": ddeSVGFEImageElement;
"feMerge": ddeSVGFEMergeElement;
"feMergeNode": ddeSVGFEMergeNodeElement;
"feMorphology": ddeSVGFEMorphologyElement;
"feOffset": ddeSVGFEOffsetElement;
"fePointLight": ddeSVGFEPointLightElement;
"feSpecularLighting": ddeSVGFESpecularLightingElement;
"feSpotLight": ddeSVGFESpotLightElement;
"feTile": ddeSVGFETileElement;
"feTurbulence": ddeSVGFETurbulenceElement;
"filter": ddeSVGFilterElement;
"foreignObject": ddeSVGForeignObjectElement;
"g": ddeSVGGElement;
"image": ddeSVGImageElement;
"line": ddeSVGLineElement;
"linearGradient": ddeSVGLinearGradientElement;
"marker": ddeSVGMarkerElement;
"mask": ddeSVGMaskElement;
"metadata": ddeSVGMetadataElement;
"mpath": ddeSVGMPathElement;
"path": ddeSVGPathElement;
"pattern": ddeSVGPatternElement;
"polygon": ddeSVGPolygonElement;
"polyline": ddeSVGPolylineElement;
"radialGradient": ddeSVGRadialGradientElement;
"rect": ddeSVGRectElement;
"script": ddeSVGScriptElement;
"set": ddeSVGSetElement;
"stop": ddeSVGStopElement;
"style": ddeSVGStyleElement;
"svg": ddeSVGSVGElement;
"switch": ddeSVGSwitchElement;
"symbol": ddeSVGSymbolElement;
"text": ddeSVGTextElement;
"textPath": ddeSVGTextPathElement;
"title": ddeSVGTitleElement;
"tspan": ddeSVGTSpanElement;
"use": ddeSVGUseElement;
"view": ddeSVGViewElement;
}
}
// editorconfig-checker-disable
export interface ddeHTMLAnchorElement extends HTMLAnchorElement {
append: ddeAppend<ddeHTMLAnchorElement>;
}
export interface ddeHTMLAreaElement extends HTMLAreaElement {
append: ddeAppend<ddeHTMLAreaElement>;
}
export interface ddeHTMLAudioElement extends HTMLAudioElement {
append: ddeAppend<ddeHTMLAudioElement>;
}
export interface ddeHTMLBaseElement extends HTMLBaseElement {
append: ddeAppend<ddeHTMLBaseElement>;
}
export interface ddeHTMLQuoteElement extends HTMLQuoteElement {
append: ddeAppend<ddeHTMLQuoteElement>;
}
export interface ddeHTMLBodyElement extends HTMLBodyElement {
append: ddeAppend<ddeHTMLBodyElement>;
}
export interface ddeHTMLBRElement extends HTMLBRElement {
append: ddeAppend<ddeHTMLBRElement>;
}
export interface ddeHTMLButtonElement extends HTMLButtonElement {
append: ddeAppend<ddeHTMLButtonElement>;
}
export interface ddeHTMLCanvasElement extends HTMLCanvasElement {
append: ddeAppend<ddeHTMLCanvasElement>;
}
export interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement {
append: ddeAppend<ddeHTMLTableCaptionElement>;
}
export interface ddeHTMLTableColElement extends HTMLTableColElement {
append: ddeAppend<ddeHTMLTableColElement>;
}
export interface ddeHTMLTableColElement extends HTMLTableColElement {
append: ddeAppend<ddeHTMLTableColElement>;
}
export interface ddeHTMLDataElement extends HTMLDataElement {
append: ddeAppend<ddeHTMLDataElement>;
}
export interface ddeHTMLDataListElement extends HTMLDataListElement {
append: ddeAppend<ddeHTMLDataListElement>;
}
export interface ddeHTMLModElement extends HTMLModElement {
append: ddeAppend<ddeHTMLModElement>;
}
export interface ddeHTMLDetailsElement extends HTMLDetailsElement {
append: ddeAppend<ddeHTMLDetailsElement>;
}
export interface ddeHTMLDialogElement extends HTMLDialogElement {
append: ddeAppend<ddeHTMLDialogElement>;
}
export interface ddeHTMLDivElement extends HTMLDivElement {
append: ddeAppend<ddeHTMLDivElement>;
}
export interface ddeHTMLDListElement extends HTMLDListElement {
append: ddeAppend<ddeHTMLDListElement>;
}
export interface ddeHTMLEmbedElement extends HTMLEmbedElement {
append: ddeAppend<ddeHTMLEmbedElement>;
}
export interface ddeHTMLFieldSetElement extends HTMLFieldSetElement {
append: ddeAppend<ddeHTMLFieldSetElement>;
}
export interface ddeHTMLFormElement extends HTMLFormElement {
append: ddeAppend<ddeHTMLFormElement>;
}
export interface ddeHTMLHeadingElement extends HTMLHeadingElement {
append: ddeAppend<ddeHTMLHeadingElement>;
}
export interface ddeHTMLHeadElement extends HTMLHeadElement {
append: ddeAppend<ddeHTMLHeadElement>;
}
export interface ddeHTMLHRElement extends HTMLHRElement {
append: ddeAppend<ddeHTMLHRElement>;
}
export interface ddeHTMLHtmlElement extends HTMLHtmlElement {
append: ddeAppend<ddeHTMLHtmlElement>;
}
export interface ddeHTMLIFrameElement extends HTMLIFrameElement {
append: ddeAppend<ddeHTMLIFrameElement>;
}
export interface ddeHTMLImageElement extends HTMLImageElement {
append: ddeAppend<ddeHTMLImageElement>;
}
export interface ddeHTMLInputElement extends HTMLInputElement {
append: ddeAppend<ddeHTMLInputElement>;
}
export interface ddeHTMLLabelElement extends HTMLLabelElement {
append: ddeAppend<ddeHTMLLabelElement>;
}
export interface ddeHTMLLegendElement extends HTMLLegendElement {
append: ddeAppend<ddeHTMLLegendElement>;
}
export interface ddeHTMLLIElement extends HTMLLIElement {
append: ddeAppend<ddeHTMLLIElement>;
}
export interface ddeHTMLLinkElement extends HTMLLinkElement {
append: ddeAppend<ddeHTMLLinkElement>;
}
export interface ddeHTMLMapElement extends HTMLMapElement {
append: ddeAppend<ddeHTMLMapElement>;
}
export interface ddeHTMLMenuElement extends HTMLMenuElement {
append: ddeAppend<ddeHTMLMenuElement>;
}
export interface ddeHTMLMetaElement extends HTMLMetaElement {
append: ddeAppend<ddeHTMLMetaElement>;
}
export interface ddeHTMLMeterElement extends HTMLMeterElement {
append: ddeAppend<ddeHTMLMeterElement>;
}
export interface ddeHTMLObjectElement extends HTMLObjectElement {
append: ddeAppend<ddeHTMLObjectElement>;
}
export interface ddeHTMLOListElement extends HTMLOListElement {
append: ddeAppend<ddeHTMLOListElement>;
}
export interface ddeHTMLOptGroupElement extends HTMLOptGroupElement {
append: ddeAppend<ddeHTMLOptGroupElement>;
}
export interface ddeHTMLOptionElement extends HTMLOptionElement {
append: ddeAppend<ddeHTMLOptionElement>;
}
export interface ddeHTMLOutputElement extends HTMLOutputElement {
append: ddeAppend<ddeHTMLOutputElement>;
}
export interface ddeHTMLParagraphElement extends HTMLParagraphElement {
append: ddeAppend<ddeHTMLParagraphElement>;
}
export interface ddeHTMLPictureElement extends HTMLPictureElement {
append: ddeAppend<ddeHTMLPictureElement>;
}
export interface ddeHTMLPreElement extends HTMLPreElement {
append: ddeAppend<ddeHTMLPreElement>;
}
export interface ddeHTMLProgressElement extends HTMLProgressElement {
append: ddeAppend<ddeHTMLProgressElement>;
}
export interface ddeHTMLScriptElement extends HTMLScriptElement {
append: ddeAppend<ddeHTMLScriptElement>;
}
export interface ddeHTMLSelectElement extends HTMLSelectElement {
append: ddeAppend<ddeHTMLSelectElement>;
}
export interface ddeHTMLSlotElement extends HTMLSlotElement {
append: ddeAppend<ddeHTMLSlotElement>;
}
export interface ddeHTMLSourceElement extends HTMLSourceElement {
append: ddeAppend<ddeHTMLSourceElement>;
}
export interface ddeHTMLSpanElement extends HTMLSpanElement {
append: ddeAppend<ddeHTMLSpanElement>;
}
export interface ddeHTMLStyleElement extends HTMLStyleElement {
append: ddeAppend<ddeHTMLStyleElement>;
}
export interface ddeHTMLTableElement extends HTMLTableElement {
append: ddeAppend<ddeHTMLTableElement>;
}
export interface ddeHTMLTableSectionElement extends HTMLTableSectionElement {
append: ddeAppend<ddeHTMLTableSectionElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTemplateElement extends HTMLTemplateElement {
append: ddeAppend<ddeHTMLTemplateElement>;
}
export interface ddeHTMLTextAreaElement extends HTMLTextAreaElement {
append: ddeAppend<ddeHTMLTextAreaElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTimeElement extends HTMLTimeElement {
append: ddeAppend<ddeHTMLTimeElement>;
}
export interface ddeHTMLTitleElement extends HTMLTitleElement {
append: ddeAppend<ddeHTMLTitleElement>;
}
export interface ddeHTMLTableRowElement extends HTMLTableRowElement {
append: ddeAppend<ddeHTMLTableRowElement>;
}
export interface ddeHTMLTrackElement extends HTMLTrackElement {
append: ddeAppend<ddeHTMLTrackElement>;
}
export interface ddeHTMLUListElement extends HTMLUListElement {
append: ddeAppend<ddeHTMLUListElement>;
}
export interface ddeHTMLVideoElement extends HTMLVideoElement {
append: ddeAppend<ddeHTMLVideoElement>;
}
export interface ddeSVGAElement extends SVGAElement {
append: ddeAppend<ddeSVGAElement>;
}
export interface ddeSVGAnimateElement extends SVGAnimateElement {
append: ddeAppend<ddeSVGAnimateElement>;
}
export interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement {
append: ddeAppend<ddeSVGAnimateMotionElement>;
}
export interface ddeSVGAnimateTransformElement extends SVGAnimateTransformElement {
append: ddeAppend<ddeSVGAnimateTransformElement>;
}
export interface ddeSVGCircleElement extends SVGCircleElement {
append: ddeAppend<ddeSVGCircleElement>;
}
export interface ddeSVGClipPathElement extends SVGClipPathElement {
append: ddeAppend<ddeSVGClipPathElement>;
}
export interface ddeSVGDefsElement extends SVGDefsElement {
append: ddeAppend<ddeSVGDefsElement>;
}
export interface ddeSVGDescElement extends SVGDescElement {
append: ddeAppend<ddeSVGDescElement>;
}
export interface ddeSVGEllipseElement extends SVGEllipseElement {
append: ddeAppend<ddeSVGEllipseElement>;
}
export interface ddeSVGFEBlendElement extends SVGFEBlendElement {
append: ddeAppend<ddeSVGFEBlendElement>;
}
export interface ddeSVGFEColorMatrixElement extends SVGFEColorMatrixElement {
append: ddeAppend<ddeSVGFEColorMatrixElement>;
}
export interface ddeSVGFEComponentTransferElement extends SVGFEComponentTransferElement {
append: ddeAppend<ddeSVGFEComponentTransferElement>;
}
export interface ddeSVGFECompositeElement extends SVGFECompositeElement {
append: ddeAppend<ddeSVGFECompositeElement>;
}
export interface ddeSVGFEConvolveMatrixElement extends SVGFEConvolveMatrixElement {
append: ddeAppend<ddeSVGFEConvolveMatrixElement>;
}
export interface ddeSVGFEDiffuseLightingElement extends SVGFEDiffuseLightingElement {
append: ddeAppend<ddeSVGFEDiffuseLightingElement>;
}
export interface ddeSVGFEDisplacementMapElement extends SVGFEDisplacementMapElement {
append: ddeAppend<ddeSVGFEDisplacementMapElement>;
}
export interface ddeSVGFEDistantLightElement extends SVGFEDistantLightElement {
append: ddeAppend<ddeSVGFEDistantLightElement>;
}
export interface ddeSVGFEDropShadowElement extends SVGFEDropShadowElement {
append: ddeAppend<ddeSVGFEDropShadowElement>;
}
export interface ddeSVGFEFloodElement extends SVGFEFloodElement {
append: ddeAppend<ddeSVGFEFloodElement>;
}
export interface ddeSVGFEFuncAElement extends SVGFEFuncAElement {
append: ddeAppend<ddeSVGFEFuncAElement>;
}
export interface ddeSVGFEFuncBElement extends SVGFEFuncBElement {
append: ddeAppend<ddeSVGFEFuncBElement>;
}
export interface ddeSVGFEFuncGElement extends SVGFEFuncGElement {
append: ddeAppend<ddeSVGFEFuncGElement>;
}
export interface ddeSVGFEFuncRElement extends SVGFEFuncRElement {
append: ddeAppend<ddeSVGFEFuncRElement>;
}
export interface ddeSVGFEGaussianBlurElement extends SVGFEGaussianBlurElement {
append: ddeAppend<ddeSVGFEGaussianBlurElement>;
}
export interface ddeSVGFEImageElement extends SVGFEImageElement {
append: ddeAppend<ddeSVGFEImageElement>;
}
export interface ddeSVGFEMergeElement extends SVGFEMergeElement {
append: ddeAppend<ddeSVGFEMergeElement>;
}
export interface ddeSVGFEMergeNodeElement extends SVGFEMergeNodeElement {
append: ddeAppend<ddeSVGFEMergeNodeElement>;
}
export interface ddeSVGFEMorphologyElement extends SVGFEMorphologyElement {
append: ddeAppend<ddeSVGFEMorphologyElement>;
}
export interface ddeSVGFEOffsetElement extends SVGFEOffsetElement {
append: ddeAppend<ddeSVGFEOffsetElement>;
}
export interface ddeSVGFEPointLightElement extends SVGFEPointLightElement {
append: ddeAppend<ddeSVGFEPointLightElement>;
}
export interface ddeSVGFESpecularLightingElement extends SVGFESpecularLightingElement {
append: ddeAppend<ddeSVGFESpecularLightingElement>;
}
export interface ddeSVGFESpotLightElement extends SVGFESpotLightElement {
append: ddeAppend<ddeSVGFESpotLightElement>;
}
export interface ddeSVGFETileElement extends SVGFETileElement {
append: ddeAppend<ddeSVGFETileElement>;
}
export interface ddeSVGFETurbulenceElement extends SVGFETurbulenceElement {
append: ddeAppend<ddeSVGFETurbulenceElement>;
}
export interface ddeSVGFilterElement extends SVGFilterElement {
append: ddeAppend<ddeSVGFilterElement>;
}
export interface ddeSVGForeignObjectElement extends SVGForeignObjectElement {
append: ddeAppend<ddeSVGForeignObjectElement>;
}
export interface ddeSVGGElement extends SVGGElement {
append: ddeAppend<ddeSVGGElement>;
}
export interface ddeSVGImageElement extends SVGImageElement {
append: ddeAppend<ddeSVGImageElement>;
}
export interface ddeSVGLineElement extends SVGLineElement {
append: ddeAppend<ddeSVGLineElement>;
}
export interface ddeSVGLinearGradientElement extends SVGLinearGradientElement {
append: ddeAppend<ddeSVGLinearGradientElement>;
}
export interface ddeSVGMarkerElement extends SVGMarkerElement {
append: ddeAppend<ddeSVGMarkerElement>;
}
export interface ddeSVGMaskElement extends SVGMaskElement {
append: ddeAppend<ddeSVGMaskElement>;
}
export interface ddeSVGMetadataElement extends SVGMetadataElement {
append: ddeAppend<ddeSVGMetadataElement>;
}
export interface ddeSVGMPathElement extends SVGMPathElement {
append: ddeAppend<ddeSVGMPathElement>;
}
export interface ddeSVGPathElement extends SVGPathElement {
append: ddeAppend<ddeSVGPathElement>;
}
export interface ddeSVGPatternElement extends SVGPatternElement {
append: ddeAppend<ddeSVGPatternElement>;
}
export interface ddeSVGPolygonElement extends SVGPolygonElement {
append: ddeAppend<ddeSVGPolygonElement>;
}
export interface ddeSVGPolylineElement extends SVGPolylineElement {
append: ddeAppend<ddeSVGPolylineElement>;
}
export interface ddeSVGRadialGradientElement extends SVGRadialGradientElement {
append: ddeAppend<ddeSVGRadialGradientElement>;
}
export interface ddeSVGRectElement extends SVGRectElement {
append: ddeAppend<ddeSVGRectElement>;
}
export interface ddeSVGScriptElement extends SVGScriptElement {
append: ddeAppend<ddeSVGScriptElement>;
}
export interface ddeSVGSetElement extends SVGSetElement {
append: ddeAppend<ddeSVGSetElement>;
}
export interface ddeSVGStopElement extends SVGStopElement {
append: ddeAppend<ddeSVGStopElement>;
}
export interface ddeSVGStyleElement extends SVGStyleElement {
append: ddeAppend<ddeSVGStyleElement>;
}
export interface ddeSVGSVGElement extends SVGSVGElement {
append: ddeAppend<ddeSVGSVGElement>;
}
export interface ddeSVGSwitchElement extends SVGSwitchElement {
append: ddeAppend<ddeSVGSwitchElement>;
}
export interface ddeSVGSymbolElement extends SVGSymbolElement {
append: ddeAppend<ddeSVGSymbolElement>;
}
export interface ddeSVGTextElement extends SVGTextElement {
append: ddeAppend<ddeSVGTextElement>;
}
export interface ddeSVGTextPathElement extends SVGTextPathElement {
append: ddeAppend<ddeSVGTextPathElement>;
}
export interface ddeSVGTitleElement extends SVGTitleElement {
append: ddeAppend<ddeSVGTitleElement>;
}
export interface ddeSVGTSpanElement extends SVGTSpanElement {
append: ddeAppend<ddeSVGTSpanElement>;
}
export interface ddeSVGUseElement extends SVGUseElement {
append: ddeAppend<ddeSVGUseElement>;
}
export interface ddeSVGViewElement extends SVGViewElement {
append: ddeAppend<ddeSVGViewElement>;
}
export {
dispatchEvent$1 as dispatchEvent,
el as createElement,
elNS as createElementNS,
};
export as namespace dde;
export {};

1645
dist/dde-with-signals.js vendored

File diff suppressed because it is too large Load Diff

785
dist/dde-with-signals.min.d.ts vendored Normal file
View File

@ -0,0 +1,785 @@
// Generated by dts-bundle-generator v9.5.1
export interface Signal<V, A> {
/** The current value of the signal */
get(): V;
/** Set new value of the signal */
set(value: V): V;
toJSON(): V;
valueOf(): V;
}
export type Action<V> = (this: {
value: V;
stopPropagation(): void;
}, ...a: any[]) => typeof signal._ | void;
//type SymbolSignal= Symbol;
export type SymbolOnclear = symbol;
export type Actions<V> = Record<string | SymbolOnclear, Action<V>>;
export type OnListenerOptions = Pick<AddEventListenerOptions, "signal"> & {
first_time?: boolean;
};
export interface signal {
_: Symbol;
/**
* Computations signal. This creates a signal which is computed from other signals.
* */
<V extends () => any>(computation: V): Signal<ReturnType<V>, {}>;
/**
* Simple example:
* ```js
* const hello= S("Hello Signal");
* ```
* simple todo signal:
* ```js
* const todos= S([], {
* add(v){ this.value.push(S(v)); },
* remove(i){ this.value.splice(i, 1); },
* [S.symbols.onclear](){ S.clear(...this.value); },
* });
* ```
* computed signal:
* ```js
* const name= S("Jan");
* const surname= S("Andrle");
* const fullname= S(()=> name.get()+" "+surname.get());
* ```
* @param value Initial signal value. Or function computing value from other signals.
* @param actions Use to define actions on the signal. Such as add item to the array.
* There is also a reserved function `S.symbol.onclear` which is called when the signal is cleared
* by `S.clear`.
* */
<V, A extends Actions<V>>(value: V, actions?: A): Signal<V, A>;
action<S extends Signal<any, Actions<any>>, A extends (S extends Signal<any, infer A> ? A : never), N extends keyof A>(signal: S, name: N, ...params: A[N] extends (...args: infer P) => any ? P : never): void;
clear(...signals: Signal<any, any>[]): void;
on<T>(signal: Signal<T, any>, onchange: (a: T) => void, options?: OnListenerOptions): void;
symbols: {
//signal: SymbolSignal;
onclear: SymbolOnclear;
};
/**
* Reactive element, which is rendered based on the given signal.
* ```js
* S.el(signal, value=> value ? el("b", "True") : el("i", "False"));
* S.el(listS, list=> list.map(li=> el("li", li)));
* ```
* */
el<S extends any>(signal: Signal<S, any>, el: (v: S) => Element | Element[] | DocumentFragment): DocumentFragment;
observedAttributes(custom_element: HTMLElement): Record<string, Signal<string, {}>>;
}
export const signal: signal;
export const S: signal;
declare global {
type ddeSignal<T, A = {}> = Signal<T, A>;
type ddeAction<V> = Action<V>;
type ddeActions<V> = Actions<V>;
}
export type CustomElementTagNameMap = {
"#text": Text;
"#comment": Comment;
};
export type SupportedElement = HTMLElementTagNameMap[keyof HTMLElementTagNameMap] | SVGElementTagNameMap[keyof SVGElementTagNameMap] | MathMLElementTagNameMap[keyof MathMLElementTagNameMap] | CustomElementTagNameMap[keyof CustomElementTagNameMap];
declare global {
type ddeComponentAttributes = Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment | Node> = (element: El) => any;
type ddeString = string | Signal<string, {}>;
type ddeStringable = ddeString | number | Signal<number, {}>;
}
export type PascalCase = `${Capitalize<string>}${string}`;
export type AttrsModified = {
/**
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/
style: Partial<CSSStyleDeclaration> | ddeString | Partial<{
[K in keyof CSSStyleDeclaration]: Signal<CSSStyleDeclaration[K], {}>;
}>;
/**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1.
* In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))`
* for others.
*/
classList: Record<string, -1 | 0 | 1 | boolean | Signal<-1 | 0 | 1 | boolean, {}>>;
/**
* Used by the dataset HTML attribute to represent data for custom attributes added to elements.
* Values are converted to string (see {@link DOMStringMap}).
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMStringMap)
* */
dataset: Record<string, ddeStringable>;
/**
* Sets `aria-*` simiraly to `dataset`
* */
ariaset: Record<string, ddeString>;
} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, ddeString> & Record<`.${string}`, any>;
export type _fromElsInterfaces<EL extends SupportedElement> = Omit<EL, keyof AttrsModified>;
export type IsReadonly<T, K extends keyof T> = T extends {
readonly [P in K]: T[K];
} ? true : false;
/**
* Just element attributtes
*
* In most cases, you can use native propertie such as
* [MDN WEB/API/Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) and so on
* (e.g. [`Text`](https://developer.mozilla.org/en-US/docs/Web/API/Text)).
*
* There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives.
* @private
*/
export type ElementAttributes<T extends SupportedElement> = Partial<{
[K in keyof _fromElsInterfaces<T>]: _fromElsInterfaces<T>[K] extends ((...p: any[]) => any) ? _fromElsInterfaces<T>[K] | ((...p: Parameters<_fromElsInterfaces<T>[K]>) => Signal<ReturnType<_fromElsInterfaces<T>[K]>, {}>) : (IsReadonly<_fromElsInterfaces<T>, K> extends false ? _fromElsInterfaces<T>[K] | Signal<_fromElsInterfaces<T>[K], {}> : ddeStringable);
} & AttrsModified> & Record<string, any>;
export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El;
export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El;
export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT];
export type ExtendedHTMLElementTagNameMap = HTMLElementTagNameMap & CustomElementTagNameMap;
export namespace el {
/**
* Creates a marker comment for elements
*
* @param attrs - Marker attributes
* @param [is_open=false] - Whether the marker is open-ended
* @returns Comment node marker
*/
export function mark(attrs: {
type: "component" | "reactive" | "later";
name?: string;
host?: "this" | "parentElement";
}, is_open?: boolean): Comment;
}
export function el<A extends ddeComponentAttributes, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>, ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
export function el<A extends {
textContent: ddeStringable;
}, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>["textContent"], ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
export function el<TAG extends keyof ExtendedHTMLElementTagNameMap>(tag_name: TAG, attrs?: ElementAttributes<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]> | ddeStringable, ...addons: ddeElementAddon<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]>[]): TAG extends keyof ddeHTMLElementTagNameMap ? ddeHTMLElementTagNameMap[TAG] : ddeHTMLElement;
export function el(tag_name?: "<>"): ddeDocumentFragment;
export function el(tag_name: string, attrs?: ElementAttributes<HTMLElement> | ddeStringable, ...addons: ddeElementAddon<HTMLElement>[]): ddeHTMLElement;
export function elNS(namespace: "http://www.w3.org/2000/svg"): <TAG extends keyof SVGElementTagNameMap & string, EL extends (TAG extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[TAG] : SVGElement)>(tag_name: TAG, attrs?: ElementAttributes<NoInfer<EL>> | ddeStringable, ...addons: ddeElementAddon<NoInfer<EL>>[]) => TAG extends keyof ddeSVGElementTagNameMap ? ddeSVGElementTagNameMap[TAG] : ddeSVGElement;
export function elNS(namespace: "http://www.w3.org/1998/Math/MathML"): <TAG extends keyof MathMLElementTagNameMap & string, EL extends (TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement)>(tag_name: TAG, attrs?: ddeStringable | Partial<{
[key in keyof EL]: EL[key] | Signal<EL[key], {}> | string | number | boolean;
}>, ...addons: ddeElementAddon<NoInfer<EL>>[]) => ddeMathMLElement;
export function elNS(namespace: string): (tag_name: string, attrs?: string | ddeStringable | Record<string, any>, ...addons: ddeElementAddon<SupportedElement>[]) => SupportedElement;
export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
/** Simulate slots for ddeComponents */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(root: EL): EL;
/**
* Simulate slots in Custom Elements without using `shadowRoot`.
* @param el Custom Element root element
* @param body Body of the custom element
* */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: HTMLElement, body: EL): EL;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, element: SupportedElement): (data?: any) => void;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options?: EventInit): (element: SupportedElement, data?: any) => void;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, element: SupportedElement | (() => SupportedElement)): (data?: any) => void;
export interface On {
/** Listens to the DOM event. See {@link Document.addEventListener} */
<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE;
<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[
string,
string
]>) => any, options?: AddEventListenerOptions): EE;
}
export const on: On;
export type Scope = {
scope: Node | Function | Object;
host: ddeElementAddon<any>;
custom_element: false | HTMLElement;
prevent: boolean;
};
/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */
export const scope: {
current: Scope;
/** Stops all automatizations. E. g. signals used as attributes in current scope
* registers removing these listeners (and clean signal if no other listeners are detected)
* on `disconnected` event. */
preventDefault<T extends boolean>(prevent: T): T;
/**
* This represents reference to the current host element `scope.host()`.
* It can be also used to register Addon(s) (functions to be called when component is initized)
* `scope.host(on.connected(console.log))`.
* */
host: (...addons: ddeElementAddon<SupportedElement>[]) => HTMLElement;
state: Scope[];
/** Adds new child scope. All attributes are inherited by default. */
push(scope?: Partial<Scope>): ReturnType<Array<Scope>["push"]>;
/** Adds root scope as a child of the current scope. */
pushRoot(): ReturnType<Array<Scope>["push"]>;
/** Removes last/current child scope. */
pop(): ReturnType<Array<Scope>["pop"]>;
};
export function customElementRender<EL extends HTMLElement, P extends any = Record<string, string | Signal<string, {}>>>(target: ShadowRoot | EL, render: (props: P) => SupportedElement | DocumentFragment, props?: P | ((el: EL) => P)): EL;
export function customElementWithDDE<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
export function lifecyclesToEvents<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
export function observedAttributes(custom_element: HTMLElement): Record<string, string>;
/**
* This is used primarly for server side rendering. To be sure that all async operations
* are finished before the page is sent to the client.
* ```
* // on component
* function component(){
*
* queue(fetch(...).then(...));
* }
*
* // building the page
* async function build(){
* const { component }= await import("./component.js");
* document.body.append(el(component));
* await queue();
* retutn document.body.innerHTML;
* }
* ```
* */
export function queue(promise?: Promise<unknown>): Promise<unknown>;
/* TypeScript MEH */
declare global {
type ddeAppend<el> = (...nodes: (Node | string)[]) => el;
interface ddeDocumentFragment extends DocumentFragment {
append: ddeAppend<ddeDocumentFragment>;
}
interface ddeHTMLElement extends HTMLElement {
append: ddeAppend<ddeHTMLElement>;
}
interface ddeSVGElement extends SVGElement {
append: ddeAppend<ddeSVGElement>;
}
interface ddeMathMLElement extends MathMLElement {
append: ddeAppend<ddeMathMLElement>;
}
interface ddeHTMLElementTagNameMap {
"a": ddeHTMLAnchorElement;
"area": ddeHTMLAreaElement;
"audio": ddeHTMLAudioElement;
"base": ddeHTMLBaseElement;
"blockquote": ddeHTMLQuoteElement;
"body": ddeHTMLBodyElement;
"br": ddeHTMLBRElement;
"button": ddeHTMLButtonElement;
"canvas": ddeHTMLCanvasElement;
"caption": ddeHTMLTableCaptionElement;
"col": ddeHTMLTableColElement;
"colgroup": ddeHTMLTableColElement;
"data": ddeHTMLDataElement;
"datalist": ddeHTMLDataListElement;
"del": ddeHTMLModElement;
"details": ddeHTMLDetailsElement;
"dialog": ddeHTMLDialogElement;
"div": ddeHTMLDivElement;
"dl": ddeHTMLDListElement;
"embed": ddeHTMLEmbedElement;
"fieldset": ddeHTMLFieldSetElement;
"form": ddeHTMLFormElement;
"h1": ddeHTMLHeadingElement;
"h2": ddeHTMLHeadingElement;
"h3": ddeHTMLHeadingElement;
"h4": ddeHTMLHeadingElement;
"h5": ddeHTMLHeadingElement;
"h6": ddeHTMLHeadingElement;
"head": ddeHTMLHeadElement;
"hr": ddeHTMLHRElement;
"html": ddeHTMLHtmlElement;
"iframe": ddeHTMLIFrameElement;
"img": ddeHTMLImageElement;
"input": ddeHTMLInputElement;
"ins": ddeHTMLModElement;
"label": ddeHTMLLabelElement;
"legend": ddeHTMLLegendElement;
"li": ddeHTMLLIElement;
"link": ddeHTMLLinkElement;
"map": ddeHTMLMapElement;
"menu": ddeHTMLMenuElement;
"meta": ddeHTMLMetaElement;
"meter": ddeHTMLMeterElement;
"object": ddeHTMLObjectElement;
"ol": ddeHTMLOListElement;
"optgroup": ddeHTMLOptGroupElement;
"option": ddeHTMLOptionElement;
"output": ddeHTMLOutputElement;
"p": ddeHTMLParagraphElement;
"picture": ddeHTMLPictureElement;
"pre": ddeHTMLPreElement;
"progress": ddeHTMLProgressElement;
"q": ddeHTMLQuoteElement;
"script": ddeHTMLScriptElement;
"select": ddeHTMLSelectElement;
"slot": ddeHTMLSlotElement;
"source": ddeHTMLSourceElement;
"span": ddeHTMLSpanElement;
"style": ddeHTMLStyleElement;
"table": ddeHTMLTableElement;
"tbody": ddeHTMLTableSectionElement;
"td": ddeHTMLTableCellElement;
"template": ddeHTMLTemplateElement;
"textarea": ddeHTMLTextAreaElement;
"tfoot": ddeHTMLTableSectionElement;
"th": ddeHTMLTableCellElement;
"thead": ddeHTMLTableSectionElement;
"time": ddeHTMLTimeElement;
"title": ddeHTMLTitleElement;
"tr": ddeHTMLTableRowElement;
"track": ddeHTMLTrackElement;
"ul": ddeHTMLUListElement;
"video": ddeHTMLVideoElement;
}
interface ddeSVGElementTagNameMap {
"a": ddeSVGAElement;
"animate": ddeSVGAnimateElement;
"animateMotion": ddeSVGAnimateMotionElement;
"animateTransform": ddeSVGAnimateTransformElement;
"circle": ddeSVGCircleElement;
"clipPath": ddeSVGClipPathElement;
"defs": ddeSVGDefsElement;
"desc": ddeSVGDescElement;
"ellipse": ddeSVGEllipseElement;
"feBlend": ddeSVGFEBlendElement;
"feColorMatrix": ddeSVGFEColorMatrixElement;
"feComponentTransfer": ddeSVGFEComponentTransferElement;
"feComposite": ddeSVGFECompositeElement;
"feConvolveMatrix": ddeSVGFEConvolveMatrixElement;
"feDiffuseLighting": ddeSVGFEDiffuseLightingElement;
"feDisplacementMap": ddeSVGFEDisplacementMapElement;
"feDistantLight": ddeSVGFEDistantLightElement;
"feDropShadow": ddeSVGFEDropShadowElement;
"feFlood": ddeSVGFEFloodElement;
"feFuncA": ddeSVGFEFuncAElement;
"feFuncB": ddeSVGFEFuncBElement;
"feFuncG": ddeSVGFEFuncGElement;
"feFuncR": ddeSVGFEFuncRElement;
"feGaussianBlur": ddeSVGFEGaussianBlurElement;
"feImage": ddeSVGFEImageElement;
"feMerge": ddeSVGFEMergeElement;
"feMergeNode": ddeSVGFEMergeNodeElement;
"feMorphology": ddeSVGFEMorphologyElement;
"feOffset": ddeSVGFEOffsetElement;
"fePointLight": ddeSVGFEPointLightElement;
"feSpecularLighting": ddeSVGFESpecularLightingElement;
"feSpotLight": ddeSVGFESpotLightElement;
"feTile": ddeSVGFETileElement;
"feTurbulence": ddeSVGFETurbulenceElement;
"filter": ddeSVGFilterElement;
"foreignObject": ddeSVGForeignObjectElement;
"g": ddeSVGGElement;
"image": ddeSVGImageElement;
"line": ddeSVGLineElement;
"linearGradient": ddeSVGLinearGradientElement;
"marker": ddeSVGMarkerElement;
"mask": ddeSVGMaskElement;
"metadata": ddeSVGMetadataElement;
"mpath": ddeSVGMPathElement;
"path": ddeSVGPathElement;
"pattern": ddeSVGPatternElement;
"polygon": ddeSVGPolygonElement;
"polyline": ddeSVGPolylineElement;
"radialGradient": ddeSVGRadialGradientElement;
"rect": ddeSVGRectElement;
"script": ddeSVGScriptElement;
"set": ddeSVGSetElement;
"stop": ddeSVGStopElement;
"style": ddeSVGStyleElement;
"svg": ddeSVGSVGElement;
"switch": ddeSVGSwitchElement;
"symbol": ddeSVGSymbolElement;
"text": ddeSVGTextElement;
"textPath": ddeSVGTextPathElement;
"title": ddeSVGTitleElement;
"tspan": ddeSVGTSpanElement;
"use": ddeSVGUseElement;
"view": ddeSVGViewElement;
}
}
// editorconfig-checker-disable
export interface ddeHTMLAnchorElement extends HTMLAnchorElement {
append: ddeAppend<ddeHTMLAnchorElement>;
}
export interface ddeHTMLAreaElement extends HTMLAreaElement {
append: ddeAppend<ddeHTMLAreaElement>;
}
export interface ddeHTMLAudioElement extends HTMLAudioElement {
append: ddeAppend<ddeHTMLAudioElement>;
}
export interface ddeHTMLBaseElement extends HTMLBaseElement {
append: ddeAppend<ddeHTMLBaseElement>;
}
export interface ddeHTMLQuoteElement extends HTMLQuoteElement {
append: ddeAppend<ddeHTMLQuoteElement>;
}
export interface ddeHTMLBodyElement extends HTMLBodyElement {
append: ddeAppend<ddeHTMLBodyElement>;
}
export interface ddeHTMLBRElement extends HTMLBRElement {
append: ddeAppend<ddeHTMLBRElement>;
}
export interface ddeHTMLButtonElement extends HTMLButtonElement {
append: ddeAppend<ddeHTMLButtonElement>;
}
export interface ddeHTMLCanvasElement extends HTMLCanvasElement {
append: ddeAppend<ddeHTMLCanvasElement>;
}
export interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement {
append: ddeAppend<ddeHTMLTableCaptionElement>;
}
export interface ddeHTMLTableColElement extends HTMLTableColElement {
append: ddeAppend<ddeHTMLTableColElement>;
}
export interface ddeHTMLTableColElement extends HTMLTableColElement {
append: ddeAppend<ddeHTMLTableColElement>;
}
export interface ddeHTMLDataElement extends HTMLDataElement {
append: ddeAppend<ddeHTMLDataElement>;
}
export interface ddeHTMLDataListElement extends HTMLDataListElement {
append: ddeAppend<ddeHTMLDataListElement>;
}
export interface ddeHTMLModElement extends HTMLModElement {
append: ddeAppend<ddeHTMLModElement>;
}
export interface ddeHTMLDetailsElement extends HTMLDetailsElement {
append: ddeAppend<ddeHTMLDetailsElement>;
}
export interface ddeHTMLDialogElement extends HTMLDialogElement {
append: ddeAppend<ddeHTMLDialogElement>;
}
export interface ddeHTMLDivElement extends HTMLDivElement {
append: ddeAppend<ddeHTMLDivElement>;
}
export interface ddeHTMLDListElement extends HTMLDListElement {
append: ddeAppend<ddeHTMLDListElement>;
}
export interface ddeHTMLEmbedElement extends HTMLEmbedElement {
append: ddeAppend<ddeHTMLEmbedElement>;
}
export interface ddeHTMLFieldSetElement extends HTMLFieldSetElement {
append: ddeAppend<ddeHTMLFieldSetElement>;
}
export interface ddeHTMLFormElement extends HTMLFormElement {
append: ddeAppend<ddeHTMLFormElement>;
}
export interface ddeHTMLHeadingElement extends HTMLHeadingElement {
append: ddeAppend<ddeHTMLHeadingElement>;
}
export interface ddeHTMLHeadElement extends HTMLHeadElement {
append: ddeAppend<ddeHTMLHeadElement>;
}
export interface ddeHTMLHRElement extends HTMLHRElement {
append: ddeAppend<ddeHTMLHRElement>;
}
export interface ddeHTMLHtmlElement extends HTMLHtmlElement {
append: ddeAppend<ddeHTMLHtmlElement>;
}
export interface ddeHTMLIFrameElement extends HTMLIFrameElement {
append: ddeAppend<ddeHTMLIFrameElement>;
}
export interface ddeHTMLImageElement extends HTMLImageElement {
append: ddeAppend<ddeHTMLImageElement>;
}
export interface ddeHTMLInputElement extends HTMLInputElement {
append: ddeAppend<ddeHTMLInputElement>;
}
export interface ddeHTMLLabelElement extends HTMLLabelElement {
append: ddeAppend<ddeHTMLLabelElement>;
}
export interface ddeHTMLLegendElement extends HTMLLegendElement {
append: ddeAppend<ddeHTMLLegendElement>;
}
export interface ddeHTMLLIElement extends HTMLLIElement {
append: ddeAppend<ddeHTMLLIElement>;
}
export interface ddeHTMLLinkElement extends HTMLLinkElement {
append: ddeAppend<ddeHTMLLinkElement>;
}
export interface ddeHTMLMapElement extends HTMLMapElement {
append: ddeAppend<ddeHTMLMapElement>;
}
export interface ddeHTMLMenuElement extends HTMLMenuElement {
append: ddeAppend<ddeHTMLMenuElement>;
}
export interface ddeHTMLMetaElement extends HTMLMetaElement {
append: ddeAppend<ddeHTMLMetaElement>;
}
export interface ddeHTMLMeterElement extends HTMLMeterElement {
append: ddeAppend<ddeHTMLMeterElement>;
}
export interface ddeHTMLObjectElement extends HTMLObjectElement {
append: ddeAppend<ddeHTMLObjectElement>;
}
export interface ddeHTMLOListElement extends HTMLOListElement {
append: ddeAppend<ddeHTMLOListElement>;
}
export interface ddeHTMLOptGroupElement extends HTMLOptGroupElement {
append: ddeAppend<ddeHTMLOptGroupElement>;
}
export interface ddeHTMLOptionElement extends HTMLOptionElement {
append: ddeAppend<ddeHTMLOptionElement>;
}
export interface ddeHTMLOutputElement extends HTMLOutputElement {
append: ddeAppend<ddeHTMLOutputElement>;
}
export interface ddeHTMLParagraphElement extends HTMLParagraphElement {
append: ddeAppend<ddeHTMLParagraphElement>;
}
export interface ddeHTMLPictureElement extends HTMLPictureElement {
append: ddeAppend<ddeHTMLPictureElement>;
}
export interface ddeHTMLPreElement extends HTMLPreElement {
append: ddeAppend<ddeHTMLPreElement>;
}
export interface ddeHTMLProgressElement extends HTMLProgressElement {
append: ddeAppend<ddeHTMLProgressElement>;
}
export interface ddeHTMLScriptElement extends HTMLScriptElement {
append: ddeAppend<ddeHTMLScriptElement>;
}
export interface ddeHTMLSelectElement extends HTMLSelectElement {
append: ddeAppend<ddeHTMLSelectElement>;
}
export interface ddeHTMLSlotElement extends HTMLSlotElement {
append: ddeAppend<ddeHTMLSlotElement>;
}
export interface ddeHTMLSourceElement extends HTMLSourceElement {
append: ddeAppend<ddeHTMLSourceElement>;
}
export interface ddeHTMLSpanElement extends HTMLSpanElement {
append: ddeAppend<ddeHTMLSpanElement>;
}
export interface ddeHTMLStyleElement extends HTMLStyleElement {
append: ddeAppend<ddeHTMLStyleElement>;
}
export interface ddeHTMLTableElement extends HTMLTableElement {
append: ddeAppend<ddeHTMLTableElement>;
}
export interface ddeHTMLTableSectionElement extends HTMLTableSectionElement {
append: ddeAppend<ddeHTMLTableSectionElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTemplateElement extends HTMLTemplateElement {
append: ddeAppend<ddeHTMLTemplateElement>;
}
export interface ddeHTMLTextAreaElement extends HTMLTextAreaElement {
append: ddeAppend<ddeHTMLTextAreaElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTimeElement extends HTMLTimeElement {
append: ddeAppend<ddeHTMLTimeElement>;
}
export interface ddeHTMLTitleElement extends HTMLTitleElement {
append: ddeAppend<ddeHTMLTitleElement>;
}
export interface ddeHTMLTableRowElement extends HTMLTableRowElement {
append: ddeAppend<ddeHTMLTableRowElement>;
}
export interface ddeHTMLTrackElement extends HTMLTrackElement {
append: ddeAppend<ddeHTMLTrackElement>;
}
export interface ddeHTMLUListElement extends HTMLUListElement {
append: ddeAppend<ddeHTMLUListElement>;
}
export interface ddeHTMLVideoElement extends HTMLVideoElement {
append: ddeAppend<ddeHTMLVideoElement>;
}
export interface ddeSVGAElement extends SVGAElement {
append: ddeAppend<ddeSVGAElement>;
}
export interface ddeSVGAnimateElement extends SVGAnimateElement {
append: ddeAppend<ddeSVGAnimateElement>;
}
export interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement {
append: ddeAppend<ddeSVGAnimateMotionElement>;
}
export interface ddeSVGAnimateTransformElement extends SVGAnimateTransformElement {
append: ddeAppend<ddeSVGAnimateTransformElement>;
}
export interface ddeSVGCircleElement extends SVGCircleElement {
append: ddeAppend<ddeSVGCircleElement>;
}
export interface ddeSVGClipPathElement extends SVGClipPathElement {
append: ddeAppend<ddeSVGClipPathElement>;
}
export interface ddeSVGDefsElement extends SVGDefsElement {
append: ddeAppend<ddeSVGDefsElement>;
}
export interface ddeSVGDescElement extends SVGDescElement {
append: ddeAppend<ddeSVGDescElement>;
}
export interface ddeSVGEllipseElement extends SVGEllipseElement {
append: ddeAppend<ddeSVGEllipseElement>;
}
export interface ddeSVGFEBlendElement extends SVGFEBlendElement {
append: ddeAppend<ddeSVGFEBlendElement>;
}
export interface ddeSVGFEColorMatrixElement extends SVGFEColorMatrixElement {
append: ddeAppend<ddeSVGFEColorMatrixElement>;
}
export interface ddeSVGFEComponentTransferElement extends SVGFEComponentTransferElement {
append: ddeAppend<ddeSVGFEComponentTransferElement>;
}
export interface ddeSVGFECompositeElement extends SVGFECompositeElement {
append: ddeAppend<ddeSVGFECompositeElement>;
}
export interface ddeSVGFEConvolveMatrixElement extends SVGFEConvolveMatrixElement {
append: ddeAppend<ddeSVGFEConvolveMatrixElement>;
}
export interface ddeSVGFEDiffuseLightingElement extends SVGFEDiffuseLightingElement {
append: ddeAppend<ddeSVGFEDiffuseLightingElement>;
}
export interface ddeSVGFEDisplacementMapElement extends SVGFEDisplacementMapElement {
append: ddeAppend<ddeSVGFEDisplacementMapElement>;
}
export interface ddeSVGFEDistantLightElement extends SVGFEDistantLightElement {
append: ddeAppend<ddeSVGFEDistantLightElement>;
}
export interface ddeSVGFEDropShadowElement extends SVGFEDropShadowElement {
append: ddeAppend<ddeSVGFEDropShadowElement>;
}
export interface ddeSVGFEFloodElement extends SVGFEFloodElement {
append: ddeAppend<ddeSVGFEFloodElement>;
}
export interface ddeSVGFEFuncAElement extends SVGFEFuncAElement {
append: ddeAppend<ddeSVGFEFuncAElement>;
}
export interface ddeSVGFEFuncBElement extends SVGFEFuncBElement {
append: ddeAppend<ddeSVGFEFuncBElement>;
}
export interface ddeSVGFEFuncGElement extends SVGFEFuncGElement {
append: ddeAppend<ddeSVGFEFuncGElement>;
}
export interface ddeSVGFEFuncRElement extends SVGFEFuncRElement {
append: ddeAppend<ddeSVGFEFuncRElement>;
}
export interface ddeSVGFEGaussianBlurElement extends SVGFEGaussianBlurElement {
append: ddeAppend<ddeSVGFEGaussianBlurElement>;
}
export interface ddeSVGFEImageElement extends SVGFEImageElement {
append: ddeAppend<ddeSVGFEImageElement>;
}
export interface ddeSVGFEMergeElement extends SVGFEMergeElement {
append: ddeAppend<ddeSVGFEMergeElement>;
}
export interface ddeSVGFEMergeNodeElement extends SVGFEMergeNodeElement {
append: ddeAppend<ddeSVGFEMergeNodeElement>;
}
export interface ddeSVGFEMorphologyElement extends SVGFEMorphologyElement {
append: ddeAppend<ddeSVGFEMorphologyElement>;
}
export interface ddeSVGFEOffsetElement extends SVGFEOffsetElement {
append: ddeAppend<ddeSVGFEOffsetElement>;
}
export interface ddeSVGFEPointLightElement extends SVGFEPointLightElement {
append: ddeAppend<ddeSVGFEPointLightElement>;
}
export interface ddeSVGFESpecularLightingElement extends SVGFESpecularLightingElement {
append: ddeAppend<ddeSVGFESpecularLightingElement>;
}
export interface ddeSVGFESpotLightElement extends SVGFESpotLightElement {
append: ddeAppend<ddeSVGFESpotLightElement>;
}
export interface ddeSVGFETileElement extends SVGFETileElement {
append: ddeAppend<ddeSVGFETileElement>;
}
export interface ddeSVGFETurbulenceElement extends SVGFETurbulenceElement {
append: ddeAppend<ddeSVGFETurbulenceElement>;
}
export interface ddeSVGFilterElement extends SVGFilterElement {
append: ddeAppend<ddeSVGFilterElement>;
}
export interface ddeSVGForeignObjectElement extends SVGForeignObjectElement {
append: ddeAppend<ddeSVGForeignObjectElement>;
}
export interface ddeSVGGElement extends SVGGElement {
append: ddeAppend<ddeSVGGElement>;
}
export interface ddeSVGImageElement extends SVGImageElement {
append: ddeAppend<ddeSVGImageElement>;
}
export interface ddeSVGLineElement extends SVGLineElement {
append: ddeAppend<ddeSVGLineElement>;
}
export interface ddeSVGLinearGradientElement extends SVGLinearGradientElement {
append: ddeAppend<ddeSVGLinearGradientElement>;
}
export interface ddeSVGMarkerElement extends SVGMarkerElement {
append: ddeAppend<ddeSVGMarkerElement>;
}
export interface ddeSVGMaskElement extends SVGMaskElement {
append: ddeAppend<ddeSVGMaskElement>;
}
export interface ddeSVGMetadataElement extends SVGMetadataElement {
append: ddeAppend<ddeSVGMetadataElement>;
}
export interface ddeSVGMPathElement extends SVGMPathElement {
append: ddeAppend<ddeSVGMPathElement>;
}
export interface ddeSVGPathElement extends SVGPathElement {
append: ddeAppend<ddeSVGPathElement>;
}
export interface ddeSVGPatternElement extends SVGPatternElement {
append: ddeAppend<ddeSVGPatternElement>;
}
export interface ddeSVGPolygonElement extends SVGPolygonElement {
append: ddeAppend<ddeSVGPolygonElement>;
}
export interface ddeSVGPolylineElement extends SVGPolylineElement {
append: ddeAppend<ddeSVGPolylineElement>;
}
export interface ddeSVGRadialGradientElement extends SVGRadialGradientElement {
append: ddeAppend<ddeSVGRadialGradientElement>;
}
export interface ddeSVGRectElement extends SVGRectElement {
append: ddeAppend<ddeSVGRectElement>;
}
export interface ddeSVGScriptElement extends SVGScriptElement {
append: ddeAppend<ddeSVGScriptElement>;
}
export interface ddeSVGSetElement extends SVGSetElement {
append: ddeAppend<ddeSVGSetElement>;
}
export interface ddeSVGStopElement extends SVGStopElement {
append: ddeAppend<ddeSVGStopElement>;
}
export interface ddeSVGStyleElement extends SVGStyleElement {
append: ddeAppend<ddeSVGStyleElement>;
}
export interface ddeSVGSVGElement extends SVGSVGElement {
append: ddeAppend<ddeSVGSVGElement>;
}
export interface ddeSVGSwitchElement extends SVGSwitchElement {
append: ddeAppend<ddeSVGSwitchElement>;
}
export interface ddeSVGSymbolElement extends SVGSymbolElement {
append: ddeAppend<ddeSVGSymbolElement>;
}
export interface ddeSVGTextElement extends SVGTextElement {
append: ddeAppend<ddeSVGTextElement>;
}
export interface ddeSVGTextPathElement extends SVGTextPathElement {
append: ddeAppend<ddeSVGTextPathElement>;
}
export interface ddeSVGTitleElement extends SVGTitleElement {
append: ddeAppend<ddeSVGTitleElement>;
}
export interface ddeSVGTSpanElement extends SVGTSpanElement {
append: ddeAppend<ddeSVGTSpanElement>;
}
export interface ddeSVGUseElement extends SVGUseElement {
append: ddeAppend<ddeSVGUseElement>;
}
export interface ddeSVGViewElement extends SVGViewElement {
append: ddeAppend<ddeSVGViewElement>;
}
export {
dispatchEvent$1 as dispatchEvent,
el as createElement,
elNS as createElementNS,
};
export as namespace dde;
export {};

4
dist/dde-with-signals.min.js vendored Normal file

File diff suppressed because one or more lines are too long

784
dist/dde.d.ts vendored Normal file
View File

@ -0,0 +1,784 @@
// Generated by dts-bundle-generator v9.5.1
export interface Signal<V, A> {
/** The current value of the signal */
get(): V;
/** Set new value of the signal */
set(value: V): V;
toJSON(): V;
valueOf(): V;
}
export type Action<V> = (this: {
value: V;
stopPropagation(): void;
}, ...a: any[]) => typeof signal._ | void;
//type SymbolSignal= Symbol;
export type SymbolOnclear = symbol;
export type Actions<V> = Record<string | SymbolOnclear, Action<V>>;
export type OnListenerOptions = Pick<AddEventListenerOptions, "signal"> & {
first_time?: boolean;
};
export interface signal {
_: Symbol;
/**
* Computations signal. This creates a signal which is computed from other signals.
* */
<V extends () => any>(computation: V): Signal<ReturnType<V>, {}>;
/**
* Simple example:
* ```js
* const hello= S("Hello Signal");
* ```
* simple todo signal:
* ```js
* const todos= S([], {
* add(v){ this.value.push(S(v)); },
* remove(i){ this.value.splice(i, 1); },
* [S.symbols.onclear](){ S.clear(...this.value); },
* });
* ```
* computed signal:
* ```js
* const name= S("Jan");
* const surname= S("Andrle");
* const fullname= S(()=> name.get()+" "+surname.get());
* ```
* @param value Initial signal value. Or function computing value from other signals.
* @param actions Use to define actions on the signal. Such as add item to the array.
* There is also a reserved function `S.symbol.onclear` which is called when the signal is cleared
* by `S.clear`.
* */
<V, A extends Actions<V>>(value: V, actions?: A): Signal<V, A>;
action<S extends Signal<any, Actions<any>>, A extends (S extends Signal<any, infer A> ? A : never), N extends keyof A>(signal: S, name: N, ...params: A[N] extends (...args: infer P) => any ? P : never): void;
clear(...signals: Signal<any, any>[]): void;
on<T>(signal: Signal<T, any>, onchange: (a: T) => void, options?: OnListenerOptions): void;
symbols: {
//signal: SymbolSignal;
onclear: SymbolOnclear;
};
/**
* Reactive element, which is rendered based on the given signal.
* ```js
* S.el(signal, value=> value ? el("b", "True") : el("i", "False"));
* S.el(listS, list=> list.map(li=> el("li", li)));
* ```
* */
el<S extends any>(signal: Signal<S, any>, el: (v: S) => Element | Element[] | DocumentFragment): DocumentFragment;
observedAttributes(custom_element: HTMLElement): Record<string, Signal<string, {}>>;
}
declare const signal: signal;
declare global {
type ddeSignal<T, A = {}> = Signal<T, A>;
type ddeAction<V> = Action<V>;
type ddeActions<V> = Actions<V>;
}
export type CustomElementTagNameMap = {
"#text": Text;
"#comment": Comment;
};
export type SupportedElement = HTMLElementTagNameMap[keyof HTMLElementTagNameMap] | SVGElementTagNameMap[keyof SVGElementTagNameMap] | MathMLElementTagNameMap[keyof MathMLElementTagNameMap] | CustomElementTagNameMap[keyof CustomElementTagNameMap];
declare global {
type ddeComponentAttributes = Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment | Node> = (element: El) => any;
type ddeString = string | Signal<string, {}>;
type ddeStringable = ddeString | number | Signal<number, {}>;
}
export type PascalCase = `${Capitalize<string>}${string}`;
export type AttrsModified = {
/**
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/
style: Partial<CSSStyleDeclaration> | ddeString | Partial<{
[K in keyof CSSStyleDeclaration]: Signal<CSSStyleDeclaration[K], {}>;
}>;
/**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1.
* In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))`
* for others.
*/
classList: Record<string, -1 | 0 | 1 | boolean | Signal<-1 | 0 | 1 | boolean, {}>>;
/**
* Used by the dataset HTML attribute to represent data for custom attributes added to elements.
* Values are converted to string (see {@link DOMStringMap}).
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMStringMap)
* */
dataset: Record<string, ddeStringable>;
/**
* Sets `aria-*` simiraly to `dataset`
* */
ariaset: Record<string, ddeString>;
} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, ddeString> & Record<`.${string}`, any>;
export type _fromElsInterfaces<EL extends SupportedElement> = Omit<EL, keyof AttrsModified>;
export type IsReadonly<T, K extends keyof T> = T extends {
readonly [P in K]: T[K];
} ? true : false;
/**
* Just element attributtes
*
* In most cases, you can use native propertie such as
* [MDN WEB/API/Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) and so on
* (e.g. [`Text`](https://developer.mozilla.org/en-US/docs/Web/API/Text)).
*
* There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives.
* @private
*/
export type ElementAttributes<T extends SupportedElement> = Partial<{
[K in keyof _fromElsInterfaces<T>]: _fromElsInterfaces<T>[K] extends ((...p: any[]) => any) ? _fromElsInterfaces<T>[K] | ((...p: Parameters<_fromElsInterfaces<T>[K]>) => Signal<ReturnType<_fromElsInterfaces<T>[K]>, {}>) : (IsReadonly<_fromElsInterfaces<T>, K> extends false ? _fromElsInterfaces<T>[K] | Signal<_fromElsInterfaces<T>[K], {}> : ddeStringable);
} & AttrsModified> & Record<string, any>;
export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El;
export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El;
export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT];
export type ExtendedHTMLElementTagNameMap = HTMLElementTagNameMap & CustomElementTagNameMap;
export namespace el {
/**
* Creates a marker comment for elements
*
* @param attrs - Marker attributes
* @param [is_open=false] - Whether the marker is open-ended
* @returns Comment node marker
*/
export function mark(attrs: {
type: "component" | "reactive" | "later";
name?: string;
host?: "this" | "parentElement";
}, is_open?: boolean): Comment;
}
export function el<A extends ddeComponentAttributes, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>, ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
export function el<A extends {
textContent: ddeStringable;
}, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>["textContent"], ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
export function el<TAG extends keyof ExtendedHTMLElementTagNameMap>(tag_name: TAG, attrs?: ElementAttributes<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]> | ddeStringable, ...addons: ddeElementAddon<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]>[]): TAG extends keyof ddeHTMLElementTagNameMap ? ddeHTMLElementTagNameMap[TAG] : ddeHTMLElement;
export function el(tag_name?: "<>"): ddeDocumentFragment;
export function el(tag_name: string, attrs?: ElementAttributes<HTMLElement> | ddeStringable, ...addons: ddeElementAddon<HTMLElement>[]): ddeHTMLElement;
export function elNS(namespace: "http://www.w3.org/2000/svg"): <TAG extends keyof SVGElementTagNameMap & string, EL extends (TAG extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[TAG] : SVGElement)>(tag_name: TAG, attrs?: ElementAttributes<NoInfer<EL>> | ddeStringable, ...addons: ddeElementAddon<NoInfer<EL>>[]) => TAG extends keyof ddeSVGElementTagNameMap ? ddeSVGElementTagNameMap[TAG] : ddeSVGElement;
export function elNS(namespace: "http://www.w3.org/1998/Math/MathML"): <TAG extends keyof MathMLElementTagNameMap & string, EL extends (TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement)>(tag_name: TAG, attrs?: ddeStringable | Partial<{
[key in keyof EL]: EL[key] | Signal<EL[key], {}> | string | number | boolean;
}>, ...addons: ddeElementAddon<NoInfer<EL>>[]) => ddeMathMLElement;
export function elNS(namespace: string): (tag_name: string, attrs?: string | ddeStringable | Record<string, any>, ...addons: ddeElementAddon<SupportedElement>[]) => SupportedElement;
export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
/** Simulate slots for ddeComponents */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(root: EL): EL;
/**
* Simulate slots in Custom Elements without using `shadowRoot`.
* @param el Custom Element root element
* @param body Body of the custom element
* */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: HTMLElement, body: EL): EL;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, element: SupportedElement): (data?: any) => void;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options?: EventInit): (element: SupportedElement, data?: any) => void;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, element: SupportedElement | (() => SupportedElement)): (data?: any) => void;
export interface On {
/** Listens to the DOM event. See {@link Document.addEventListener} */
<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE;
<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[
string,
string
]>) => any, options?: AddEventListenerOptions): EE;
}
export const on: On;
export type Scope = {
scope: Node | Function | Object;
host: ddeElementAddon<any>;
custom_element: false | HTMLElement;
prevent: boolean;
};
/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */
export const scope: {
current: Scope;
/** Stops all automatizations. E. g. signals used as attributes in current scope
* registers removing these listeners (and clean signal if no other listeners are detected)
* on `disconnected` event. */
preventDefault<T extends boolean>(prevent: T): T;
/**
* This represents reference to the current host element `scope.host()`.
* It can be also used to register Addon(s) (functions to be called when component is initized)
* `scope.host(on.connected(console.log))`.
* */
host: (...addons: ddeElementAddon<SupportedElement>[]) => HTMLElement;
state: Scope[];
/** Adds new child scope. All attributes are inherited by default. */
push(scope?: Partial<Scope>): ReturnType<Array<Scope>["push"]>;
/** Adds root scope as a child of the current scope. */
pushRoot(): ReturnType<Array<Scope>["push"]>;
/** Removes last/current child scope. */
pop(): ReturnType<Array<Scope>["pop"]>;
};
export function customElementRender<EL extends HTMLElement, P extends any = Record<string, string | Signal<string, {}>>>(target: ShadowRoot | EL, render: (props: P) => SupportedElement | DocumentFragment, props?: P | ((el: EL) => P)): EL;
export function customElementWithDDE<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
export function lifecyclesToEvents<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
export function observedAttributes(custom_element: HTMLElement): Record<string, string>;
/**
* This is used primarly for server side rendering. To be sure that all async operations
* are finished before the page is sent to the client.
* ```
* // on component
* function component(){
*
* queue(fetch(...).then(...));
* }
*
* // building the page
* async function build(){
* const { component }= await import("./component.js");
* document.body.append(el(component));
* await queue();
* retutn document.body.innerHTML;
* }
* ```
* */
export function queue(promise?: Promise<unknown>): Promise<unknown>;
/* TypeScript MEH */
declare global {
type ddeAppend<el> = (...nodes: (Node | string)[]) => el;
interface ddeDocumentFragment extends DocumentFragment {
append: ddeAppend<ddeDocumentFragment>;
}
interface ddeHTMLElement extends HTMLElement {
append: ddeAppend<ddeHTMLElement>;
}
interface ddeSVGElement extends SVGElement {
append: ddeAppend<ddeSVGElement>;
}
interface ddeMathMLElement extends MathMLElement {
append: ddeAppend<ddeMathMLElement>;
}
interface ddeHTMLElementTagNameMap {
"a": ddeHTMLAnchorElement;
"area": ddeHTMLAreaElement;
"audio": ddeHTMLAudioElement;
"base": ddeHTMLBaseElement;
"blockquote": ddeHTMLQuoteElement;
"body": ddeHTMLBodyElement;
"br": ddeHTMLBRElement;
"button": ddeHTMLButtonElement;
"canvas": ddeHTMLCanvasElement;
"caption": ddeHTMLTableCaptionElement;
"col": ddeHTMLTableColElement;
"colgroup": ddeHTMLTableColElement;
"data": ddeHTMLDataElement;
"datalist": ddeHTMLDataListElement;
"del": ddeHTMLModElement;
"details": ddeHTMLDetailsElement;
"dialog": ddeHTMLDialogElement;
"div": ddeHTMLDivElement;
"dl": ddeHTMLDListElement;
"embed": ddeHTMLEmbedElement;
"fieldset": ddeHTMLFieldSetElement;
"form": ddeHTMLFormElement;
"h1": ddeHTMLHeadingElement;
"h2": ddeHTMLHeadingElement;
"h3": ddeHTMLHeadingElement;
"h4": ddeHTMLHeadingElement;
"h5": ddeHTMLHeadingElement;
"h6": ddeHTMLHeadingElement;
"head": ddeHTMLHeadElement;
"hr": ddeHTMLHRElement;
"html": ddeHTMLHtmlElement;
"iframe": ddeHTMLIFrameElement;
"img": ddeHTMLImageElement;
"input": ddeHTMLInputElement;
"ins": ddeHTMLModElement;
"label": ddeHTMLLabelElement;
"legend": ddeHTMLLegendElement;
"li": ddeHTMLLIElement;
"link": ddeHTMLLinkElement;
"map": ddeHTMLMapElement;
"menu": ddeHTMLMenuElement;
"meta": ddeHTMLMetaElement;
"meter": ddeHTMLMeterElement;
"object": ddeHTMLObjectElement;
"ol": ddeHTMLOListElement;
"optgroup": ddeHTMLOptGroupElement;
"option": ddeHTMLOptionElement;
"output": ddeHTMLOutputElement;
"p": ddeHTMLParagraphElement;
"picture": ddeHTMLPictureElement;
"pre": ddeHTMLPreElement;
"progress": ddeHTMLProgressElement;
"q": ddeHTMLQuoteElement;
"script": ddeHTMLScriptElement;
"select": ddeHTMLSelectElement;
"slot": ddeHTMLSlotElement;
"source": ddeHTMLSourceElement;
"span": ddeHTMLSpanElement;
"style": ddeHTMLStyleElement;
"table": ddeHTMLTableElement;
"tbody": ddeHTMLTableSectionElement;
"td": ddeHTMLTableCellElement;
"template": ddeHTMLTemplateElement;
"textarea": ddeHTMLTextAreaElement;
"tfoot": ddeHTMLTableSectionElement;
"th": ddeHTMLTableCellElement;
"thead": ddeHTMLTableSectionElement;
"time": ddeHTMLTimeElement;
"title": ddeHTMLTitleElement;
"tr": ddeHTMLTableRowElement;
"track": ddeHTMLTrackElement;
"ul": ddeHTMLUListElement;
"video": ddeHTMLVideoElement;
}
interface ddeSVGElementTagNameMap {
"a": ddeSVGAElement;
"animate": ddeSVGAnimateElement;
"animateMotion": ddeSVGAnimateMotionElement;
"animateTransform": ddeSVGAnimateTransformElement;
"circle": ddeSVGCircleElement;
"clipPath": ddeSVGClipPathElement;
"defs": ddeSVGDefsElement;
"desc": ddeSVGDescElement;
"ellipse": ddeSVGEllipseElement;
"feBlend": ddeSVGFEBlendElement;
"feColorMatrix": ddeSVGFEColorMatrixElement;
"feComponentTransfer": ddeSVGFEComponentTransferElement;
"feComposite": ddeSVGFECompositeElement;
"feConvolveMatrix": ddeSVGFEConvolveMatrixElement;
"feDiffuseLighting": ddeSVGFEDiffuseLightingElement;
"feDisplacementMap": ddeSVGFEDisplacementMapElement;
"feDistantLight": ddeSVGFEDistantLightElement;
"feDropShadow": ddeSVGFEDropShadowElement;
"feFlood": ddeSVGFEFloodElement;
"feFuncA": ddeSVGFEFuncAElement;
"feFuncB": ddeSVGFEFuncBElement;
"feFuncG": ddeSVGFEFuncGElement;
"feFuncR": ddeSVGFEFuncRElement;
"feGaussianBlur": ddeSVGFEGaussianBlurElement;
"feImage": ddeSVGFEImageElement;
"feMerge": ddeSVGFEMergeElement;
"feMergeNode": ddeSVGFEMergeNodeElement;
"feMorphology": ddeSVGFEMorphologyElement;
"feOffset": ddeSVGFEOffsetElement;
"fePointLight": ddeSVGFEPointLightElement;
"feSpecularLighting": ddeSVGFESpecularLightingElement;
"feSpotLight": ddeSVGFESpotLightElement;
"feTile": ddeSVGFETileElement;
"feTurbulence": ddeSVGFETurbulenceElement;
"filter": ddeSVGFilterElement;
"foreignObject": ddeSVGForeignObjectElement;
"g": ddeSVGGElement;
"image": ddeSVGImageElement;
"line": ddeSVGLineElement;
"linearGradient": ddeSVGLinearGradientElement;
"marker": ddeSVGMarkerElement;
"mask": ddeSVGMaskElement;
"metadata": ddeSVGMetadataElement;
"mpath": ddeSVGMPathElement;
"path": ddeSVGPathElement;
"pattern": ddeSVGPatternElement;
"polygon": ddeSVGPolygonElement;
"polyline": ddeSVGPolylineElement;
"radialGradient": ddeSVGRadialGradientElement;
"rect": ddeSVGRectElement;
"script": ddeSVGScriptElement;
"set": ddeSVGSetElement;
"stop": ddeSVGStopElement;
"style": ddeSVGStyleElement;
"svg": ddeSVGSVGElement;
"switch": ddeSVGSwitchElement;
"symbol": ddeSVGSymbolElement;
"text": ddeSVGTextElement;
"textPath": ddeSVGTextPathElement;
"title": ddeSVGTitleElement;
"tspan": ddeSVGTSpanElement;
"use": ddeSVGUseElement;
"view": ddeSVGViewElement;
}
}
// editorconfig-checker-disable
export interface ddeHTMLAnchorElement extends HTMLAnchorElement {
append: ddeAppend<ddeHTMLAnchorElement>;
}
export interface ddeHTMLAreaElement extends HTMLAreaElement {
append: ddeAppend<ddeHTMLAreaElement>;
}
export interface ddeHTMLAudioElement extends HTMLAudioElement {
append: ddeAppend<ddeHTMLAudioElement>;
}
export interface ddeHTMLBaseElement extends HTMLBaseElement {
append: ddeAppend<ddeHTMLBaseElement>;
}
export interface ddeHTMLQuoteElement extends HTMLQuoteElement {
append: ddeAppend<ddeHTMLQuoteElement>;
}
export interface ddeHTMLBodyElement extends HTMLBodyElement {
append: ddeAppend<ddeHTMLBodyElement>;
}
export interface ddeHTMLBRElement extends HTMLBRElement {
append: ddeAppend<ddeHTMLBRElement>;
}
export interface ddeHTMLButtonElement extends HTMLButtonElement {
append: ddeAppend<ddeHTMLButtonElement>;
}
export interface ddeHTMLCanvasElement extends HTMLCanvasElement {
append: ddeAppend<ddeHTMLCanvasElement>;
}
export interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement {
append: ddeAppend<ddeHTMLTableCaptionElement>;
}
export interface ddeHTMLTableColElement extends HTMLTableColElement {
append: ddeAppend<ddeHTMLTableColElement>;
}
export interface ddeHTMLTableColElement extends HTMLTableColElement {
append: ddeAppend<ddeHTMLTableColElement>;
}
export interface ddeHTMLDataElement extends HTMLDataElement {
append: ddeAppend<ddeHTMLDataElement>;
}
export interface ddeHTMLDataListElement extends HTMLDataListElement {
append: ddeAppend<ddeHTMLDataListElement>;
}
export interface ddeHTMLModElement extends HTMLModElement {
append: ddeAppend<ddeHTMLModElement>;
}
export interface ddeHTMLDetailsElement extends HTMLDetailsElement {
append: ddeAppend<ddeHTMLDetailsElement>;
}
export interface ddeHTMLDialogElement extends HTMLDialogElement {
append: ddeAppend<ddeHTMLDialogElement>;
}
export interface ddeHTMLDivElement extends HTMLDivElement {
append: ddeAppend<ddeHTMLDivElement>;
}
export interface ddeHTMLDListElement extends HTMLDListElement {
append: ddeAppend<ddeHTMLDListElement>;
}
export interface ddeHTMLEmbedElement extends HTMLEmbedElement {
append: ddeAppend<ddeHTMLEmbedElement>;
}
export interface ddeHTMLFieldSetElement extends HTMLFieldSetElement {
append: ddeAppend<ddeHTMLFieldSetElement>;
}
export interface ddeHTMLFormElement extends HTMLFormElement {
append: ddeAppend<ddeHTMLFormElement>;
}
export interface ddeHTMLHeadingElement extends HTMLHeadingElement {
append: ddeAppend<ddeHTMLHeadingElement>;
}
export interface ddeHTMLHeadElement extends HTMLHeadElement {
append: ddeAppend<ddeHTMLHeadElement>;
}
export interface ddeHTMLHRElement extends HTMLHRElement {
append: ddeAppend<ddeHTMLHRElement>;
}
export interface ddeHTMLHtmlElement extends HTMLHtmlElement {
append: ddeAppend<ddeHTMLHtmlElement>;
}
export interface ddeHTMLIFrameElement extends HTMLIFrameElement {
append: ddeAppend<ddeHTMLIFrameElement>;
}
export interface ddeHTMLImageElement extends HTMLImageElement {
append: ddeAppend<ddeHTMLImageElement>;
}
export interface ddeHTMLInputElement extends HTMLInputElement {
append: ddeAppend<ddeHTMLInputElement>;
}
export interface ddeHTMLLabelElement extends HTMLLabelElement {
append: ddeAppend<ddeHTMLLabelElement>;
}
export interface ddeHTMLLegendElement extends HTMLLegendElement {
append: ddeAppend<ddeHTMLLegendElement>;
}
export interface ddeHTMLLIElement extends HTMLLIElement {
append: ddeAppend<ddeHTMLLIElement>;
}
export interface ddeHTMLLinkElement extends HTMLLinkElement {
append: ddeAppend<ddeHTMLLinkElement>;
}
export interface ddeHTMLMapElement extends HTMLMapElement {
append: ddeAppend<ddeHTMLMapElement>;
}
export interface ddeHTMLMenuElement extends HTMLMenuElement {
append: ddeAppend<ddeHTMLMenuElement>;
}
export interface ddeHTMLMetaElement extends HTMLMetaElement {
append: ddeAppend<ddeHTMLMetaElement>;
}
export interface ddeHTMLMeterElement extends HTMLMeterElement {
append: ddeAppend<ddeHTMLMeterElement>;
}
export interface ddeHTMLObjectElement extends HTMLObjectElement {
append: ddeAppend<ddeHTMLObjectElement>;
}
export interface ddeHTMLOListElement extends HTMLOListElement {
append: ddeAppend<ddeHTMLOListElement>;
}
export interface ddeHTMLOptGroupElement extends HTMLOptGroupElement {
append: ddeAppend<ddeHTMLOptGroupElement>;
}
export interface ddeHTMLOptionElement extends HTMLOptionElement {
append: ddeAppend<ddeHTMLOptionElement>;
}
export interface ddeHTMLOutputElement extends HTMLOutputElement {
append: ddeAppend<ddeHTMLOutputElement>;
}
export interface ddeHTMLParagraphElement extends HTMLParagraphElement {
append: ddeAppend<ddeHTMLParagraphElement>;
}
export interface ddeHTMLPictureElement extends HTMLPictureElement {
append: ddeAppend<ddeHTMLPictureElement>;
}
export interface ddeHTMLPreElement extends HTMLPreElement {
append: ddeAppend<ddeHTMLPreElement>;
}
export interface ddeHTMLProgressElement extends HTMLProgressElement {
append: ddeAppend<ddeHTMLProgressElement>;
}
export interface ddeHTMLScriptElement extends HTMLScriptElement {
append: ddeAppend<ddeHTMLScriptElement>;
}
export interface ddeHTMLSelectElement extends HTMLSelectElement {
append: ddeAppend<ddeHTMLSelectElement>;
}
export interface ddeHTMLSlotElement extends HTMLSlotElement {
append: ddeAppend<ddeHTMLSlotElement>;
}
export interface ddeHTMLSourceElement extends HTMLSourceElement {
append: ddeAppend<ddeHTMLSourceElement>;
}
export interface ddeHTMLSpanElement extends HTMLSpanElement {
append: ddeAppend<ddeHTMLSpanElement>;
}
export interface ddeHTMLStyleElement extends HTMLStyleElement {
append: ddeAppend<ddeHTMLStyleElement>;
}
export interface ddeHTMLTableElement extends HTMLTableElement {
append: ddeAppend<ddeHTMLTableElement>;
}
export interface ddeHTMLTableSectionElement extends HTMLTableSectionElement {
append: ddeAppend<ddeHTMLTableSectionElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTemplateElement extends HTMLTemplateElement {
append: ddeAppend<ddeHTMLTemplateElement>;
}
export interface ddeHTMLTextAreaElement extends HTMLTextAreaElement {
append: ddeAppend<ddeHTMLTextAreaElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTimeElement extends HTMLTimeElement {
append: ddeAppend<ddeHTMLTimeElement>;
}
export interface ddeHTMLTitleElement extends HTMLTitleElement {
append: ddeAppend<ddeHTMLTitleElement>;
}
export interface ddeHTMLTableRowElement extends HTMLTableRowElement {
append: ddeAppend<ddeHTMLTableRowElement>;
}
export interface ddeHTMLTrackElement extends HTMLTrackElement {
append: ddeAppend<ddeHTMLTrackElement>;
}
export interface ddeHTMLUListElement extends HTMLUListElement {
append: ddeAppend<ddeHTMLUListElement>;
}
export interface ddeHTMLVideoElement extends HTMLVideoElement {
append: ddeAppend<ddeHTMLVideoElement>;
}
export interface ddeSVGAElement extends SVGAElement {
append: ddeAppend<ddeSVGAElement>;
}
export interface ddeSVGAnimateElement extends SVGAnimateElement {
append: ddeAppend<ddeSVGAnimateElement>;
}
export interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement {
append: ddeAppend<ddeSVGAnimateMotionElement>;
}
export interface ddeSVGAnimateTransformElement extends SVGAnimateTransformElement {
append: ddeAppend<ddeSVGAnimateTransformElement>;
}
export interface ddeSVGCircleElement extends SVGCircleElement {
append: ddeAppend<ddeSVGCircleElement>;
}
export interface ddeSVGClipPathElement extends SVGClipPathElement {
append: ddeAppend<ddeSVGClipPathElement>;
}
export interface ddeSVGDefsElement extends SVGDefsElement {
append: ddeAppend<ddeSVGDefsElement>;
}
export interface ddeSVGDescElement extends SVGDescElement {
append: ddeAppend<ddeSVGDescElement>;
}
export interface ddeSVGEllipseElement extends SVGEllipseElement {
append: ddeAppend<ddeSVGEllipseElement>;
}
export interface ddeSVGFEBlendElement extends SVGFEBlendElement {
append: ddeAppend<ddeSVGFEBlendElement>;
}
export interface ddeSVGFEColorMatrixElement extends SVGFEColorMatrixElement {
append: ddeAppend<ddeSVGFEColorMatrixElement>;
}
export interface ddeSVGFEComponentTransferElement extends SVGFEComponentTransferElement {
append: ddeAppend<ddeSVGFEComponentTransferElement>;
}
export interface ddeSVGFECompositeElement extends SVGFECompositeElement {
append: ddeAppend<ddeSVGFECompositeElement>;
}
export interface ddeSVGFEConvolveMatrixElement extends SVGFEConvolveMatrixElement {
append: ddeAppend<ddeSVGFEConvolveMatrixElement>;
}
export interface ddeSVGFEDiffuseLightingElement extends SVGFEDiffuseLightingElement {
append: ddeAppend<ddeSVGFEDiffuseLightingElement>;
}
export interface ddeSVGFEDisplacementMapElement extends SVGFEDisplacementMapElement {
append: ddeAppend<ddeSVGFEDisplacementMapElement>;
}
export interface ddeSVGFEDistantLightElement extends SVGFEDistantLightElement {
append: ddeAppend<ddeSVGFEDistantLightElement>;
}
export interface ddeSVGFEDropShadowElement extends SVGFEDropShadowElement {
append: ddeAppend<ddeSVGFEDropShadowElement>;
}
export interface ddeSVGFEFloodElement extends SVGFEFloodElement {
append: ddeAppend<ddeSVGFEFloodElement>;
}
export interface ddeSVGFEFuncAElement extends SVGFEFuncAElement {
append: ddeAppend<ddeSVGFEFuncAElement>;
}
export interface ddeSVGFEFuncBElement extends SVGFEFuncBElement {
append: ddeAppend<ddeSVGFEFuncBElement>;
}
export interface ddeSVGFEFuncGElement extends SVGFEFuncGElement {
append: ddeAppend<ddeSVGFEFuncGElement>;
}
export interface ddeSVGFEFuncRElement extends SVGFEFuncRElement {
append: ddeAppend<ddeSVGFEFuncRElement>;
}
export interface ddeSVGFEGaussianBlurElement extends SVGFEGaussianBlurElement {
append: ddeAppend<ddeSVGFEGaussianBlurElement>;
}
export interface ddeSVGFEImageElement extends SVGFEImageElement {
append: ddeAppend<ddeSVGFEImageElement>;
}
export interface ddeSVGFEMergeElement extends SVGFEMergeElement {
append: ddeAppend<ddeSVGFEMergeElement>;
}
export interface ddeSVGFEMergeNodeElement extends SVGFEMergeNodeElement {
append: ddeAppend<ddeSVGFEMergeNodeElement>;
}
export interface ddeSVGFEMorphologyElement extends SVGFEMorphologyElement {
append: ddeAppend<ddeSVGFEMorphologyElement>;
}
export interface ddeSVGFEOffsetElement extends SVGFEOffsetElement {
append: ddeAppend<ddeSVGFEOffsetElement>;
}
export interface ddeSVGFEPointLightElement extends SVGFEPointLightElement {
append: ddeAppend<ddeSVGFEPointLightElement>;
}
export interface ddeSVGFESpecularLightingElement extends SVGFESpecularLightingElement {
append: ddeAppend<ddeSVGFESpecularLightingElement>;
}
export interface ddeSVGFESpotLightElement extends SVGFESpotLightElement {
append: ddeAppend<ddeSVGFESpotLightElement>;
}
export interface ddeSVGFETileElement extends SVGFETileElement {
append: ddeAppend<ddeSVGFETileElement>;
}
export interface ddeSVGFETurbulenceElement extends SVGFETurbulenceElement {
append: ddeAppend<ddeSVGFETurbulenceElement>;
}
export interface ddeSVGFilterElement extends SVGFilterElement {
append: ddeAppend<ddeSVGFilterElement>;
}
export interface ddeSVGForeignObjectElement extends SVGForeignObjectElement {
append: ddeAppend<ddeSVGForeignObjectElement>;
}
export interface ddeSVGGElement extends SVGGElement {
append: ddeAppend<ddeSVGGElement>;
}
export interface ddeSVGImageElement extends SVGImageElement {
append: ddeAppend<ddeSVGImageElement>;
}
export interface ddeSVGLineElement extends SVGLineElement {
append: ddeAppend<ddeSVGLineElement>;
}
export interface ddeSVGLinearGradientElement extends SVGLinearGradientElement {
append: ddeAppend<ddeSVGLinearGradientElement>;
}
export interface ddeSVGMarkerElement extends SVGMarkerElement {
append: ddeAppend<ddeSVGMarkerElement>;
}
export interface ddeSVGMaskElement extends SVGMaskElement {
append: ddeAppend<ddeSVGMaskElement>;
}
export interface ddeSVGMetadataElement extends SVGMetadataElement {
append: ddeAppend<ddeSVGMetadataElement>;
}
export interface ddeSVGMPathElement extends SVGMPathElement {
append: ddeAppend<ddeSVGMPathElement>;
}
export interface ddeSVGPathElement extends SVGPathElement {
append: ddeAppend<ddeSVGPathElement>;
}
export interface ddeSVGPatternElement extends SVGPatternElement {
append: ddeAppend<ddeSVGPatternElement>;
}
export interface ddeSVGPolygonElement extends SVGPolygonElement {
append: ddeAppend<ddeSVGPolygonElement>;
}
export interface ddeSVGPolylineElement extends SVGPolylineElement {
append: ddeAppend<ddeSVGPolylineElement>;
}
export interface ddeSVGRadialGradientElement extends SVGRadialGradientElement {
append: ddeAppend<ddeSVGRadialGradientElement>;
}
export interface ddeSVGRectElement extends SVGRectElement {
append: ddeAppend<ddeSVGRectElement>;
}
export interface ddeSVGScriptElement extends SVGScriptElement {
append: ddeAppend<ddeSVGScriptElement>;
}
export interface ddeSVGSetElement extends SVGSetElement {
append: ddeAppend<ddeSVGSetElement>;
}
export interface ddeSVGStopElement extends SVGStopElement {
append: ddeAppend<ddeSVGStopElement>;
}
export interface ddeSVGStyleElement extends SVGStyleElement {
append: ddeAppend<ddeSVGStyleElement>;
}
export interface ddeSVGSVGElement extends SVGSVGElement {
append: ddeAppend<ddeSVGSVGElement>;
}
export interface ddeSVGSwitchElement extends SVGSwitchElement {
append: ddeAppend<ddeSVGSwitchElement>;
}
export interface ddeSVGSymbolElement extends SVGSymbolElement {
append: ddeAppend<ddeSVGSymbolElement>;
}
export interface ddeSVGTextElement extends SVGTextElement {
append: ddeAppend<ddeSVGTextElement>;
}
export interface ddeSVGTextPathElement extends SVGTextPathElement {
append: ddeAppend<ddeSVGTextPathElement>;
}
export interface ddeSVGTitleElement extends SVGTitleElement {
append: ddeAppend<ddeSVGTitleElement>;
}
export interface ddeSVGTSpanElement extends SVGTSpanElement {
append: ddeAppend<ddeSVGTSpanElement>;
}
export interface ddeSVGUseElement extends SVGUseElement {
append: ddeAppend<ddeSVGUseElement>;
}
export interface ddeSVGViewElement extends SVGViewElement {
append: ddeAppend<ddeSVGViewElement>;
}
export {
dispatchEvent$1 as dispatchEvent,
el as createElement,
elNS as createElementNS,
};
export as namespace dde;
export {};

1104
dist/dde.js vendored

File diff suppressed because it is too large Load Diff

784
dist/dde.min.d.ts vendored Normal file
View File

@ -0,0 +1,784 @@
// Generated by dts-bundle-generator v9.5.1
export interface Signal<V, A> {
/** The current value of the signal */
get(): V;
/** Set new value of the signal */
set(value: V): V;
toJSON(): V;
valueOf(): V;
}
export type Action<V> = (this: {
value: V;
stopPropagation(): void;
}, ...a: any[]) => typeof signal._ | void;
//type SymbolSignal= Symbol;
export type SymbolOnclear = symbol;
export type Actions<V> = Record<string | SymbolOnclear, Action<V>>;
export type OnListenerOptions = Pick<AddEventListenerOptions, "signal"> & {
first_time?: boolean;
};
export interface signal {
_: Symbol;
/**
* Computations signal. This creates a signal which is computed from other signals.
* */
<V extends () => any>(computation: V): Signal<ReturnType<V>, {}>;
/**
* Simple example:
* ```js
* const hello= S("Hello Signal");
* ```
* simple todo signal:
* ```js
* const todos= S([], {
* add(v){ this.value.push(S(v)); },
* remove(i){ this.value.splice(i, 1); },
* [S.symbols.onclear](){ S.clear(...this.value); },
* });
* ```
* computed signal:
* ```js
* const name= S("Jan");
* const surname= S("Andrle");
* const fullname= S(()=> name.get()+" "+surname.get());
* ```
* @param value Initial signal value. Or function computing value from other signals.
* @param actions Use to define actions on the signal. Such as add item to the array.
* There is also a reserved function `S.symbol.onclear` which is called when the signal is cleared
* by `S.clear`.
* */
<V, A extends Actions<V>>(value: V, actions?: A): Signal<V, A>;
action<S extends Signal<any, Actions<any>>, A extends (S extends Signal<any, infer A> ? A : never), N extends keyof A>(signal: S, name: N, ...params: A[N] extends (...args: infer P) => any ? P : never): void;
clear(...signals: Signal<any, any>[]): void;
on<T>(signal: Signal<T, any>, onchange: (a: T) => void, options?: OnListenerOptions): void;
symbols: {
//signal: SymbolSignal;
onclear: SymbolOnclear;
};
/**
* Reactive element, which is rendered based on the given signal.
* ```js
* S.el(signal, value=> value ? el("b", "True") : el("i", "False"));
* S.el(listS, list=> list.map(li=> el("li", li)));
* ```
* */
el<S extends any>(signal: Signal<S, any>, el: (v: S) => Element | Element[] | DocumentFragment): DocumentFragment;
observedAttributes(custom_element: HTMLElement): Record<string, Signal<string, {}>>;
}
declare const signal: signal;
declare global {
type ddeSignal<T, A = {}> = Signal<T, A>;
type ddeAction<V> = Action<V>;
type ddeActions<V> = Actions<V>;
}
export type CustomElementTagNameMap = {
"#text": Text;
"#comment": Comment;
};
export type SupportedElement = HTMLElementTagNameMap[keyof HTMLElementTagNameMap] | SVGElementTagNameMap[keyof SVGElementTagNameMap] | MathMLElementTagNameMap[keyof MathMLElementTagNameMap] | CustomElementTagNameMap[keyof CustomElementTagNameMap];
declare global {
type ddeComponentAttributes = Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment | Node> = (element: El) => any;
type ddeString = string | Signal<string, {}>;
type ddeStringable = ddeString | number | Signal<number, {}>;
}
export type PascalCase = `${Capitalize<string>}${string}`;
export type AttrsModified = {
/**
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/
style: Partial<CSSStyleDeclaration> | ddeString | Partial<{
[K in keyof CSSStyleDeclaration]: Signal<CSSStyleDeclaration[K], {}>;
}>;
/**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1.
* In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))`
* for others.
*/
classList: Record<string, -1 | 0 | 1 | boolean | Signal<-1 | 0 | 1 | boolean, {}>>;
/**
* Used by the dataset HTML attribute to represent data for custom attributes added to elements.
* Values are converted to string (see {@link DOMStringMap}).
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMStringMap)
* */
dataset: Record<string, ddeStringable>;
/**
* Sets `aria-*` simiraly to `dataset`
* */
ariaset: Record<string, ddeString>;
} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, ddeString> & Record<`.${string}`, any>;
export type _fromElsInterfaces<EL extends SupportedElement> = Omit<EL, keyof AttrsModified>;
export type IsReadonly<T, K extends keyof T> = T extends {
readonly [P in K]: T[K];
} ? true : false;
/**
* Just element attributtes
*
* In most cases, you can use native propertie such as
* [MDN WEB/API/Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) and so on
* (e.g. [`Text`](https://developer.mozilla.org/en-US/docs/Web/API/Text)).
*
* There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives.
* @private
*/
export type ElementAttributes<T extends SupportedElement> = Partial<{
[K in keyof _fromElsInterfaces<T>]: _fromElsInterfaces<T>[K] extends ((...p: any[]) => any) ? _fromElsInterfaces<T>[K] | ((...p: Parameters<_fromElsInterfaces<T>[K]>) => Signal<ReturnType<_fromElsInterfaces<T>[K]>, {}>) : (IsReadonly<_fromElsInterfaces<T>, K> extends false ? _fromElsInterfaces<T>[K] | Signal<_fromElsInterfaces<T>[K], {}> : ddeStringable);
} & AttrsModified> & Record<string, any>;
export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El;
export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El;
export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT];
export type ExtendedHTMLElementTagNameMap = HTMLElementTagNameMap & CustomElementTagNameMap;
export namespace el {
/**
* Creates a marker comment for elements
*
* @param attrs - Marker attributes
* @param [is_open=false] - Whether the marker is open-ended
* @returns Comment node marker
*/
export function mark(attrs: {
type: "component" | "reactive" | "later";
name?: string;
host?: "this" | "parentElement";
}, is_open?: boolean): Comment;
}
export function el<A extends ddeComponentAttributes, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>, ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
export function el<A extends {
textContent: ddeStringable;
}, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>["textContent"], ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
export function el<TAG extends keyof ExtendedHTMLElementTagNameMap>(tag_name: TAG, attrs?: ElementAttributes<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]> | ddeStringable, ...addons: ddeElementAddon<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]>[]): TAG extends keyof ddeHTMLElementTagNameMap ? ddeHTMLElementTagNameMap[TAG] : ddeHTMLElement;
export function el(tag_name?: "<>"): ddeDocumentFragment;
export function el(tag_name: string, attrs?: ElementAttributes<HTMLElement> | ddeStringable, ...addons: ddeElementAddon<HTMLElement>[]): ddeHTMLElement;
export function elNS(namespace: "http://www.w3.org/2000/svg"): <TAG extends keyof SVGElementTagNameMap & string, EL extends (TAG extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[TAG] : SVGElement)>(tag_name: TAG, attrs?: ElementAttributes<NoInfer<EL>> | ddeStringable, ...addons: ddeElementAddon<NoInfer<EL>>[]) => TAG extends keyof ddeSVGElementTagNameMap ? ddeSVGElementTagNameMap[TAG] : ddeSVGElement;
export function elNS(namespace: "http://www.w3.org/1998/Math/MathML"): <TAG extends keyof MathMLElementTagNameMap & string, EL extends (TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement)>(tag_name: TAG, attrs?: ddeStringable | Partial<{
[key in keyof EL]: EL[key] | Signal<EL[key], {}> | string | number | boolean;
}>, ...addons: ddeElementAddon<NoInfer<EL>>[]) => ddeMathMLElement;
export function elNS(namespace: string): (tag_name: string, attrs?: string | ddeStringable | Record<string, any>, ...addons: ddeElementAddon<SupportedElement>[]) => SupportedElement;
export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
/** Simulate slots for ddeComponents */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(root: EL): EL;
/**
* Simulate slots in Custom Elements without using `shadowRoot`.
* @param el Custom Element root element
* @param body Body of the custom element
* */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: HTMLElement, body: EL): EL;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, element: SupportedElement): (data?: any) => void;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options?: EventInit): (element: SupportedElement, data?: any) => void;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, element: SupportedElement | (() => SupportedElement)): (data?: any) => void;
export interface On {
/** Listens to the DOM event. See {@link Document.addEventListener} */
<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE;
<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[
string,
string
]>) => any, options?: AddEventListenerOptions): EE;
}
export const on: On;
export type Scope = {
scope: Node | Function | Object;
host: ddeElementAddon<any>;
custom_element: false | HTMLElement;
prevent: boolean;
};
/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */
export const scope: {
current: Scope;
/** Stops all automatizations. E. g. signals used as attributes in current scope
* registers removing these listeners (and clean signal if no other listeners are detected)
* on `disconnected` event. */
preventDefault<T extends boolean>(prevent: T): T;
/**
* This represents reference to the current host element `scope.host()`.
* It can be also used to register Addon(s) (functions to be called when component is initized)
* `scope.host(on.connected(console.log))`.
* */
host: (...addons: ddeElementAddon<SupportedElement>[]) => HTMLElement;
state: Scope[];
/** Adds new child scope. All attributes are inherited by default. */
push(scope?: Partial<Scope>): ReturnType<Array<Scope>["push"]>;
/** Adds root scope as a child of the current scope. */
pushRoot(): ReturnType<Array<Scope>["push"]>;
/** Removes last/current child scope. */
pop(): ReturnType<Array<Scope>["pop"]>;
};
export function customElementRender<EL extends HTMLElement, P extends any = Record<string, string | Signal<string, {}>>>(target: ShadowRoot | EL, render: (props: P) => SupportedElement | DocumentFragment, props?: P | ((el: EL) => P)): EL;
export function customElementWithDDE<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
export function lifecyclesToEvents<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
export function observedAttributes(custom_element: HTMLElement): Record<string, string>;
/**
* This is used primarly for server side rendering. To be sure that all async operations
* are finished before the page is sent to the client.
* ```
* // on component
* function component(){
*
* queue(fetch(...).then(...));
* }
*
* // building the page
* async function build(){
* const { component }= await import("./component.js");
* document.body.append(el(component));
* await queue();
* retutn document.body.innerHTML;
* }
* ```
* */
export function queue(promise?: Promise<unknown>): Promise<unknown>;
/* TypeScript MEH */
declare global {
type ddeAppend<el> = (...nodes: (Node | string)[]) => el;
interface ddeDocumentFragment extends DocumentFragment {
append: ddeAppend<ddeDocumentFragment>;
}
interface ddeHTMLElement extends HTMLElement {
append: ddeAppend<ddeHTMLElement>;
}
interface ddeSVGElement extends SVGElement {
append: ddeAppend<ddeSVGElement>;
}
interface ddeMathMLElement extends MathMLElement {
append: ddeAppend<ddeMathMLElement>;
}
interface ddeHTMLElementTagNameMap {
"a": ddeHTMLAnchorElement;
"area": ddeHTMLAreaElement;
"audio": ddeHTMLAudioElement;
"base": ddeHTMLBaseElement;
"blockquote": ddeHTMLQuoteElement;
"body": ddeHTMLBodyElement;
"br": ddeHTMLBRElement;
"button": ddeHTMLButtonElement;
"canvas": ddeHTMLCanvasElement;
"caption": ddeHTMLTableCaptionElement;
"col": ddeHTMLTableColElement;
"colgroup": ddeHTMLTableColElement;
"data": ddeHTMLDataElement;
"datalist": ddeHTMLDataListElement;
"del": ddeHTMLModElement;
"details": ddeHTMLDetailsElement;
"dialog": ddeHTMLDialogElement;
"div": ddeHTMLDivElement;
"dl": ddeHTMLDListElement;
"embed": ddeHTMLEmbedElement;
"fieldset": ddeHTMLFieldSetElement;
"form": ddeHTMLFormElement;
"h1": ddeHTMLHeadingElement;
"h2": ddeHTMLHeadingElement;
"h3": ddeHTMLHeadingElement;
"h4": ddeHTMLHeadingElement;
"h5": ddeHTMLHeadingElement;
"h6": ddeHTMLHeadingElement;
"head": ddeHTMLHeadElement;
"hr": ddeHTMLHRElement;
"html": ddeHTMLHtmlElement;
"iframe": ddeHTMLIFrameElement;
"img": ddeHTMLImageElement;
"input": ddeHTMLInputElement;
"ins": ddeHTMLModElement;
"label": ddeHTMLLabelElement;
"legend": ddeHTMLLegendElement;
"li": ddeHTMLLIElement;
"link": ddeHTMLLinkElement;
"map": ddeHTMLMapElement;
"menu": ddeHTMLMenuElement;
"meta": ddeHTMLMetaElement;
"meter": ddeHTMLMeterElement;
"object": ddeHTMLObjectElement;
"ol": ddeHTMLOListElement;
"optgroup": ddeHTMLOptGroupElement;
"option": ddeHTMLOptionElement;
"output": ddeHTMLOutputElement;
"p": ddeHTMLParagraphElement;
"picture": ddeHTMLPictureElement;
"pre": ddeHTMLPreElement;
"progress": ddeHTMLProgressElement;
"q": ddeHTMLQuoteElement;
"script": ddeHTMLScriptElement;
"select": ddeHTMLSelectElement;
"slot": ddeHTMLSlotElement;
"source": ddeHTMLSourceElement;
"span": ddeHTMLSpanElement;
"style": ddeHTMLStyleElement;
"table": ddeHTMLTableElement;
"tbody": ddeHTMLTableSectionElement;
"td": ddeHTMLTableCellElement;
"template": ddeHTMLTemplateElement;
"textarea": ddeHTMLTextAreaElement;
"tfoot": ddeHTMLTableSectionElement;
"th": ddeHTMLTableCellElement;
"thead": ddeHTMLTableSectionElement;
"time": ddeHTMLTimeElement;
"title": ddeHTMLTitleElement;
"tr": ddeHTMLTableRowElement;
"track": ddeHTMLTrackElement;
"ul": ddeHTMLUListElement;
"video": ddeHTMLVideoElement;
}
interface ddeSVGElementTagNameMap {
"a": ddeSVGAElement;
"animate": ddeSVGAnimateElement;
"animateMotion": ddeSVGAnimateMotionElement;
"animateTransform": ddeSVGAnimateTransformElement;
"circle": ddeSVGCircleElement;
"clipPath": ddeSVGClipPathElement;
"defs": ddeSVGDefsElement;
"desc": ddeSVGDescElement;
"ellipse": ddeSVGEllipseElement;
"feBlend": ddeSVGFEBlendElement;
"feColorMatrix": ddeSVGFEColorMatrixElement;
"feComponentTransfer": ddeSVGFEComponentTransferElement;
"feComposite": ddeSVGFECompositeElement;
"feConvolveMatrix": ddeSVGFEConvolveMatrixElement;
"feDiffuseLighting": ddeSVGFEDiffuseLightingElement;
"feDisplacementMap": ddeSVGFEDisplacementMapElement;
"feDistantLight": ddeSVGFEDistantLightElement;
"feDropShadow": ddeSVGFEDropShadowElement;
"feFlood": ddeSVGFEFloodElement;
"feFuncA": ddeSVGFEFuncAElement;
"feFuncB": ddeSVGFEFuncBElement;
"feFuncG": ddeSVGFEFuncGElement;
"feFuncR": ddeSVGFEFuncRElement;
"feGaussianBlur": ddeSVGFEGaussianBlurElement;
"feImage": ddeSVGFEImageElement;
"feMerge": ddeSVGFEMergeElement;
"feMergeNode": ddeSVGFEMergeNodeElement;
"feMorphology": ddeSVGFEMorphologyElement;
"feOffset": ddeSVGFEOffsetElement;
"fePointLight": ddeSVGFEPointLightElement;
"feSpecularLighting": ddeSVGFESpecularLightingElement;
"feSpotLight": ddeSVGFESpotLightElement;
"feTile": ddeSVGFETileElement;
"feTurbulence": ddeSVGFETurbulenceElement;
"filter": ddeSVGFilterElement;
"foreignObject": ddeSVGForeignObjectElement;
"g": ddeSVGGElement;
"image": ddeSVGImageElement;
"line": ddeSVGLineElement;
"linearGradient": ddeSVGLinearGradientElement;
"marker": ddeSVGMarkerElement;
"mask": ddeSVGMaskElement;
"metadata": ddeSVGMetadataElement;
"mpath": ddeSVGMPathElement;
"path": ddeSVGPathElement;
"pattern": ddeSVGPatternElement;
"polygon": ddeSVGPolygonElement;
"polyline": ddeSVGPolylineElement;
"radialGradient": ddeSVGRadialGradientElement;
"rect": ddeSVGRectElement;
"script": ddeSVGScriptElement;
"set": ddeSVGSetElement;
"stop": ddeSVGStopElement;
"style": ddeSVGStyleElement;
"svg": ddeSVGSVGElement;
"switch": ddeSVGSwitchElement;
"symbol": ddeSVGSymbolElement;
"text": ddeSVGTextElement;
"textPath": ddeSVGTextPathElement;
"title": ddeSVGTitleElement;
"tspan": ddeSVGTSpanElement;
"use": ddeSVGUseElement;
"view": ddeSVGViewElement;
}
}
// editorconfig-checker-disable
export interface ddeHTMLAnchorElement extends HTMLAnchorElement {
append: ddeAppend<ddeHTMLAnchorElement>;
}
export interface ddeHTMLAreaElement extends HTMLAreaElement {
append: ddeAppend<ddeHTMLAreaElement>;
}
export interface ddeHTMLAudioElement extends HTMLAudioElement {
append: ddeAppend<ddeHTMLAudioElement>;
}
export interface ddeHTMLBaseElement extends HTMLBaseElement {
append: ddeAppend<ddeHTMLBaseElement>;
}
export interface ddeHTMLQuoteElement extends HTMLQuoteElement {
append: ddeAppend<ddeHTMLQuoteElement>;
}
export interface ddeHTMLBodyElement extends HTMLBodyElement {
append: ddeAppend<ddeHTMLBodyElement>;
}
export interface ddeHTMLBRElement extends HTMLBRElement {
append: ddeAppend<ddeHTMLBRElement>;
}
export interface ddeHTMLButtonElement extends HTMLButtonElement {
append: ddeAppend<ddeHTMLButtonElement>;
}
export interface ddeHTMLCanvasElement extends HTMLCanvasElement {
append: ddeAppend<ddeHTMLCanvasElement>;
}
export interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement {
append: ddeAppend<ddeHTMLTableCaptionElement>;
}
export interface ddeHTMLTableColElement extends HTMLTableColElement {
append: ddeAppend<ddeHTMLTableColElement>;
}
export interface ddeHTMLTableColElement extends HTMLTableColElement {
append: ddeAppend<ddeHTMLTableColElement>;
}
export interface ddeHTMLDataElement extends HTMLDataElement {
append: ddeAppend<ddeHTMLDataElement>;
}
export interface ddeHTMLDataListElement extends HTMLDataListElement {
append: ddeAppend<ddeHTMLDataListElement>;
}
export interface ddeHTMLModElement extends HTMLModElement {
append: ddeAppend<ddeHTMLModElement>;
}
export interface ddeHTMLDetailsElement extends HTMLDetailsElement {
append: ddeAppend<ddeHTMLDetailsElement>;
}
export interface ddeHTMLDialogElement extends HTMLDialogElement {
append: ddeAppend<ddeHTMLDialogElement>;
}
export interface ddeHTMLDivElement extends HTMLDivElement {
append: ddeAppend<ddeHTMLDivElement>;
}
export interface ddeHTMLDListElement extends HTMLDListElement {
append: ddeAppend<ddeHTMLDListElement>;
}
export interface ddeHTMLEmbedElement extends HTMLEmbedElement {
append: ddeAppend<ddeHTMLEmbedElement>;
}
export interface ddeHTMLFieldSetElement extends HTMLFieldSetElement {
append: ddeAppend<ddeHTMLFieldSetElement>;
}
export interface ddeHTMLFormElement extends HTMLFormElement {
append: ddeAppend<ddeHTMLFormElement>;
}
export interface ddeHTMLHeadingElement extends HTMLHeadingElement {
append: ddeAppend<ddeHTMLHeadingElement>;
}
export interface ddeHTMLHeadElement extends HTMLHeadElement {
append: ddeAppend<ddeHTMLHeadElement>;
}
export interface ddeHTMLHRElement extends HTMLHRElement {
append: ddeAppend<ddeHTMLHRElement>;
}
export interface ddeHTMLHtmlElement extends HTMLHtmlElement {
append: ddeAppend<ddeHTMLHtmlElement>;
}
export interface ddeHTMLIFrameElement extends HTMLIFrameElement {
append: ddeAppend<ddeHTMLIFrameElement>;
}
export interface ddeHTMLImageElement extends HTMLImageElement {
append: ddeAppend<ddeHTMLImageElement>;
}
export interface ddeHTMLInputElement extends HTMLInputElement {
append: ddeAppend<ddeHTMLInputElement>;
}
export interface ddeHTMLLabelElement extends HTMLLabelElement {
append: ddeAppend<ddeHTMLLabelElement>;
}
export interface ddeHTMLLegendElement extends HTMLLegendElement {
append: ddeAppend<ddeHTMLLegendElement>;
}
export interface ddeHTMLLIElement extends HTMLLIElement {
append: ddeAppend<ddeHTMLLIElement>;
}
export interface ddeHTMLLinkElement extends HTMLLinkElement {
append: ddeAppend<ddeHTMLLinkElement>;
}
export interface ddeHTMLMapElement extends HTMLMapElement {
append: ddeAppend<ddeHTMLMapElement>;
}
export interface ddeHTMLMenuElement extends HTMLMenuElement {
append: ddeAppend<ddeHTMLMenuElement>;
}
export interface ddeHTMLMetaElement extends HTMLMetaElement {
append: ddeAppend<ddeHTMLMetaElement>;
}
export interface ddeHTMLMeterElement extends HTMLMeterElement {
append: ddeAppend<ddeHTMLMeterElement>;
}
export interface ddeHTMLObjectElement extends HTMLObjectElement {
append: ddeAppend<ddeHTMLObjectElement>;
}
export interface ddeHTMLOListElement extends HTMLOListElement {
append: ddeAppend<ddeHTMLOListElement>;
}
export interface ddeHTMLOptGroupElement extends HTMLOptGroupElement {
append: ddeAppend<ddeHTMLOptGroupElement>;
}
export interface ddeHTMLOptionElement extends HTMLOptionElement {
append: ddeAppend<ddeHTMLOptionElement>;
}
export interface ddeHTMLOutputElement extends HTMLOutputElement {
append: ddeAppend<ddeHTMLOutputElement>;
}
export interface ddeHTMLParagraphElement extends HTMLParagraphElement {
append: ddeAppend<ddeHTMLParagraphElement>;
}
export interface ddeHTMLPictureElement extends HTMLPictureElement {
append: ddeAppend<ddeHTMLPictureElement>;
}
export interface ddeHTMLPreElement extends HTMLPreElement {
append: ddeAppend<ddeHTMLPreElement>;
}
export interface ddeHTMLProgressElement extends HTMLProgressElement {
append: ddeAppend<ddeHTMLProgressElement>;
}
export interface ddeHTMLScriptElement extends HTMLScriptElement {
append: ddeAppend<ddeHTMLScriptElement>;
}
export interface ddeHTMLSelectElement extends HTMLSelectElement {
append: ddeAppend<ddeHTMLSelectElement>;
}
export interface ddeHTMLSlotElement extends HTMLSlotElement {
append: ddeAppend<ddeHTMLSlotElement>;
}
export interface ddeHTMLSourceElement extends HTMLSourceElement {
append: ddeAppend<ddeHTMLSourceElement>;
}
export interface ddeHTMLSpanElement extends HTMLSpanElement {
append: ddeAppend<ddeHTMLSpanElement>;
}
export interface ddeHTMLStyleElement extends HTMLStyleElement {
append: ddeAppend<ddeHTMLStyleElement>;
}
export interface ddeHTMLTableElement extends HTMLTableElement {
append: ddeAppend<ddeHTMLTableElement>;
}
export interface ddeHTMLTableSectionElement extends HTMLTableSectionElement {
append: ddeAppend<ddeHTMLTableSectionElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTemplateElement extends HTMLTemplateElement {
append: ddeAppend<ddeHTMLTemplateElement>;
}
export interface ddeHTMLTextAreaElement extends HTMLTextAreaElement {
append: ddeAppend<ddeHTMLTextAreaElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTimeElement extends HTMLTimeElement {
append: ddeAppend<ddeHTMLTimeElement>;
}
export interface ddeHTMLTitleElement extends HTMLTitleElement {
append: ddeAppend<ddeHTMLTitleElement>;
}
export interface ddeHTMLTableRowElement extends HTMLTableRowElement {
append: ddeAppend<ddeHTMLTableRowElement>;
}
export interface ddeHTMLTrackElement extends HTMLTrackElement {
append: ddeAppend<ddeHTMLTrackElement>;
}
export interface ddeHTMLUListElement extends HTMLUListElement {
append: ddeAppend<ddeHTMLUListElement>;
}
export interface ddeHTMLVideoElement extends HTMLVideoElement {
append: ddeAppend<ddeHTMLVideoElement>;
}
export interface ddeSVGAElement extends SVGAElement {
append: ddeAppend<ddeSVGAElement>;
}
export interface ddeSVGAnimateElement extends SVGAnimateElement {
append: ddeAppend<ddeSVGAnimateElement>;
}
export interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement {
append: ddeAppend<ddeSVGAnimateMotionElement>;
}
export interface ddeSVGAnimateTransformElement extends SVGAnimateTransformElement {
append: ddeAppend<ddeSVGAnimateTransformElement>;
}
export interface ddeSVGCircleElement extends SVGCircleElement {
append: ddeAppend<ddeSVGCircleElement>;
}
export interface ddeSVGClipPathElement extends SVGClipPathElement {
append: ddeAppend<ddeSVGClipPathElement>;
}
export interface ddeSVGDefsElement extends SVGDefsElement {
append: ddeAppend<ddeSVGDefsElement>;
}
export interface ddeSVGDescElement extends SVGDescElement {
append: ddeAppend<ddeSVGDescElement>;
}
export interface ddeSVGEllipseElement extends SVGEllipseElement {
append: ddeAppend<ddeSVGEllipseElement>;
}
export interface ddeSVGFEBlendElement extends SVGFEBlendElement {
append: ddeAppend<ddeSVGFEBlendElement>;
}
export interface ddeSVGFEColorMatrixElement extends SVGFEColorMatrixElement {
append: ddeAppend<ddeSVGFEColorMatrixElement>;
}
export interface ddeSVGFEComponentTransferElement extends SVGFEComponentTransferElement {
append: ddeAppend<ddeSVGFEComponentTransferElement>;
}
export interface ddeSVGFECompositeElement extends SVGFECompositeElement {
append: ddeAppend<ddeSVGFECompositeElement>;
}
export interface ddeSVGFEConvolveMatrixElement extends SVGFEConvolveMatrixElement {
append: ddeAppend<ddeSVGFEConvolveMatrixElement>;
}
export interface ddeSVGFEDiffuseLightingElement extends SVGFEDiffuseLightingElement {
append: ddeAppend<ddeSVGFEDiffuseLightingElement>;
}
export interface ddeSVGFEDisplacementMapElement extends SVGFEDisplacementMapElement {
append: ddeAppend<ddeSVGFEDisplacementMapElement>;
}
export interface ddeSVGFEDistantLightElement extends SVGFEDistantLightElement {
append: ddeAppend<ddeSVGFEDistantLightElement>;
}
export interface ddeSVGFEDropShadowElement extends SVGFEDropShadowElement {
append: ddeAppend<ddeSVGFEDropShadowElement>;
}
export interface ddeSVGFEFloodElement extends SVGFEFloodElement {
append: ddeAppend<ddeSVGFEFloodElement>;
}
export interface ddeSVGFEFuncAElement extends SVGFEFuncAElement {
append: ddeAppend<ddeSVGFEFuncAElement>;
}
export interface ddeSVGFEFuncBElement extends SVGFEFuncBElement {
append: ddeAppend<ddeSVGFEFuncBElement>;
}
export interface ddeSVGFEFuncGElement extends SVGFEFuncGElement {
append: ddeAppend<ddeSVGFEFuncGElement>;
}
export interface ddeSVGFEFuncRElement extends SVGFEFuncRElement {
append: ddeAppend<ddeSVGFEFuncRElement>;
}
export interface ddeSVGFEGaussianBlurElement extends SVGFEGaussianBlurElement {
append: ddeAppend<ddeSVGFEGaussianBlurElement>;
}
export interface ddeSVGFEImageElement extends SVGFEImageElement {
append: ddeAppend<ddeSVGFEImageElement>;
}
export interface ddeSVGFEMergeElement extends SVGFEMergeElement {
append: ddeAppend<ddeSVGFEMergeElement>;
}
export interface ddeSVGFEMergeNodeElement extends SVGFEMergeNodeElement {
append: ddeAppend<ddeSVGFEMergeNodeElement>;
}
export interface ddeSVGFEMorphologyElement extends SVGFEMorphologyElement {
append: ddeAppend<ddeSVGFEMorphologyElement>;
}
export interface ddeSVGFEOffsetElement extends SVGFEOffsetElement {
append: ddeAppend<ddeSVGFEOffsetElement>;
}
export interface ddeSVGFEPointLightElement extends SVGFEPointLightElement {
append: ddeAppend<ddeSVGFEPointLightElement>;
}
export interface ddeSVGFESpecularLightingElement extends SVGFESpecularLightingElement {
append: ddeAppend<ddeSVGFESpecularLightingElement>;
}
export interface ddeSVGFESpotLightElement extends SVGFESpotLightElement {
append: ddeAppend<ddeSVGFESpotLightElement>;
}
export interface ddeSVGFETileElement extends SVGFETileElement {
append: ddeAppend<ddeSVGFETileElement>;
}
export interface ddeSVGFETurbulenceElement extends SVGFETurbulenceElement {
append: ddeAppend<ddeSVGFETurbulenceElement>;
}
export interface ddeSVGFilterElement extends SVGFilterElement {
append: ddeAppend<ddeSVGFilterElement>;
}
export interface ddeSVGForeignObjectElement extends SVGForeignObjectElement {
append: ddeAppend<ddeSVGForeignObjectElement>;
}
export interface ddeSVGGElement extends SVGGElement {
append: ddeAppend<ddeSVGGElement>;
}
export interface ddeSVGImageElement extends SVGImageElement {
append: ddeAppend<ddeSVGImageElement>;
}
export interface ddeSVGLineElement extends SVGLineElement {
append: ddeAppend<ddeSVGLineElement>;
}
export interface ddeSVGLinearGradientElement extends SVGLinearGradientElement {
append: ddeAppend<ddeSVGLinearGradientElement>;
}
export interface ddeSVGMarkerElement extends SVGMarkerElement {
append: ddeAppend<ddeSVGMarkerElement>;
}
export interface ddeSVGMaskElement extends SVGMaskElement {
append: ddeAppend<ddeSVGMaskElement>;
}
export interface ddeSVGMetadataElement extends SVGMetadataElement {
append: ddeAppend<ddeSVGMetadataElement>;
}
export interface ddeSVGMPathElement extends SVGMPathElement {
append: ddeAppend<ddeSVGMPathElement>;
}
export interface ddeSVGPathElement extends SVGPathElement {
append: ddeAppend<ddeSVGPathElement>;
}
export interface ddeSVGPatternElement extends SVGPatternElement {
append: ddeAppend<ddeSVGPatternElement>;
}
export interface ddeSVGPolygonElement extends SVGPolygonElement {
append: ddeAppend<ddeSVGPolygonElement>;
}
export interface ddeSVGPolylineElement extends SVGPolylineElement {
append: ddeAppend<ddeSVGPolylineElement>;
}
export interface ddeSVGRadialGradientElement extends SVGRadialGradientElement {
append: ddeAppend<ddeSVGRadialGradientElement>;
}
export interface ddeSVGRectElement extends SVGRectElement {
append: ddeAppend<ddeSVGRectElement>;
}
export interface ddeSVGScriptElement extends SVGScriptElement {
append: ddeAppend<ddeSVGScriptElement>;
}
export interface ddeSVGSetElement extends SVGSetElement {
append: ddeAppend<ddeSVGSetElement>;
}
export interface ddeSVGStopElement extends SVGStopElement {
append: ddeAppend<ddeSVGStopElement>;
}
export interface ddeSVGStyleElement extends SVGStyleElement {
append: ddeAppend<ddeSVGStyleElement>;
}
export interface ddeSVGSVGElement extends SVGSVGElement {
append: ddeAppend<ddeSVGSVGElement>;
}
export interface ddeSVGSwitchElement extends SVGSwitchElement {
append: ddeAppend<ddeSVGSwitchElement>;
}
export interface ddeSVGSymbolElement extends SVGSymbolElement {
append: ddeAppend<ddeSVGSymbolElement>;
}
export interface ddeSVGTextElement extends SVGTextElement {
append: ddeAppend<ddeSVGTextElement>;
}
export interface ddeSVGTextPathElement extends SVGTextPathElement {
append: ddeAppend<ddeSVGTextPathElement>;
}
export interface ddeSVGTitleElement extends SVGTitleElement {
append: ddeAppend<ddeSVGTitleElement>;
}
export interface ddeSVGTSpanElement extends SVGTSpanElement {
append: ddeAppend<ddeSVGTSpanElement>;
}
export interface ddeSVGUseElement extends SVGUseElement {
append: ddeAppend<ddeSVGUseElement>;
}
export interface ddeSVGViewElement extends SVGViewElement {
append: ddeAppend<ddeSVGViewElement>;
}
export {
dispatchEvent$1 as dispatchEvent,
el as createElement,
elNS as createElementNS,
};
export as namespace dde;
export {};

1
dist/dde.min.js vendored Normal file

File diff suppressed because one or more lines are too long

641
dist/esm-with-signals.d.min.ts vendored Normal file
View File

@ -0,0 +1,641 @@
declare global{ /* ddeSignal */ }
type CustomElementTagNameMap= { '#text': Text, '#comment': Comment }
type SupportedElement=
HTMLElementTagNameMap[keyof HTMLElementTagNameMap]
| SVGElementTagNameMap[keyof SVGElementTagNameMap]
| MathMLElementTagNameMap[keyof MathMLElementTagNameMap]
| CustomElementTagNameMap[keyof CustomElementTagNameMap]
declare global {
type ddeComponentAttributes= Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment | Node>= (element: El)=> any;
type ddeString= string | ddeSignal<string>
type ddeStringable= ddeString | number | ddeSignal<number>
}
type PascalCase=
`${Capitalize<string>}${string}`;
type AttrsModified= {
/**
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/
style: Partial<CSSStyleDeclaration> | ddeString
| Partial<{ [K in keyof CSSStyleDeclaration]: ddeSignal<CSSStyleDeclaration[K]> }>
/**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1.
* In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))`
* for others.
*/
classList: Record<string,-1|0|1|boolean|ddeSignal<-1|0|1|boolean>>,
/**
* Used by the dataset HTML attribute to represent data for custom attributes added to elements.
* Values are converted to string (see {@link DOMStringMap}).
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMStringMap)
* */
dataset: Record<string, ddeStringable>,
/**
* Sets `aria-*` simiraly to `dataset`
* */
ariaset: Record<string, ddeString>,
} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, ddeString>
& Record<`.${string}`, any>
type _fromElsInterfaces<EL extends SupportedElement>= Omit<EL, keyof AttrsModified>;
type IsReadonly<T, K extends keyof T> =
T extends { readonly [P in K]: T[K] } ? true : false;
/**
* Just element attributtes
*
* In most cases, you can use native propertie such as
* [MDN WEB/API/Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) and so on
* (e.g. [`Text`](https://developer.mozilla.org/en-US/docs/Web/API/Text)).
*
* There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives.
* @private
*/
type ElementAttributes<T extends SupportedElement>= Partial<{
[K in keyof _fromElsInterfaces<T>]:
_fromElsInterfaces<T>[K] extends ((...p: any[])=> any)
? _fromElsInterfaces<T>[K] | ((...p: Parameters<_fromElsInterfaces<T>[K]>)=>
ddeSignal<ReturnType<_fromElsInterfaces<T>[K]>>)
: (IsReadonly<_fromElsInterfaces<T>, K> extends false
? _fromElsInterfaces<T>[K] | ddeSignal<_fromElsInterfaces<T>[K]>
: ddeStringable)
} & AttrsModified> & Record<string, any>;
export function classListDeclarative<El extends SupportedElement>(
element: El,
classList: AttrsModified["classList"]
): El
export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El
export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(
element: El,
attr: ATT,
value: ElementAttributes<El>[ATT]
): ElementAttributes<El>[ATT]
type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap;
export namespace el {
/**
* Creates a marker comment for elements
*
* @param attrs - Marker attributes
* @param [is_open=false] - Whether the marker is open-ended
* @returns Comment node marker
*/
export function mark(
attrs: { type: "component"|"reactive"|"later", name?: string, host?: "this"|"parentElement" },
is_open?: boolean
): Comment;
}
export function el<
A extends ddeComponentAttributes,
EL extends SupportedElement | ddeDocumentFragment
>(
component: (attr: A, ...rest: any[])=> EL,
attrs?: NoInfer<A>,
...addons: ddeElementAddon<EL>[]
): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap]
? EL
: ( EL extends ddeDocumentFragment ? EL : ddeHTMLElement )
export function el<
A extends { textContent: ddeStringable },
EL extends SupportedElement | ddeDocumentFragment
>(
component: (attr: A, ...rest: any[])=> EL,
attrs?: NoInfer<A>["textContent"],
...addons: ddeElementAddon<EL>[]
): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap]
? EL
: ( EL extends ddeDocumentFragment ? EL : ddeHTMLElement )
export function el<
TAG extends keyof ExtendedHTMLElementTagNameMap,
>(
tag_name: TAG,
attrs?: ElementAttributes<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]> | ddeStringable,
...addons: ddeElementAddon<
ExtendedHTMLElementTagNameMap[NoInfer<TAG>]
>[], // TODO: for now addons must have the same element
): TAG extends keyof ddeHTMLElementTagNameMap ? ddeHTMLElementTagNameMap[TAG] : ddeHTMLElement
export function el(
tag_name?: "<>",
): ddeDocumentFragment
export function el(
tag_name: string,
attrs?: ElementAttributes<HTMLElement> | ddeStringable,
...addons: ddeElementAddon<HTMLElement>[]
): ddeHTMLElement
export { el as createElement }
export function elNS(
namespace: "http://www.w3.org/2000/svg"
): <
TAG extends keyof SVGElementTagNameMap & string,
EL extends ( TAG extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[TAG] : SVGElement ),
>(
tag_name: TAG,
attrs?: ElementAttributes<NoInfer<EL>> | ddeStringable,
...addons: ddeElementAddon<NoInfer<EL>>[]
)=> TAG extends keyof ddeSVGElementTagNameMap ? ddeSVGElementTagNameMap[TAG] : ddeSVGElement
export function elNS(
namespace: "http://www.w3.org/1998/Math/MathML"
): <
TAG extends keyof MathMLElementTagNameMap & string,
EL extends ( TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement ),
>(
tag_name: TAG,
attrs?: ddeStringable | Partial<{
[key in keyof EL]: EL[key] | ddeSignal<EL[key]> | string | number | boolean
}>,
...addons: ddeElementAddon<NoInfer<EL>>[]
)=> ddeMathMLElement
export function elNS(
namespace: string
): (
tag_name: string,
attrs?: string | ddeStringable | Record<string, any>,
...addons: ddeElementAddon<SupportedElement>[]
)=> SupportedElement
export { elNS as createElementNS }
export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
/** Simulate slots for ddeComponents */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(
root: EL,
): EL
/**
* Simulate slots in Custom Elements without using `shadowRoot`.
* @param el Custom Element root element
* @param body Body of the custom element
* */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(
el: HTMLElement,
body: EL,
): EL
export function dispatchEvent(name: keyof DocumentEventMap | string, element: SupportedElement):
(data?: any)=> void;
export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit):
(element: SupportedElement, data?: any)=> void;
export function dispatchEvent(
name: keyof DocumentEventMap | string,
options: EventInit | null,
element: SupportedElement | (()=> SupportedElement)
): (data?: any)=> void;
interface On{
/** Listens to the DOM event. See {@link Document.addEventListener} */
<
Event extends keyof DocumentEventMap,
EE extends ddeElementAddon<SupportedElement>= ddeElementAddon<HTMLElement>,
>(
type: Event,
listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any,
options?: AddEventListenerOptions
) : EE;
<
EE extends ddeElementAddon<SupportedElement>= ddeElementAddon<HTMLElement>,
>(
type: string,
listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent ) => any,
options?: AddEventListenerOptions
) : EE;
/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line
connected<
EE extends ddeElementAddon<SupportedElement>,
El extends ( EE extends ddeElementAddon<infer El> ? El : never )
>(
listener: (this: El, event: CustomEvent<El>) => any,
options?: AddEventListenerOptions
) : EE;
/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line
disconnected<
EE extends ddeElementAddon<SupportedElement>,
El extends ( EE extends ddeElementAddon<infer El> ? El : never )
>(
listener: (this: El, event: CustomEvent<void>) => any,
options?: AddEventListenerOptions
) : EE;
/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line
attributeChanged<
EE extends ddeElementAddon<SupportedElement>,
El extends ( EE extends ddeElementAddon<infer El> ? El : never )
>(
listener: (this: El, event: CustomEvent<[ string, string ]>) => any,
options?: AddEventListenerOptions
) : EE;
}
export const on: On;
type Scope= {
scope: Node | Function | Object,
host: ddeElementAddon<any>,
custom_element: false | HTMLElement,
prevent: boolean
};
/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */
export const scope: {
current: Scope,
/** Stops all automatizations. E. g. signals used as attributes in current scope
* registers removing these listeners (and clean signal if no other listeners are detected)
* on `disconnected` event. */
preventDefault<T extends boolean>(prevent: T): T,
/**
* This represents reference to the current host element `scope.host()`.
* It can be also used to register Addon(s) (functions to be called when component is initized)
* `scope.host(on.connected(console.log))`.
* */
host: (...addons: ddeElementAddon<SupportedElement>[])=> HTMLElement,
state: Scope[],
/** Adds new child scope. All attributes are inherited by default. */
push(scope?: Partial<Scope>): ReturnType<Array<Scope>["push"]>,
/** Adds root scope as a child of the current scope. */
pushRoot(): ReturnType<Array<Scope>["push"]>,
/** Removes last/current child scope. */
pop(): ReturnType<Array<Scope>["pop"]>,
};
export function customElementRender<
EL extends HTMLElement,
P extends any = Record<string, string | ddeSignal<string>>
>(
target: ShadowRoot | EL,
render: (props: P)=> SupportedElement | DocumentFragment,
props?: P | ((el: EL)=> P)
): EL
export function customElementWithDDE<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL
export function lifecyclesToEvents<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL
export function observedAttributes(custom_element: HTMLElement): Record<string, string>
/**
* This is used primarly for server side rendering. To be sure that all async operations
* are finished before the page is sent to the client.
* ```
* // on component
* function component(){
*
* queue(fetch(...).then(...));
* }
*
* // building the page
* async function build(){
* const { component }= await import("./component.js");
* document.body.append(el(component));
* await queue();
* retutn document.body.innerHTML;
* }
* ```
* */
export function queue(promise?: Promise<unknown>): Promise<unknown>;
/* TypeScript MEH */
declare global{
type ddeAppend<el>= (...nodes: (Node | string)[])=> el;
interface ddeDocumentFragment extends DocumentFragment{ append: ddeAppend<ddeDocumentFragment>; }
interface ddeHTMLElement extends HTMLElement{ append: ddeAppend<ddeHTMLElement>; }
interface ddeSVGElement extends SVGElement{ append: ddeAppend<ddeSVGElement>; }
interface ddeMathMLElement extends MathMLElement{ append: ddeAppend<ddeMathMLElement>; }
interface ddeHTMLElementTagNameMap {
"a": ddeHTMLAnchorElement;
"area": ddeHTMLAreaElement;
"audio": ddeHTMLAudioElement;
"base": ddeHTMLBaseElement;
"blockquote": ddeHTMLQuoteElement;
"body": ddeHTMLBodyElement;
"br": ddeHTMLBRElement;
"button": ddeHTMLButtonElement;
"canvas": ddeHTMLCanvasElement;
"caption": ddeHTMLTableCaptionElement;
"col": ddeHTMLTableColElement;
"colgroup": ddeHTMLTableColElement;
"data": ddeHTMLDataElement;
"datalist": ddeHTMLDataListElement;
"del": ddeHTMLModElement;
"details": ddeHTMLDetailsElement;
"dialog": ddeHTMLDialogElement;
"div": ddeHTMLDivElement;
"dl": ddeHTMLDListElement;
"embed": ddeHTMLEmbedElement;
"fieldset": ddeHTMLFieldSetElement;
"form": ddeHTMLFormElement;
"h1": ddeHTMLHeadingElement;
"h2": ddeHTMLHeadingElement;
"h3": ddeHTMLHeadingElement;
"h4": ddeHTMLHeadingElement;
"h5": ddeHTMLHeadingElement;
"h6": ddeHTMLHeadingElement;
"head": ddeHTMLHeadElement;
"hr": ddeHTMLHRElement;
"html": ddeHTMLHtmlElement;
"iframe": ddeHTMLIFrameElement;
"img": ddeHTMLImageElement;
"input": ddeHTMLInputElement;
"ins": ddeHTMLModElement;
"label": ddeHTMLLabelElement;
"legend": ddeHTMLLegendElement;
"li": ddeHTMLLIElement;
"link": ddeHTMLLinkElement;
"map": ddeHTMLMapElement;
"menu": ddeHTMLMenuElement;
"meta": ddeHTMLMetaElement;
"meter": ddeHTMLMeterElement;
"object": ddeHTMLObjectElement;
"ol": ddeHTMLOListElement;
"optgroup": ddeHTMLOptGroupElement;
"option": ddeHTMLOptionElement;
"output": ddeHTMLOutputElement;
"p": ddeHTMLParagraphElement;
"picture": ddeHTMLPictureElement;
"pre": ddeHTMLPreElement;
"progress": ddeHTMLProgressElement;
"q": ddeHTMLQuoteElement;
"script": ddeHTMLScriptElement;
"select": ddeHTMLSelectElement;
"slot": ddeHTMLSlotElement;
"source": ddeHTMLSourceElement;
"span": ddeHTMLSpanElement;
"style": ddeHTMLStyleElement;
"table": ddeHTMLTableElement;
"tbody": ddeHTMLTableSectionElement;
"td": ddeHTMLTableCellElement;
"template": ddeHTMLTemplateElement;
"textarea": ddeHTMLTextAreaElement;
"tfoot": ddeHTMLTableSectionElement;
"th": ddeHTMLTableCellElement;
"thead": ddeHTMLTableSectionElement;
"time": ddeHTMLTimeElement;
"title": ddeHTMLTitleElement;
"tr": ddeHTMLTableRowElement;
"track": ddeHTMLTrackElement;
"ul": ddeHTMLUListElement;
"video": ddeHTMLVideoElement;
}
interface ddeSVGElementTagNameMap {
"a": ddeSVGAElement;
"animate": ddeSVGAnimateElement;
"animateMotion": ddeSVGAnimateMotionElement;
"animateTransform": ddeSVGAnimateTransformElement;
"circle": ddeSVGCircleElement;
"clipPath": ddeSVGClipPathElement;
"defs": ddeSVGDefsElement;
"desc": ddeSVGDescElement;
"ellipse": ddeSVGEllipseElement;
"feBlend": ddeSVGFEBlendElement;
"feColorMatrix": ddeSVGFEColorMatrixElement;
"feComponentTransfer": ddeSVGFEComponentTransferElement;
"feComposite": ddeSVGFECompositeElement;
"feConvolveMatrix": ddeSVGFEConvolveMatrixElement;
"feDiffuseLighting": ddeSVGFEDiffuseLightingElement;
"feDisplacementMap": ddeSVGFEDisplacementMapElement;
"feDistantLight": ddeSVGFEDistantLightElement;
"feDropShadow": ddeSVGFEDropShadowElement;
"feFlood": ddeSVGFEFloodElement;
"feFuncA": ddeSVGFEFuncAElement;
"feFuncB": ddeSVGFEFuncBElement;
"feFuncG": ddeSVGFEFuncGElement;
"feFuncR": ddeSVGFEFuncRElement;
"feGaussianBlur": ddeSVGFEGaussianBlurElement;
"feImage": ddeSVGFEImageElement;
"feMerge": ddeSVGFEMergeElement;
"feMergeNode": ddeSVGFEMergeNodeElement;
"feMorphology": ddeSVGFEMorphologyElement;
"feOffset": ddeSVGFEOffsetElement;
"fePointLight": ddeSVGFEPointLightElement;
"feSpecularLighting": ddeSVGFESpecularLightingElement;
"feSpotLight": ddeSVGFESpotLightElement;
"feTile": ddeSVGFETileElement;
"feTurbulence": ddeSVGFETurbulenceElement;
"filter": ddeSVGFilterElement;
"foreignObject": ddeSVGForeignObjectElement;
"g": ddeSVGGElement;
"image": ddeSVGImageElement;
"line": ddeSVGLineElement;
"linearGradient": ddeSVGLinearGradientElement;
"marker": ddeSVGMarkerElement;
"mask": ddeSVGMaskElement;
"metadata": ddeSVGMetadataElement;
"mpath": ddeSVGMPathElement;
"path": ddeSVGPathElement;
"pattern": ddeSVGPatternElement;
"polygon": ddeSVGPolygonElement;
"polyline": ddeSVGPolylineElement;
"radialGradient": ddeSVGRadialGradientElement;
"rect": ddeSVGRectElement;
"script": ddeSVGScriptElement;
"set": ddeSVGSetElement;
"stop": ddeSVGStopElement;
"style": ddeSVGStyleElement;
"svg": ddeSVGSVGElement;
"switch": ddeSVGSwitchElement;
"symbol": ddeSVGSymbolElement;
"text": ddeSVGTextElement;
"textPath": ddeSVGTextPathElement;
"title": ddeSVGTitleElement;
"tspan": ddeSVGTSpanElement;
"use": ddeSVGUseElement;
"view": ddeSVGViewElement;
}
}
// editorconfig-checker-disable
interface ddeHTMLAnchorElement extends HTMLAnchorElement{ append: ddeAppend<ddeHTMLAnchorElement>; }
interface ddeHTMLAreaElement extends HTMLAreaElement{ append: ddeAppend<ddeHTMLAreaElement>; }
interface ddeHTMLAudioElement extends HTMLAudioElement{ append: ddeAppend<ddeHTMLAudioElement>; }
interface ddeHTMLBaseElement extends HTMLBaseElement{ append: ddeAppend<ddeHTMLBaseElement>; }
interface ddeHTMLQuoteElement extends HTMLQuoteElement{ append: ddeAppend<ddeHTMLQuoteElement>; }
interface ddeHTMLBodyElement extends HTMLBodyElement{ append: ddeAppend<ddeHTMLBodyElement>; }
interface ddeHTMLBRElement extends HTMLBRElement{ append: ddeAppend<ddeHTMLBRElement>; }
interface ddeHTMLButtonElement extends HTMLButtonElement{ append: ddeAppend<ddeHTMLButtonElement>; }
interface ddeHTMLCanvasElement extends HTMLCanvasElement{ append: ddeAppend<ddeHTMLCanvasElement>; }
interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement{ append: ddeAppend<ddeHTMLTableCaptionElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLDataElement extends HTMLDataElement{ append: ddeAppend<ddeHTMLDataElement>; }
interface ddeHTMLDataListElement extends HTMLDataListElement{ append: ddeAppend<ddeHTMLDataListElement>; }
interface ddeHTMLModElement extends HTMLModElement{ append: ddeAppend<ddeHTMLModElement>; }
interface ddeHTMLDetailsElement extends HTMLDetailsElement{ append: ddeAppend<ddeHTMLDetailsElement>; }
interface ddeHTMLDialogElement extends HTMLDialogElement{ append: ddeAppend<ddeHTMLDialogElement>; }
interface ddeHTMLDivElement extends HTMLDivElement{ append: ddeAppend<ddeHTMLDivElement>; }
interface ddeHTMLDListElement extends HTMLDListElement{ append: ddeAppend<ddeHTMLDListElement>; }
interface ddeHTMLEmbedElement extends HTMLEmbedElement{ append: ddeAppend<ddeHTMLEmbedElement>; }
interface ddeHTMLFieldSetElement extends HTMLFieldSetElement{ append: ddeAppend<ddeHTMLFieldSetElement>; }
interface ddeHTMLFormElement extends HTMLFormElement{ append: ddeAppend<ddeHTMLFormElement>; }
interface ddeHTMLHeadingElement extends HTMLHeadingElement{ append: ddeAppend<ddeHTMLHeadingElement>; }
interface ddeHTMLHeadElement extends HTMLHeadElement{ append: ddeAppend<ddeHTMLHeadElement>; }
interface ddeHTMLHRElement extends HTMLHRElement{ append: ddeAppend<ddeHTMLHRElement>; }
interface ddeHTMLHtmlElement extends HTMLHtmlElement{ append: ddeAppend<ddeHTMLHtmlElement>; }
interface ddeHTMLIFrameElement extends HTMLIFrameElement{ append: ddeAppend<ddeHTMLIFrameElement>; }
interface ddeHTMLImageElement extends HTMLImageElement{ append: ddeAppend<ddeHTMLImageElement>; }
interface ddeHTMLInputElement extends HTMLInputElement{ append: ddeAppend<ddeHTMLInputElement>; }
interface ddeHTMLLabelElement extends HTMLLabelElement{ append: ddeAppend<ddeHTMLLabelElement>; }
interface ddeHTMLLegendElement extends HTMLLegendElement{ append: ddeAppend<ddeHTMLLegendElement>; }
interface ddeHTMLLIElement extends HTMLLIElement{ append: ddeAppend<ddeHTMLLIElement>; }
interface ddeHTMLLinkElement extends HTMLLinkElement{ append: ddeAppend<ddeHTMLLinkElement>; }
interface ddeHTMLMapElement extends HTMLMapElement{ append: ddeAppend<ddeHTMLMapElement>; }
interface ddeHTMLMenuElement extends HTMLMenuElement{ append: ddeAppend<ddeHTMLMenuElement>; }
interface ddeHTMLMetaElement extends HTMLMetaElement{ append: ddeAppend<ddeHTMLMetaElement>; }
interface ddeHTMLMeterElement extends HTMLMeterElement{ append: ddeAppend<ddeHTMLMeterElement>; }
interface ddeHTMLObjectElement extends HTMLObjectElement{ append: ddeAppend<ddeHTMLObjectElement>; }
interface ddeHTMLOListElement extends HTMLOListElement{ append: ddeAppend<ddeHTMLOListElement>; }
interface ddeHTMLOptGroupElement extends HTMLOptGroupElement{ append: ddeAppend<ddeHTMLOptGroupElement>; }
interface ddeHTMLOptionElement extends HTMLOptionElement{ append: ddeAppend<ddeHTMLOptionElement>; }
interface ddeHTMLOutputElement extends HTMLOutputElement{ append: ddeAppend<ddeHTMLOutputElement>; }
interface ddeHTMLParagraphElement extends HTMLParagraphElement{ append: ddeAppend<ddeHTMLParagraphElement>; }
interface ddeHTMLPictureElement extends HTMLPictureElement{ append: ddeAppend<ddeHTMLPictureElement>; }
interface ddeHTMLPreElement extends HTMLPreElement{ append: ddeAppend<ddeHTMLPreElement>; }
interface ddeHTMLProgressElement extends HTMLProgressElement{ append: ddeAppend<ddeHTMLProgressElement>; }
interface ddeHTMLScriptElement extends HTMLScriptElement{ append: ddeAppend<ddeHTMLScriptElement>; }
interface ddeHTMLSelectElement extends HTMLSelectElement{ append: ddeAppend<ddeHTMLSelectElement>; }
interface ddeHTMLSlotElement extends HTMLSlotElement{ append: ddeAppend<ddeHTMLSlotElement>; }
interface ddeHTMLSourceElement extends HTMLSourceElement{ append: ddeAppend<ddeHTMLSourceElement>; }
interface ddeHTMLSpanElement extends HTMLSpanElement{ append: ddeAppend<ddeHTMLSpanElement>; }
interface ddeHTMLStyleElement extends HTMLStyleElement{ append: ddeAppend<ddeHTMLStyleElement>; }
interface ddeHTMLTableElement extends HTMLTableElement{ append: ddeAppend<ddeHTMLTableElement>; }
interface ddeHTMLTableSectionElement extends HTMLTableSectionElement{ append: ddeAppend<ddeHTMLTableSectionElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTemplateElement extends HTMLTemplateElement{ append: ddeAppend<ddeHTMLTemplateElement>; }
interface ddeHTMLTextAreaElement extends HTMLTextAreaElement{ append: ddeAppend<ddeHTMLTextAreaElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTimeElement extends HTMLTimeElement{ append: ddeAppend<ddeHTMLTimeElement>; }
interface ddeHTMLTitleElement extends HTMLTitleElement{ append: ddeAppend<ddeHTMLTitleElement>; }
interface ddeHTMLTableRowElement extends HTMLTableRowElement{ append: ddeAppend<ddeHTMLTableRowElement>; }
interface ddeHTMLTrackElement extends HTMLTrackElement{ append: ddeAppend<ddeHTMLTrackElement>; }
interface ddeHTMLUListElement extends HTMLUListElement{ append: ddeAppend<ddeHTMLUListElement>; }
interface ddeHTMLVideoElement extends HTMLVideoElement{ append: ddeAppend<ddeHTMLVideoElement>; }
interface ddeSVGAElement extends SVGAElement{ append: ddeAppend<ddeSVGAElement>; }
interface ddeSVGAnimateElement extends SVGAnimateElement{ append: ddeAppend<ddeSVGAnimateElement>; }
interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement{ append: ddeAppend<ddeSVGAnimateMotionElement>; }
interface ddeSVGAnimateTransformElement extends SVGAnimateTransformElement{ append: ddeAppend<ddeSVGAnimateTransformElement>; }
interface ddeSVGCircleElement extends SVGCircleElement{ append: ddeAppend<ddeSVGCircleElement>; }
interface ddeSVGClipPathElement extends SVGClipPathElement{ append: ddeAppend<ddeSVGClipPathElement>; }
interface ddeSVGDefsElement extends SVGDefsElement{ append: ddeAppend<ddeSVGDefsElement>; }
interface ddeSVGDescElement extends SVGDescElement{ append: ddeAppend<ddeSVGDescElement>; }
interface ddeSVGEllipseElement extends SVGEllipseElement{ append: ddeAppend<ddeSVGEllipseElement>; }
interface ddeSVGFEBlendElement extends SVGFEBlendElement{ append: ddeAppend<ddeSVGFEBlendElement>; }
interface ddeSVGFEColorMatrixElement extends SVGFEColorMatrixElement{ append: ddeAppend<ddeSVGFEColorMatrixElement>; }
interface ddeSVGFEComponentTransferElement extends SVGFEComponentTransferElement{ append: ddeAppend<ddeSVGFEComponentTransferElement>; }
interface ddeSVGFECompositeElement extends SVGFECompositeElement{ append: ddeAppend<ddeSVGFECompositeElement>; }
interface ddeSVGFEConvolveMatrixElement extends SVGFEConvolveMatrixElement{ append: ddeAppend<ddeSVGFEConvolveMatrixElement>; }
interface ddeSVGFEDiffuseLightingElement extends SVGFEDiffuseLightingElement{ append: ddeAppend<ddeSVGFEDiffuseLightingElement>; }
interface ddeSVGFEDisplacementMapElement extends SVGFEDisplacementMapElement{ append: ddeAppend<ddeSVGFEDisplacementMapElement>; }
interface ddeSVGFEDistantLightElement extends SVGFEDistantLightElement{ append: ddeAppend<ddeSVGFEDistantLightElement>; }
interface ddeSVGFEDropShadowElement extends SVGFEDropShadowElement{ append: ddeAppend<ddeSVGFEDropShadowElement>; }
interface ddeSVGFEFloodElement extends SVGFEFloodElement{ append: ddeAppend<ddeSVGFEFloodElement>; }
interface ddeSVGFEFuncAElement extends SVGFEFuncAElement{ append: ddeAppend<ddeSVGFEFuncAElement>; }
interface ddeSVGFEFuncBElement extends SVGFEFuncBElement{ append: ddeAppend<ddeSVGFEFuncBElement>; }
interface ddeSVGFEFuncGElement extends SVGFEFuncGElement{ append: ddeAppend<ddeSVGFEFuncGElement>; }
interface ddeSVGFEFuncRElement extends SVGFEFuncRElement{ append: ddeAppend<ddeSVGFEFuncRElement>; }
interface ddeSVGFEGaussianBlurElement extends SVGFEGaussianBlurElement{ append: ddeAppend<ddeSVGFEGaussianBlurElement>; }
interface ddeSVGFEImageElement extends SVGFEImageElement{ append: ddeAppend<ddeSVGFEImageElement>; }
interface ddeSVGFEMergeElement extends SVGFEMergeElement{ append: ddeAppend<ddeSVGFEMergeElement>; }
interface ddeSVGFEMergeNodeElement extends SVGFEMergeNodeElement{ append: ddeAppend<ddeSVGFEMergeNodeElement>; }
interface ddeSVGFEMorphologyElement extends SVGFEMorphologyElement{ append: ddeAppend<ddeSVGFEMorphologyElement>; }
interface ddeSVGFEOffsetElement extends SVGFEOffsetElement{ append: ddeAppend<ddeSVGFEOffsetElement>; }
interface ddeSVGFEPointLightElement extends SVGFEPointLightElement{ append: ddeAppend<ddeSVGFEPointLightElement>; }
interface ddeSVGFESpecularLightingElement extends SVGFESpecularLightingElement{ append: ddeAppend<ddeSVGFESpecularLightingElement>; }
interface ddeSVGFESpotLightElement extends SVGFESpotLightElement{ append: ddeAppend<ddeSVGFESpotLightElement>; }
interface ddeSVGFETileElement extends SVGFETileElement{ append: ddeAppend<ddeSVGFETileElement>; }
interface ddeSVGFETurbulenceElement extends SVGFETurbulenceElement{ append: ddeAppend<ddeSVGFETurbulenceElement>; }
interface ddeSVGFilterElement extends SVGFilterElement{ append: ddeAppend<ddeSVGFilterElement>; }
interface ddeSVGForeignObjectElement extends SVGForeignObjectElement{ append: ddeAppend<ddeSVGForeignObjectElement>; }
interface ddeSVGGElement extends SVGGElement{ append: ddeAppend<ddeSVGGElement>; }
interface ddeSVGImageElement extends SVGImageElement{ append: ddeAppend<ddeSVGImageElement>; }
interface ddeSVGLineElement extends SVGLineElement{ append: ddeAppend<ddeSVGLineElement>; }
interface ddeSVGLinearGradientElement extends SVGLinearGradientElement{ append: ddeAppend<ddeSVGLinearGradientElement>; }
interface ddeSVGMarkerElement extends SVGMarkerElement{ append: ddeAppend<ddeSVGMarkerElement>; }
interface ddeSVGMaskElement extends SVGMaskElement{ append: ddeAppend<ddeSVGMaskElement>; }
interface ddeSVGMetadataElement extends SVGMetadataElement{ append: ddeAppend<ddeSVGMetadataElement>; }
interface ddeSVGMPathElement extends SVGMPathElement{ append: ddeAppend<ddeSVGMPathElement>; }
interface ddeSVGPathElement extends SVGPathElement{ append: ddeAppend<ddeSVGPathElement>; }
interface ddeSVGPatternElement extends SVGPatternElement{ append: ddeAppend<ddeSVGPatternElement>; }
interface ddeSVGPolygonElement extends SVGPolygonElement{ append: ddeAppend<ddeSVGPolygonElement>; }
interface ddeSVGPolylineElement extends SVGPolylineElement{ append: ddeAppend<ddeSVGPolylineElement>; }
interface ddeSVGRadialGradientElement extends SVGRadialGradientElement{ append: ddeAppend<ddeSVGRadialGradientElement>; }
interface ddeSVGRectElement extends SVGRectElement{ append: ddeAppend<ddeSVGRectElement>; }
interface ddeSVGScriptElement extends SVGScriptElement{ append: ddeAppend<ddeSVGScriptElement>; }
interface ddeSVGSetElement extends SVGSetElement{ append: ddeAppend<ddeSVGSetElement>; }
interface ddeSVGStopElement extends SVGStopElement{ append: ddeAppend<ddeSVGStopElement>; }
interface ddeSVGStyleElement extends SVGStyleElement{ append: ddeAppend<ddeSVGStyleElement>; }
interface ddeSVGSVGElement extends SVGSVGElement{ append: ddeAppend<ddeSVGSVGElement>; }
interface ddeSVGSwitchElement extends SVGSwitchElement{ append: ddeAppend<ddeSVGSwitchElement>; }
interface ddeSVGSymbolElement extends SVGSymbolElement{ append: ddeAppend<ddeSVGSymbolElement>; }
interface ddeSVGTextElement extends SVGTextElement{ append: ddeAppend<ddeSVGTextElement>; }
interface ddeSVGTextPathElement extends SVGTextPathElement{ append: ddeAppend<ddeSVGTextPathElement>; }
interface ddeSVGTitleElement extends SVGTitleElement{ append: ddeAppend<ddeSVGTitleElement>; }
interface ddeSVGTSpanElement extends SVGTSpanElement{ append: ddeAppend<ddeSVGTSpanElement>; }
interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend<ddeSVGUseElement>; }
interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend<ddeSVGViewElement>; }
// editorconfig-checker-enable
export interface Signal<V, A> {
/** The current value of the signal */
get(): V;
/** Set new value of the signal */
set(value: V): V;
toJSON(): V;
valueOf(): V;
}
type Action<V>= (this: { value: V, stopPropagation(): void }, ...a: any[])=> typeof signal._ | void;
//type SymbolSignal= Symbol;
type SymbolOnclear= symbol;
type Actions<V>= Record<string | SymbolOnclear, Action<V>>;
type OnListenerOptions= Pick<AddEventListenerOptions, "signal"> & { first_time?: boolean };
interface signal{
_: Symbol
/**
* Computations signal. This creates a signal which is computed from other signals.
* */
<V extends ()=> any>(computation: V): Signal<ReturnType<V>, {}>
/**
* Simple example:
* ```js
* const hello= S("Hello Signal");
* ```
* simple todo signal:
* ```js
* const todos= S([], {
* add(v){ this.value.push(S(v)); },
* remove(i){ this.value.splice(i, 1); },
* [S.symbols.onclear](){ S.clear(...this.value); },
* });
* ```
* computed signal:
* ```js
* const name= S("Jan");
* const surname= S("Andrle");
* const fullname= S(()=> name.get()+" "+surname.get());
* ```
* @param value Initial signal value. Or function computing value from other signals.
* @param actions Use to define actions on the signal. Such as add item to the array.
* There is also a reserved function `S.symbol.onclear` which is called when the signal is cleared
* by `S.clear`.
* */
<V, A extends Actions<V>>(value: V, actions?: A): Signal<V, A>;
action<S extends Signal<any, Actions<any>>, A extends (S extends Signal<any, infer A> ? A : never), N extends keyof A>(
signal: S,
name: N,
...params: A[N] extends (...args: infer P)=> any ? P : never
): void;
clear(...signals: Signal<any, any>[]): void;
on<T>(signal: Signal<T, any>, onchange: (a: T)=> void, options?: OnListenerOptions): void;
symbols: {
//signal: SymbolSignal;
onclear: SymbolOnclear;
}
/**
* Reactive element, which is rendered based on the given signal.
* ```js
* S.el(signal, value=> value ? el("b", "True") : el("i", "False"));
* S.el(listS, list=> list.map(li=> el("li", li)));
* ```
* */
el<S extends any>(signal: Signal<S, any>, el: (v: S)=> Element | Element[] | DocumentFragment): DocumentFragment;
observedAttributes(custom_element: HTMLElement): Record<string, Signal<string, {}>>;
}
export const signal: signal;
export const S: signal;
declare global {
type ddeSignal<T, A= {}>= Signal<T, A>;
type ddeAction<V>= Action<V>
type ddeActions<V>= Actions<V>
}

File diff suppressed because it is too large Load Diff

1320
dist/esm-with-signals.js vendored

File diff suppressed because it is too large Load Diff

783
dist/esm-with-signals.min.d.ts vendored Normal file
View File

@ -0,0 +1,783 @@
// Generated by dts-bundle-generator v9.5.1
export interface Signal<V, A> {
/** The current value of the signal */
get(): V;
/** Set new value of the signal */
set(value: V): V;
toJSON(): V;
valueOf(): V;
}
export type Action<V> = (this: {
value: V;
stopPropagation(): void;
}, ...a: any[]) => typeof signal._ | void;
//type SymbolSignal= Symbol;
export type SymbolOnclear = symbol;
export type Actions<V> = Record<string | SymbolOnclear, Action<V>>;
export type OnListenerOptions = Pick<AddEventListenerOptions, "signal"> & {
first_time?: boolean;
};
export interface signal {
_: Symbol;
/**
* Computations signal. This creates a signal which is computed from other signals.
* */
<V extends () => any>(computation: V): Signal<ReturnType<V>, {}>;
/**
* Simple example:
* ```js
* const hello= S("Hello Signal");
* ```
* simple todo signal:
* ```js
* const todos= S([], {
* add(v){ this.value.push(S(v)); },
* remove(i){ this.value.splice(i, 1); },
* [S.symbols.onclear](){ S.clear(...this.value); },
* });
* ```
* computed signal:
* ```js
* const name= S("Jan");
* const surname= S("Andrle");
* const fullname= S(()=> name.get()+" "+surname.get());
* ```
* @param value Initial signal value. Or function computing value from other signals.
* @param actions Use to define actions on the signal. Such as add item to the array.
* There is also a reserved function `S.symbol.onclear` which is called when the signal is cleared
* by `S.clear`.
* */
<V, A extends Actions<V>>(value: V, actions?: A): Signal<V, A>;
action<S extends Signal<any, Actions<any>>, A extends (S extends Signal<any, infer A> ? A : never), N extends keyof A>(signal: S, name: N, ...params: A[N] extends (...args: infer P) => any ? P : never): void;
clear(...signals: Signal<any, any>[]): void;
on<T>(signal: Signal<T, any>, onchange: (a: T) => void, options?: OnListenerOptions): void;
symbols: {
//signal: SymbolSignal;
onclear: SymbolOnclear;
};
/**
* Reactive element, which is rendered based on the given signal.
* ```js
* S.el(signal, value=> value ? el("b", "True") : el("i", "False"));
* S.el(listS, list=> list.map(li=> el("li", li)));
* ```
* */
el<S extends any>(signal: Signal<S, any>, el: (v: S) => Element | Element[] | DocumentFragment): DocumentFragment;
observedAttributes(custom_element: HTMLElement): Record<string, Signal<string, {}>>;
}
export const signal: signal;
export const S: signal;
declare global {
type ddeSignal<T, A = {}> = Signal<T, A>;
type ddeAction<V> = Action<V>;
type ddeActions<V> = Actions<V>;
}
export type CustomElementTagNameMap = {
"#text": Text;
"#comment": Comment;
};
export type SupportedElement = HTMLElementTagNameMap[keyof HTMLElementTagNameMap] | SVGElementTagNameMap[keyof SVGElementTagNameMap] | MathMLElementTagNameMap[keyof MathMLElementTagNameMap] | CustomElementTagNameMap[keyof CustomElementTagNameMap];
declare global {
type ddeComponentAttributes = Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment | Node> = (element: El) => any;
type ddeString = string | Signal<string, {}>;
type ddeStringable = ddeString | number | Signal<number, {}>;
}
export type PascalCase = `${Capitalize<string>}${string}`;
export type AttrsModified = {
/**
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/
style: Partial<CSSStyleDeclaration> | ddeString | Partial<{
[K in keyof CSSStyleDeclaration]: Signal<CSSStyleDeclaration[K], {}>;
}>;
/**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1.
* In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))`
* for others.
*/
classList: Record<string, -1 | 0 | 1 | boolean | Signal<-1 | 0 | 1 | boolean, {}>>;
/**
* Used by the dataset HTML attribute to represent data for custom attributes added to elements.
* Values are converted to string (see {@link DOMStringMap}).
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMStringMap)
* */
dataset: Record<string, ddeStringable>;
/**
* Sets `aria-*` simiraly to `dataset`
* */
ariaset: Record<string, ddeString>;
} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, ddeString> & Record<`.${string}`, any>;
export type _fromElsInterfaces<EL extends SupportedElement> = Omit<EL, keyof AttrsModified>;
export type IsReadonly<T, K extends keyof T> = T extends {
readonly [P in K]: T[K];
} ? true : false;
/**
* Just element attributtes
*
* In most cases, you can use native propertie such as
* [MDN WEB/API/Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) and so on
* (e.g. [`Text`](https://developer.mozilla.org/en-US/docs/Web/API/Text)).
*
* There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives.
* @private
*/
export type ElementAttributes<T extends SupportedElement> = Partial<{
[K in keyof _fromElsInterfaces<T>]: _fromElsInterfaces<T>[K] extends ((...p: any[]) => any) ? _fromElsInterfaces<T>[K] | ((...p: Parameters<_fromElsInterfaces<T>[K]>) => Signal<ReturnType<_fromElsInterfaces<T>[K]>, {}>) : (IsReadonly<_fromElsInterfaces<T>, K> extends false ? _fromElsInterfaces<T>[K] | Signal<_fromElsInterfaces<T>[K], {}> : ddeStringable);
} & AttrsModified> & Record<string, any>;
export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El;
export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El;
export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT];
export type ExtendedHTMLElementTagNameMap = HTMLElementTagNameMap & CustomElementTagNameMap;
export namespace el {
/**
* Creates a marker comment for elements
*
* @param attrs - Marker attributes
* @param [is_open=false] - Whether the marker is open-ended
* @returns Comment node marker
*/
export function mark(attrs: {
type: "component" | "reactive" | "later";
name?: string;
host?: "this" | "parentElement";
}, is_open?: boolean): Comment;
}
export function el<A extends ddeComponentAttributes, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>, ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
export function el<A extends {
textContent: ddeStringable;
}, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>["textContent"], ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
export function el<TAG extends keyof ExtendedHTMLElementTagNameMap>(tag_name: TAG, attrs?: ElementAttributes<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]> | ddeStringable, ...addons: ddeElementAddon<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]>[]): TAG extends keyof ddeHTMLElementTagNameMap ? ddeHTMLElementTagNameMap[TAG] : ddeHTMLElement;
export function el(tag_name?: "<>"): ddeDocumentFragment;
export function el(tag_name: string, attrs?: ElementAttributes<HTMLElement> | ddeStringable, ...addons: ddeElementAddon<HTMLElement>[]): ddeHTMLElement;
export function elNS(namespace: "http://www.w3.org/2000/svg"): <TAG extends keyof SVGElementTagNameMap & string, EL extends (TAG extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[TAG] : SVGElement)>(tag_name: TAG, attrs?: ElementAttributes<NoInfer<EL>> | ddeStringable, ...addons: ddeElementAddon<NoInfer<EL>>[]) => TAG extends keyof ddeSVGElementTagNameMap ? ddeSVGElementTagNameMap[TAG] : ddeSVGElement;
export function elNS(namespace: "http://www.w3.org/1998/Math/MathML"): <TAG extends keyof MathMLElementTagNameMap & string, EL extends (TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement)>(tag_name: TAG, attrs?: ddeStringable | Partial<{
[key in keyof EL]: EL[key] | Signal<EL[key], {}> | string | number | boolean;
}>, ...addons: ddeElementAddon<NoInfer<EL>>[]) => ddeMathMLElement;
export function elNS(namespace: string): (tag_name: string, attrs?: string | ddeStringable | Record<string, any>, ...addons: ddeElementAddon<SupportedElement>[]) => SupportedElement;
export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
/** Simulate slots for ddeComponents */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(root: EL): EL;
/**
* Simulate slots in Custom Elements without using `shadowRoot`.
* @param el Custom Element root element
* @param body Body of the custom element
* */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: HTMLElement, body: EL): EL;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, element: SupportedElement): (data?: any) => void;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options?: EventInit): (element: SupportedElement, data?: any) => void;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, element: SupportedElement | (() => SupportedElement)): (data?: any) => void;
export interface On {
/** Listens to the DOM event. See {@link Document.addEventListener} */
<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE;
<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[
string,
string
]>) => any, options?: AddEventListenerOptions): EE;
}
export const on: On;
export type Scope = {
scope: Node | Function | Object;
host: ddeElementAddon<any>;
custom_element: false | HTMLElement;
prevent: boolean;
};
/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */
export const scope: {
current: Scope;
/** Stops all automatizations. E. g. signals used as attributes in current scope
* registers removing these listeners (and clean signal if no other listeners are detected)
* on `disconnected` event. */
preventDefault<T extends boolean>(prevent: T): T;
/**
* This represents reference to the current host element `scope.host()`.
* It can be also used to register Addon(s) (functions to be called when component is initized)
* `scope.host(on.connected(console.log))`.
* */
host: (...addons: ddeElementAddon<SupportedElement>[]) => HTMLElement;
state: Scope[];
/** Adds new child scope. All attributes are inherited by default. */
push(scope?: Partial<Scope>): ReturnType<Array<Scope>["push"]>;
/** Adds root scope as a child of the current scope. */
pushRoot(): ReturnType<Array<Scope>["push"]>;
/** Removes last/current child scope. */
pop(): ReturnType<Array<Scope>["pop"]>;
};
export function customElementRender<EL extends HTMLElement, P extends any = Record<string, string | Signal<string, {}>>>(target: ShadowRoot | EL, render: (props: P) => SupportedElement | DocumentFragment, props?: P | ((el: EL) => P)): EL;
export function customElementWithDDE<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
export function lifecyclesToEvents<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
export function observedAttributes(custom_element: HTMLElement): Record<string, string>;
/**
* This is used primarly for server side rendering. To be sure that all async operations
* are finished before the page is sent to the client.
* ```
* // on component
* function component(){
*
* queue(fetch(...).then(...));
* }
*
* // building the page
* async function build(){
* const { component }= await import("./component.js");
* document.body.append(el(component));
* await queue();
* retutn document.body.innerHTML;
* }
* ```
* */
export function queue(promise?: Promise<unknown>): Promise<unknown>;
/* TypeScript MEH */
declare global {
type ddeAppend<el> = (...nodes: (Node | string)[]) => el;
interface ddeDocumentFragment extends DocumentFragment {
append: ddeAppend<ddeDocumentFragment>;
}
interface ddeHTMLElement extends HTMLElement {
append: ddeAppend<ddeHTMLElement>;
}
interface ddeSVGElement extends SVGElement {
append: ddeAppend<ddeSVGElement>;
}
interface ddeMathMLElement extends MathMLElement {
append: ddeAppend<ddeMathMLElement>;
}
interface ddeHTMLElementTagNameMap {
"a": ddeHTMLAnchorElement;
"area": ddeHTMLAreaElement;
"audio": ddeHTMLAudioElement;
"base": ddeHTMLBaseElement;
"blockquote": ddeHTMLQuoteElement;
"body": ddeHTMLBodyElement;
"br": ddeHTMLBRElement;
"button": ddeHTMLButtonElement;
"canvas": ddeHTMLCanvasElement;
"caption": ddeHTMLTableCaptionElement;
"col": ddeHTMLTableColElement;
"colgroup": ddeHTMLTableColElement;
"data": ddeHTMLDataElement;
"datalist": ddeHTMLDataListElement;
"del": ddeHTMLModElement;
"details": ddeHTMLDetailsElement;
"dialog": ddeHTMLDialogElement;
"div": ddeHTMLDivElement;
"dl": ddeHTMLDListElement;
"embed": ddeHTMLEmbedElement;
"fieldset": ddeHTMLFieldSetElement;
"form": ddeHTMLFormElement;
"h1": ddeHTMLHeadingElement;
"h2": ddeHTMLHeadingElement;
"h3": ddeHTMLHeadingElement;
"h4": ddeHTMLHeadingElement;
"h5": ddeHTMLHeadingElement;
"h6": ddeHTMLHeadingElement;
"head": ddeHTMLHeadElement;
"hr": ddeHTMLHRElement;
"html": ddeHTMLHtmlElement;
"iframe": ddeHTMLIFrameElement;
"img": ddeHTMLImageElement;
"input": ddeHTMLInputElement;
"ins": ddeHTMLModElement;
"label": ddeHTMLLabelElement;
"legend": ddeHTMLLegendElement;
"li": ddeHTMLLIElement;
"link": ddeHTMLLinkElement;
"map": ddeHTMLMapElement;
"menu": ddeHTMLMenuElement;
"meta": ddeHTMLMetaElement;
"meter": ddeHTMLMeterElement;
"object": ddeHTMLObjectElement;
"ol": ddeHTMLOListElement;
"optgroup": ddeHTMLOptGroupElement;
"option": ddeHTMLOptionElement;
"output": ddeHTMLOutputElement;
"p": ddeHTMLParagraphElement;
"picture": ddeHTMLPictureElement;
"pre": ddeHTMLPreElement;
"progress": ddeHTMLProgressElement;
"q": ddeHTMLQuoteElement;
"script": ddeHTMLScriptElement;
"select": ddeHTMLSelectElement;
"slot": ddeHTMLSlotElement;
"source": ddeHTMLSourceElement;
"span": ddeHTMLSpanElement;
"style": ddeHTMLStyleElement;
"table": ddeHTMLTableElement;
"tbody": ddeHTMLTableSectionElement;
"td": ddeHTMLTableCellElement;
"template": ddeHTMLTemplateElement;
"textarea": ddeHTMLTextAreaElement;
"tfoot": ddeHTMLTableSectionElement;
"th": ddeHTMLTableCellElement;
"thead": ddeHTMLTableSectionElement;
"time": ddeHTMLTimeElement;
"title": ddeHTMLTitleElement;
"tr": ddeHTMLTableRowElement;
"track": ddeHTMLTrackElement;
"ul": ddeHTMLUListElement;
"video": ddeHTMLVideoElement;
}
interface ddeSVGElementTagNameMap {
"a": ddeSVGAElement;
"animate": ddeSVGAnimateElement;
"animateMotion": ddeSVGAnimateMotionElement;
"animateTransform": ddeSVGAnimateTransformElement;
"circle": ddeSVGCircleElement;
"clipPath": ddeSVGClipPathElement;
"defs": ddeSVGDefsElement;
"desc": ddeSVGDescElement;
"ellipse": ddeSVGEllipseElement;
"feBlend": ddeSVGFEBlendElement;
"feColorMatrix": ddeSVGFEColorMatrixElement;
"feComponentTransfer": ddeSVGFEComponentTransferElement;
"feComposite": ddeSVGFECompositeElement;
"feConvolveMatrix": ddeSVGFEConvolveMatrixElement;
"feDiffuseLighting": ddeSVGFEDiffuseLightingElement;
"feDisplacementMap": ddeSVGFEDisplacementMapElement;
"feDistantLight": ddeSVGFEDistantLightElement;
"feDropShadow": ddeSVGFEDropShadowElement;
"feFlood": ddeSVGFEFloodElement;
"feFuncA": ddeSVGFEFuncAElement;
"feFuncB": ddeSVGFEFuncBElement;
"feFuncG": ddeSVGFEFuncGElement;
"feFuncR": ddeSVGFEFuncRElement;
"feGaussianBlur": ddeSVGFEGaussianBlurElement;
"feImage": ddeSVGFEImageElement;
"feMerge": ddeSVGFEMergeElement;
"feMergeNode": ddeSVGFEMergeNodeElement;
"feMorphology": ddeSVGFEMorphologyElement;
"feOffset": ddeSVGFEOffsetElement;
"fePointLight": ddeSVGFEPointLightElement;
"feSpecularLighting": ddeSVGFESpecularLightingElement;
"feSpotLight": ddeSVGFESpotLightElement;
"feTile": ddeSVGFETileElement;
"feTurbulence": ddeSVGFETurbulenceElement;
"filter": ddeSVGFilterElement;
"foreignObject": ddeSVGForeignObjectElement;
"g": ddeSVGGElement;
"image": ddeSVGImageElement;
"line": ddeSVGLineElement;
"linearGradient": ddeSVGLinearGradientElement;
"marker": ddeSVGMarkerElement;
"mask": ddeSVGMaskElement;
"metadata": ddeSVGMetadataElement;
"mpath": ddeSVGMPathElement;
"path": ddeSVGPathElement;
"pattern": ddeSVGPatternElement;
"polygon": ddeSVGPolygonElement;
"polyline": ddeSVGPolylineElement;
"radialGradient": ddeSVGRadialGradientElement;
"rect": ddeSVGRectElement;
"script": ddeSVGScriptElement;
"set": ddeSVGSetElement;
"stop": ddeSVGStopElement;
"style": ddeSVGStyleElement;
"svg": ddeSVGSVGElement;
"switch": ddeSVGSwitchElement;
"symbol": ddeSVGSymbolElement;
"text": ddeSVGTextElement;
"textPath": ddeSVGTextPathElement;
"title": ddeSVGTitleElement;
"tspan": ddeSVGTSpanElement;
"use": ddeSVGUseElement;
"view": ddeSVGViewElement;
}
}
// editorconfig-checker-disable
export interface ddeHTMLAnchorElement extends HTMLAnchorElement {
append: ddeAppend<ddeHTMLAnchorElement>;
}
export interface ddeHTMLAreaElement extends HTMLAreaElement {
append: ddeAppend<ddeHTMLAreaElement>;
}
export interface ddeHTMLAudioElement extends HTMLAudioElement {
append: ddeAppend<ddeHTMLAudioElement>;
}
export interface ddeHTMLBaseElement extends HTMLBaseElement {
append: ddeAppend<ddeHTMLBaseElement>;
}
export interface ddeHTMLQuoteElement extends HTMLQuoteElement {
append: ddeAppend<ddeHTMLQuoteElement>;
}
export interface ddeHTMLBodyElement extends HTMLBodyElement {
append: ddeAppend<ddeHTMLBodyElement>;
}
export interface ddeHTMLBRElement extends HTMLBRElement {
append: ddeAppend<ddeHTMLBRElement>;
}
export interface ddeHTMLButtonElement extends HTMLButtonElement {
append: ddeAppend<ddeHTMLButtonElement>;
}
export interface ddeHTMLCanvasElement extends HTMLCanvasElement {
append: ddeAppend<ddeHTMLCanvasElement>;
}
export interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement {
append: ddeAppend<ddeHTMLTableCaptionElement>;
}
export interface ddeHTMLTableColElement extends HTMLTableColElement {
append: ddeAppend<ddeHTMLTableColElement>;
}
export interface ddeHTMLTableColElement extends HTMLTableColElement {
append: ddeAppend<ddeHTMLTableColElement>;
}
export interface ddeHTMLDataElement extends HTMLDataElement {
append: ddeAppend<ddeHTMLDataElement>;
}
export interface ddeHTMLDataListElement extends HTMLDataListElement {
append: ddeAppend<ddeHTMLDataListElement>;
}
export interface ddeHTMLModElement extends HTMLModElement {
append: ddeAppend<ddeHTMLModElement>;
}
export interface ddeHTMLDetailsElement extends HTMLDetailsElement {
append: ddeAppend<ddeHTMLDetailsElement>;
}
export interface ddeHTMLDialogElement extends HTMLDialogElement {
append: ddeAppend<ddeHTMLDialogElement>;
}
export interface ddeHTMLDivElement extends HTMLDivElement {
append: ddeAppend<ddeHTMLDivElement>;
}
export interface ddeHTMLDListElement extends HTMLDListElement {
append: ddeAppend<ddeHTMLDListElement>;
}
export interface ddeHTMLEmbedElement extends HTMLEmbedElement {
append: ddeAppend<ddeHTMLEmbedElement>;
}
export interface ddeHTMLFieldSetElement extends HTMLFieldSetElement {
append: ddeAppend<ddeHTMLFieldSetElement>;
}
export interface ddeHTMLFormElement extends HTMLFormElement {
append: ddeAppend<ddeHTMLFormElement>;
}
export interface ddeHTMLHeadingElement extends HTMLHeadingElement {
append: ddeAppend<ddeHTMLHeadingElement>;
}
export interface ddeHTMLHeadElement extends HTMLHeadElement {
append: ddeAppend<ddeHTMLHeadElement>;
}
export interface ddeHTMLHRElement extends HTMLHRElement {
append: ddeAppend<ddeHTMLHRElement>;
}
export interface ddeHTMLHtmlElement extends HTMLHtmlElement {
append: ddeAppend<ddeHTMLHtmlElement>;
}
export interface ddeHTMLIFrameElement extends HTMLIFrameElement {
append: ddeAppend<ddeHTMLIFrameElement>;
}
export interface ddeHTMLImageElement extends HTMLImageElement {
append: ddeAppend<ddeHTMLImageElement>;
}
export interface ddeHTMLInputElement extends HTMLInputElement {
append: ddeAppend<ddeHTMLInputElement>;
}
export interface ddeHTMLLabelElement extends HTMLLabelElement {
append: ddeAppend<ddeHTMLLabelElement>;
}
export interface ddeHTMLLegendElement extends HTMLLegendElement {
append: ddeAppend<ddeHTMLLegendElement>;
}
export interface ddeHTMLLIElement extends HTMLLIElement {
append: ddeAppend<ddeHTMLLIElement>;
}
export interface ddeHTMLLinkElement extends HTMLLinkElement {
append: ddeAppend<ddeHTMLLinkElement>;
}
export interface ddeHTMLMapElement extends HTMLMapElement {
append: ddeAppend<ddeHTMLMapElement>;
}
export interface ddeHTMLMenuElement extends HTMLMenuElement {
append: ddeAppend<ddeHTMLMenuElement>;
}
export interface ddeHTMLMetaElement extends HTMLMetaElement {
append: ddeAppend<ddeHTMLMetaElement>;
}
export interface ddeHTMLMeterElement extends HTMLMeterElement {
append: ddeAppend<ddeHTMLMeterElement>;
}
export interface ddeHTMLObjectElement extends HTMLObjectElement {
append: ddeAppend<ddeHTMLObjectElement>;
}
export interface ddeHTMLOListElement extends HTMLOListElement {
append: ddeAppend<ddeHTMLOListElement>;
}
export interface ddeHTMLOptGroupElement extends HTMLOptGroupElement {
append: ddeAppend<ddeHTMLOptGroupElement>;
}
export interface ddeHTMLOptionElement extends HTMLOptionElement {
append: ddeAppend<ddeHTMLOptionElement>;
}
export interface ddeHTMLOutputElement extends HTMLOutputElement {
append: ddeAppend<ddeHTMLOutputElement>;
}
export interface ddeHTMLParagraphElement extends HTMLParagraphElement {
append: ddeAppend<ddeHTMLParagraphElement>;
}
export interface ddeHTMLPictureElement extends HTMLPictureElement {
append: ddeAppend<ddeHTMLPictureElement>;
}
export interface ddeHTMLPreElement extends HTMLPreElement {
append: ddeAppend<ddeHTMLPreElement>;
}
export interface ddeHTMLProgressElement extends HTMLProgressElement {
append: ddeAppend<ddeHTMLProgressElement>;
}
export interface ddeHTMLScriptElement extends HTMLScriptElement {
append: ddeAppend<ddeHTMLScriptElement>;
}
export interface ddeHTMLSelectElement extends HTMLSelectElement {
append: ddeAppend<ddeHTMLSelectElement>;
}
export interface ddeHTMLSlotElement extends HTMLSlotElement {
append: ddeAppend<ddeHTMLSlotElement>;
}
export interface ddeHTMLSourceElement extends HTMLSourceElement {
append: ddeAppend<ddeHTMLSourceElement>;
}
export interface ddeHTMLSpanElement extends HTMLSpanElement {
append: ddeAppend<ddeHTMLSpanElement>;
}
export interface ddeHTMLStyleElement extends HTMLStyleElement {
append: ddeAppend<ddeHTMLStyleElement>;
}
export interface ddeHTMLTableElement extends HTMLTableElement {
append: ddeAppend<ddeHTMLTableElement>;
}
export interface ddeHTMLTableSectionElement extends HTMLTableSectionElement {
append: ddeAppend<ddeHTMLTableSectionElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTemplateElement extends HTMLTemplateElement {
append: ddeAppend<ddeHTMLTemplateElement>;
}
export interface ddeHTMLTextAreaElement extends HTMLTextAreaElement {
append: ddeAppend<ddeHTMLTextAreaElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTimeElement extends HTMLTimeElement {
append: ddeAppend<ddeHTMLTimeElement>;
}
export interface ddeHTMLTitleElement extends HTMLTitleElement {
append: ddeAppend<ddeHTMLTitleElement>;
}
export interface ddeHTMLTableRowElement extends HTMLTableRowElement {
append: ddeAppend<ddeHTMLTableRowElement>;
}
export interface ddeHTMLTrackElement extends HTMLTrackElement {
append: ddeAppend<ddeHTMLTrackElement>;
}
export interface ddeHTMLUListElement extends HTMLUListElement {
append: ddeAppend<ddeHTMLUListElement>;
}
export interface ddeHTMLVideoElement extends HTMLVideoElement {
append: ddeAppend<ddeHTMLVideoElement>;
}
export interface ddeSVGAElement extends SVGAElement {
append: ddeAppend<ddeSVGAElement>;
}
export interface ddeSVGAnimateElement extends SVGAnimateElement {
append: ddeAppend<ddeSVGAnimateElement>;
}
export interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement {
append: ddeAppend<ddeSVGAnimateMotionElement>;
}
export interface ddeSVGAnimateTransformElement extends SVGAnimateTransformElement {
append: ddeAppend<ddeSVGAnimateTransformElement>;
}
export interface ddeSVGCircleElement extends SVGCircleElement {
append: ddeAppend<ddeSVGCircleElement>;
}
export interface ddeSVGClipPathElement extends SVGClipPathElement {
append: ddeAppend<ddeSVGClipPathElement>;
}
export interface ddeSVGDefsElement extends SVGDefsElement {
append: ddeAppend<ddeSVGDefsElement>;
}
export interface ddeSVGDescElement extends SVGDescElement {
append: ddeAppend<ddeSVGDescElement>;
}
export interface ddeSVGEllipseElement extends SVGEllipseElement {
append: ddeAppend<ddeSVGEllipseElement>;
}
export interface ddeSVGFEBlendElement extends SVGFEBlendElement {
append: ddeAppend<ddeSVGFEBlendElement>;
}
export interface ddeSVGFEColorMatrixElement extends SVGFEColorMatrixElement {
append: ddeAppend<ddeSVGFEColorMatrixElement>;
}
export interface ddeSVGFEComponentTransferElement extends SVGFEComponentTransferElement {
append: ddeAppend<ddeSVGFEComponentTransferElement>;
}
export interface ddeSVGFECompositeElement extends SVGFECompositeElement {
append: ddeAppend<ddeSVGFECompositeElement>;
}
export interface ddeSVGFEConvolveMatrixElement extends SVGFEConvolveMatrixElement {
append: ddeAppend<ddeSVGFEConvolveMatrixElement>;
}
export interface ddeSVGFEDiffuseLightingElement extends SVGFEDiffuseLightingElement {
append: ddeAppend<ddeSVGFEDiffuseLightingElement>;
}
export interface ddeSVGFEDisplacementMapElement extends SVGFEDisplacementMapElement {
append: ddeAppend<ddeSVGFEDisplacementMapElement>;
}
export interface ddeSVGFEDistantLightElement extends SVGFEDistantLightElement {
append: ddeAppend<ddeSVGFEDistantLightElement>;
}
export interface ddeSVGFEDropShadowElement extends SVGFEDropShadowElement {
append: ddeAppend<ddeSVGFEDropShadowElement>;
}
export interface ddeSVGFEFloodElement extends SVGFEFloodElement {
append: ddeAppend<ddeSVGFEFloodElement>;
}
export interface ddeSVGFEFuncAElement extends SVGFEFuncAElement {
append: ddeAppend<ddeSVGFEFuncAElement>;
}
export interface ddeSVGFEFuncBElement extends SVGFEFuncBElement {
append: ddeAppend<ddeSVGFEFuncBElement>;
}
export interface ddeSVGFEFuncGElement extends SVGFEFuncGElement {
append: ddeAppend<ddeSVGFEFuncGElement>;
}
export interface ddeSVGFEFuncRElement extends SVGFEFuncRElement {
append: ddeAppend<ddeSVGFEFuncRElement>;
}
export interface ddeSVGFEGaussianBlurElement extends SVGFEGaussianBlurElement {
append: ddeAppend<ddeSVGFEGaussianBlurElement>;
}
export interface ddeSVGFEImageElement extends SVGFEImageElement {
append: ddeAppend<ddeSVGFEImageElement>;
}
export interface ddeSVGFEMergeElement extends SVGFEMergeElement {
append: ddeAppend<ddeSVGFEMergeElement>;
}
export interface ddeSVGFEMergeNodeElement extends SVGFEMergeNodeElement {
append: ddeAppend<ddeSVGFEMergeNodeElement>;
}
export interface ddeSVGFEMorphologyElement extends SVGFEMorphologyElement {
append: ddeAppend<ddeSVGFEMorphologyElement>;
}
export interface ddeSVGFEOffsetElement extends SVGFEOffsetElement {
append: ddeAppend<ddeSVGFEOffsetElement>;
}
export interface ddeSVGFEPointLightElement extends SVGFEPointLightElement {
append: ddeAppend<ddeSVGFEPointLightElement>;
}
export interface ddeSVGFESpecularLightingElement extends SVGFESpecularLightingElement {
append: ddeAppend<ddeSVGFESpecularLightingElement>;
}
export interface ddeSVGFESpotLightElement extends SVGFESpotLightElement {
append: ddeAppend<ddeSVGFESpotLightElement>;
}
export interface ddeSVGFETileElement extends SVGFETileElement {
append: ddeAppend<ddeSVGFETileElement>;
}
export interface ddeSVGFETurbulenceElement extends SVGFETurbulenceElement {
append: ddeAppend<ddeSVGFETurbulenceElement>;
}
export interface ddeSVGFilterElement extends SVGFilterElement {
append: ddeAppend<ddeSVGFilterElement>;
}
export interface ddeSVGForeignObjectElement extends SVGForeignObjectElement {
append: ddeAppend<ddeSVGForeignObjectElement>;
}
export interface ddeSVGGElement extends SVGGElement {
append: ddeAppend<ddeSVGGElement>;
}
export interface ddeSVGImageElement extends SVGImageElement {
append: ddeAppend<ddeSVGImageElement>;
}
export interface ddeSVGLineElement extends SVGLineElement {
append: ddeAppend<ddeSVGLineElement>;
}
export interface ddeSVGLinearGradientElement extends SVGLinearGradientElement {
append: ddeAppend<ddeSVGLinearGradientElement>;
}
export interface ddeSVGMarkerElement extends SVGMarkerElement {
append: ddeAppend<ddeSVGMarkerElement>;
}
export interface ddeSVGMaskElement extends SVGMaskElement {
append: ddeAppend<ddeSVGMaskElement>;
}
export interface ddeSVGMetadataElement extends SVGMetadataElement {
append: ddeAppend<ddeSVGMetadataElement>;
}
export interface ddeSVGMPathElement extends SVGMPathElement {
append: ddeAppend<ddeSVGMPathElement>;
}
export interface ddeSVGPathElement extends SVGPathElement {
append: ddeAppend<ddeSVGPathElement>;
}
export interface ddeSVGPatternElement extends SVGPatternElement {
append: ddeAppend<ddeSVGPatternElement>;
}
export interface ddeSVGPolygonElement extends SVGPolygonElement {
append: ddeAppend<ddeSVGPolygonElement>;
}
export interface ddeSVGPolylineElement extends SVGPolylineElement {
append: ddeAppend<ddeSVGPolylineElement>;
}
export interface ddeSVGRadialGradientElement extends SVGRadialGradientElement {
append: ddeAppend<ddeSVGRadialGradientElement>;
}
export interface ddeSVGRectElement extends SVGRectElement {
append: ddeAppend<ddeSVGRectElement>;
}
export interface ddeSVGScriptElement extends SVGScriptElement {
append: ddeAppend<ddeSVGScriptElement>;
}
export interface ddeSVGSetElement extends SVGSetElement {
append: ddeAppend<ddeSVGSetElement>;
}
export interface ddeSVGStopElement extends SVGStopElement {
append: ddeAppend<ddeSVGStopElement>;
}
export interface ddeSVGStyleElement extends SVGStyleElement {
append: ddeAppend<ddeSVGStyleElement>;
}
export interface ddeSVGSVGElement extends SVGSVGElement {
append: ddeAppend<ddeSVGSVGElement>;
}
export interface ddeSVGSwitchElement extends SVGSwitchElement {
append: ddeAppend<ddeSVGSwitchElement>;
}
export interface ddeSVGSymbolElement extends SVGSymbolElement {
append: ddeAppend<ddeSVGSymbolElement>;
}
export interface ddeSVGTextElement extends SVGTextElement {
append: ddeAppend<ddeSVGTextElement>;
}
export interface ddeSVGTextPathElement extends SVGTextPathElement {
append: ddeAppend<ddeSVGTextPathElement>;
}
export interface ddeSVGTitleElement extends SVGTitleElement {
append: ddeAppend<ddeSVGTitleElement>;
}
export interface ddeSVGTSpanElement extends SVGTSpanElement {
append: ddeAppend<ddeSVGTSpanElement>;
}
export interface ddeSVGUseElement extends SVGUseElement {
append: ddeAppend<ddeSVGUseElement>;
}
export interface ddeSVGViewElement extends SVGViewElement {
append: ddeAppend<ddeSVGViewElement>;
}
export {
dispatchEvent$1 as dispatchEvent,
el as createElement,
elNS as createElementNS,
};
export {};

4
dist/esm-with-signals.min.js vendored Normal file

File diff suppressed because one or more lines are too long

568
dist/esm.d.min.ts vendored Normal file
View File

@ -0,0 +1,568 @@
declare global{ /* ddeSignal */ }
type CustomElementTagNameMap= { '#text': Text, '#comment': Comment }
type SupportedElement=
HTMLElementTagNameMap[keyof HTMLElementTagNameMap]
| SVGElementTagNameMap[keyof SVGElementTagNameMap]
| MathMLElementTagNameMap[keyof MathMLElementTagNameMap]
| CustomElementTagNameMap[keyof CustomElementTagNameMap]
declare global {
type ddeComponentAttributes= Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment | Node>= (element: El)=> any;
type ddeString= string | ddeSignal<string>
type ddeStringable= ddeString | number | ddeSignal<number>
}
type PascalCase=
`${Capitalize<string>}${string}`;
type AttrsModified= {
/**
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/
style: Partial<CSSStyleDeclaration> | ddeString
| Partial<{ [K in keyof CSSStyleDeclaration]: ddeSignal<CSSStyleDeclaration[K]> }>
/**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1.
* In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))`
* for others.
*/
classList: Record<string,-1|0|1|boolean|ddeSignal<-1|0|1|boolean>>,
/**
* Used by the dataset HTML attribute to represent data for custom attributes added to elements.
* Values are converted to string (see {@link DOMStringMap}).
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMStringMap)
* */
dataset: Record<string, ddeStringable>,
/**
* Sets `aria-*` simiraly to `dataset`
* */
ariaset: Record<string, ddeString>,
} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, ddeString>
& Record<`.${string}`, any>
type _fromElsInterfaces<EL extends SupportedElement>= Omit<EL, keyof AttrsModified>;
type IsReadonly<T, K extends keyof T> =
T extends { readonly [P in K]: T[K] } ? true : false;
/**
* Just element attributtes
*
* In most cases, you can use native propertie such as
* [MDN WEB/API/Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) and so on
* (e.g. [`Text`](https://developer.mozilla.org/en-US/docs/Web/API/Text)).
*
* There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives.
* @private
*/
type ElementAttributes<T extends SupportedElement>= Partial<{
[K in keyof _fromElsInterfaces<T>]:
_fromElsInterfaces<T>[K] extends ((...p: any[])=> any)
? _fromElsInterfaces<T>[K] | ((...p: Parameters<_fromElsInterfaces<T>[K]>)=>
ddeSignal<ReturnType<_fromElsInterfaces<T>[K]>>)
: (IsReadonly<_fromElsInterfaces<T>, K> extends false
? _fromElsInterfaces<T>[K] | ddeSignal<_fromElsInterfaces<T>[K]>
: ddeStringable)
} & AttrsModified> & Record<string, any>;
export function classListDeclarative<El extends SupportedElement>(
element: El,
classList: AttrsModified["classList"]
): El
export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El
export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(
element: El,
attr: ATT,
value: ElementAttributes<El>[ATT]
): ElementAttributes<El>[ATT]
type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap;
export namespace el {
/**
* Creates a marker comment for elements
*
* @param attrs - Marker attributes
* @param [is_open=false] - Whether the marker is open-ended
* @returns Comment node marker
*/
export function mark(
attrs: { type: "component"|"reactive"|"later", name?: string, host?: "this"|"parentElement" },
is_open?: boolean
): Comment;
}
export function el<
A extends ddeComponentAttributes,
EL extends SupportedElement | ddeDocumentFragment
>(
component: (attr: A, ...rest: any[])=> EL,
attrs?: NoInfer<A>,
...addons: ddeElementAddon<EL>[]
): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap]
? EL
: ( EL extends ddeDocumentFragment ? EL : ddeHTMLElement )
export function el<
A extends { textContent: ddeStringable },
EL extends SupportedElement | ddeDocumentFragment
>(
component: (attr: A, ...rest: any[])=> EL,
attrs?: NoInfer<A>["textContent"],
...addons: ddeElementAddon<EL>[]
): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap]
? EL
: ( EL extends ddeDocumentFragment ? EL : ddeHTMLElement )
export function el<
TAG extends keyof ExtendedHTMLElementTagNameMap,
>(
tag_name: TAG,
attrs?: ElementAttributes<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]> | ddeStringable,
...addons: ddeElementAddon<
ExtendedHTMLElementTagNameMap[NoInfer<TAG>]
>[], // TODO: for now addons must have the same element
): TAG extends keyof ddeHTMLElementTagNameMap ? ddeHTMLElementTagNameMap[TAG] : ddeHTMLElement
export function el(
tag_name?: "<>",
): ddeDocumentFragment
export function el(
tag_name: string,
attrs?: ElementAttributes<HTMLElement> | ddeStringable,
...addons: ddeElementAddon<HTMLElement>[]
): ddeHTMLElement
export { el as createElement }
export function elNS(
namespace: "http://www.w3.org/2000/svg"
): <
TAG extends keyof SVGElementTagNameMap & string,
EL extends ( TAG extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[TAG] : SVGElement ),
>(
tag_name: TAG,
attrs?: ElementAttributes<NoInfer<EL>> | ddeStringable,
...addons: ddeElementAddon<NoInfer<EL>>[]
)=> TAG extends keyof ddeSVGElementTagNameMap ? ddeSVGElementTagNameMap[TAG] : ddeSVGElement
export function elNS(
namespace: "http://www.w3.org/1998/Math/MathML"
): <
TAG extends keyof MathMLElementTagNameMap & string,
EL extends ( TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement ),
>(
tag_name: TAG,
attrs?: ddeStringable | Partial<{
[key in keyof EL]: EL[key] | ddeSignal<EL[key]> | string | number | boolean
}>,
...addons: ddeElementAddon<NoInfer<EL>>[]
)=> ddeMathMLElement
export function elNS(
namespace: string
): (
tag_name: string,
attrs?: string | ddeStringable | Record<string, any>,
...addons: ddeElementAddon<SupportedElement>[]
)=> SupportedElement
export { elNS as createElementNS }
export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
/** Simulate slots for ddeComponents */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(
root: EL,
): EL
/**
* Simulate slots in Custom Elements without using `shadowRoot`.
* @param el Custom Element root element
* @param body Body of the custom element
* */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(
el: HTMLElement,
body: EL,
): EL
export function dispatchEvent(name: keyof DocumentEventMap | string, element: SupportedElement):
(data?: any)=> void;
export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit):
(element: SupportedElement, data?: any)=> void;
export function dispatchEvent(
name: keyof DocumentEventMap | string,
options: EventInit | null,
element: SupportedElement | (()=> SupportedElement)
): (data?: any)=> void;
interface On{
/** Listens to the DOM event. See {@link Document.addEventListener} */
<
Event extends keyof DocumentEventMap,
EE extends ddeElementAddon<SupportedElement>= ddeElementAddon<HTMLElement>,
>(
type: Event,
listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any,
options?: AddEventListenerOptions
) : EE;
<
EE extends ddeElementAddon<SupportedElement>= ddeElementAddon<HTMLElement>,
>(
type: string,
listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent ) => any,
options?: AddEventListenerOptions
) : EE;
/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line
connected<
EE extends ddeElementAddon<SupportedElement>,
El extends ( EE extends ddeElementAddon<infer El> ? El : never )
>(
listener: (this: El, event: CustomEvent<El>) => any,
options?: AddEventListenerOptions
) : EE;
/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line
disconnected<
EE extends ddeElementAddon<SupportedElement>,
El extends ( EE extends ddeElementAddon<infer El> ? El : never )
>(
listener: (this: El, event: CustomEvent<void>) => any,
options?: AddEventListenerOptions
) : EE;
/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line
attributeChanged<
EE extends ddeElementAddon<SupportedElement>,
El extends ( EE extends ddeElementAddon<infer El> ? El : never )
>(
listener: (this: El, event: CustomEvent<[ string, string ]>) => any,
options?: AddEventListenerOptions
) : EE;
}
export const on: On;
type Scope= {
scope: Node | Function | Object,
host: ddeElementAddon<any>,
custom_element: false | HTMLElement,
prevent: boolean
};
/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */
export const scope: {
current: Scope,
/** Stops all automatizations. E. g. signals used as attributes in current scope
* registers removing these listeners (and clean signal if no other listeners are detected)
* on `disconnected` event. */
preventDefault<T extends boolean>(prevent: T): T,
/**
* This represents reference to the current host element `scope.host()`.
* It can be also used to register Addon(s) (functions to be called when component is initized)
* `scope.host(on.connected(console.log))`.
* */
host: (...addons: ddeElementAddon<SupportedElement>[])=> HTMLElement,
state: Scope[],
/** Adds new child scope. All attributes are inherited by default. */
push(scope?: Partial<Scope>): ReturnType<Array<Scope>["push"]>,
/** Adds root scope as a child of the current scope. */
pushRoot(): ReturnType<Array<Scope>["push"]>,
/** Removes last/current child scope. */
pop(): ReturnType<Array<Scope>["pop"]>,
};
export function customElementRender<
EL extends HTMLElement,
P extends any = Record<string, string | ddeSignal<string>>
>(
target: ShadowRoot | EL,
render: (props: P)=> SupportedElement | DocumentFragment,
props?: P | ((el: EL)=> P)
): EL
export function customElementWithDDE<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL
export function lifecyclesToEvents<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL
export function observedAttributes(custom_element: HTMLElement): Record<string, string>
/**
* This is used primarly for server side rendering. To be sure that all async operations
* are finished before the page is sent to the client.
* ```
* // on component
* function component(){
*
* queue(fetch(...).then(...));
* }
*
* // building the page
* async function build(){
* const { component }= await import("./component.js");
* document.body.append(el(component));
* await queue();
* retutn document.body.innerHTML;
* }
* ```
* */
export function queue(promise?: Promise<unknown>): Promise<unknown>;
/* TypeScript MEH */
declare global{
type ddeAppend<el>= (...nodes: (Node | string)[])=> el;
interface ddeDocumentFragment extends DocumentFragment{ append: ddeAppend<ddeDocumentFragment>; }
interface ddeHTMLElement extends HTMLElement{ append: ddeAppend<ddeHTMLElement>; }
interface ddeSVGElement extends SVGElement{ append: ddeAppend<ddeSVGElement>; }
interface ddeMathMLElement extends MathMLElement{ append: ddeAppend<ddeMathMLElement>; }
interface ddeHTMLElementTagNameMap {
"a": ddeHTMLAnchorElement;
"area": ddeHTMLAreaElement;
"audio": ddeHTMLAudioElement;
"base": ddeHTMLBaseElement;
"blockquote": ddeHTMLQuoteElement;
"body": ddeHTMLBodyElement;
"br": ddeHTMLBRElement;
"button": ddeHTMLButtonElement;
"canvas": ddeHTMLCanvasElement;
"caption": ddeHTMLTableCaptionElement;
"col": ddeHTMLTableColElement;
"colgroup": ddeHTMLTableColElement;
"data": ddeHTMLDataElement;
"datalist": ddeHTMLDataListElement;
"del": ddeHTMLModElement;
"details": ddeHTMLDetailsElement;
"dialog": ddeHTMLDialogElement;
"div": ddeHTMLDivElement;
"dl": ddeHTMLDListElement;
"embed": ddeHTMLEmbedElement;
"fieldset": ddeHTMLFieldSetElement;
"form": ddeHTMLFormElement;
"h1": ddeHTMLHeadingElement;
"h2": ddeHTMLHeadingElement;
"h3": ddeHTMLHeadingElement;
"h4": ddeHTMLHeadingElement;
"h5": ddeHTMLHeadingElement;
"h6": ddeHTMLHeadingElement;
"head": ddeHTMLHeadElement;
"hr": ddeHTMLHRElement;
"html": ddeHTMLHtmlElement;
"iframe": ddeHTMLIFrameElement;
"img": ddeHTMLImageElement;
"input": ddeHTMLInputElement;
"ins": ddeHTMLModElement;
"label": ddeHTMLLabelElement;
"legend": ddeHTMLLegendElement;
"li": ddeHTMLLIElement;
"link": ddeHTMLLinkElement;
"map": ddeHTMLMapElement;
"menu": ddeHTMLMenuElement;
"meta": ddeHTMLMetaElement;
"meter": ddeHTMLMeterElement;
"object": ddeHTMLObjectElement;
"ol": ddeHTMLOListElement;
"optgroup": ddeHTMLOptGroupElement;
"option": ddeHTMLOptionElement;
"output": ddeHTMLOutputElement;
"p": ddeHTMLParagraphElement;
"picture": ddeHTMLPictureElement;
"pre": ddeHTMLPreElement;
"progress": ddeHTMLProgressElement;
"q": ddeHTMLQuoteElement;
"script": ddeHTMLScriptElement;
"select": ddeHTMLSelectElement;
"slot": ddeHTMLSlotElement;
"source": ddeHTMLSourceElement;
"span": ddeHTMLSpanElement;
"style": ddeHTMLStyleElement;
"table": ddeHTMLTableElement;
"tbody": ddeHTMLTableSectionElement;
"td": ddeHTMLTableCellElement;
"template": ddeHTMLTemplateElement;
"textarea": ddeHTMLTextAreaElement;
"tfoot": ddeHTMLTableSectionElement;
"th": ddeHTMLTableCellElement;
"thead": ddeHTMLTableSectionElement;
"time": ddeHTMLTimeElement;
"title": ddeHTMLTitleElement;
"tr": ddeHTMLTableRowElement;
"track": ddeHTMLTrackElement;
"ul": ddeHTMLUListElement;
"video": ddeHTMLVideoElement;
}
interface ddeSVGElementTagNameMap {
"a": ddeSVGAElement;
"animate": ddeSVGAnimateElement;
"animateMotion": ddeSVGAnimateMotionElement;
"animateTransform": ddeSVGAnimateTransformElement;
"circle": ddeSVGCircleElement;
"clipPath": ddeSVGClipPathElement;
"defs": ddeSVGDefsElement;
"desc": ddeSVGDescElement;
"ellipse": ddeSVGEllipseElement;
"feBlend": ddeSVGFEBlendElement;
"feColorMatrix": ddeSVGFEColorMatrixElement;
"feComponentTransfer": ddeSVGFEComponentTransferElement;
"feComposite": ddeSVGFECompositeElement;
"feConvolveMatrix": ddeSVGFEConvolveMatrixElement;
"feDiffuseLighting": ddeSVGFEDiffuseLightingElement;
"feDisplacementMap": ddeSVGFEDisplacementMapElement;
"feDistantLight": ddeSVGFEDistantLightElement;
"feDropShadow": ddeSVGFEDropShadowElement;
"feFlood": ddeSVGFEFloodElement;
"feFuncA": ddeSVGFEFuncAElement;
"feFuncB": ddeSVGFEFuncBElement;
"feFuncG": ddeSVGFEFuncGElement;
"feFuncR": ddeSVGFEFuncRElement;
"feGaussianBlur": ddeSVGFEGaussianBlurElement;
"feImage": ddeSVGFEImageElement;
"feMerge": ddeSVGFEMergeElement;
"feMergeNode": ddeSVGFEMergeNodeElement;
"feMorphology": ddeSVGFEMorphologyElement;
"feOffset": ddeSVGFEOffsetElement;
"fePointLight": ddeSVGFEPointLightElement;
"feSpecularLighting": ddeSVGFESpecularLightingElement;
"feSpotLight": ddeSVGFESpotLightElement;
"feTile": ddeSVGFETileElement;
"feTurbulence": ddeSVGFETurbulenceElement;
"filter": ddeSVGFilterElement;
"foreignObject": ddeSVGForeignObjectElement;
"g": ddeSVGGElement;
"image": ddeSVGImageElement;
"line": ddeSVGLineElement;
"linearGradient": ddeSVGLinearGradientElement;
"marker": ddeSVGMarkerElement;
"mask": ddeSVGMaskElement;
"metadata": ddeSVGMetadataElement;
"mpath": ddeSVGMPathElement;
"path": ddeSVGPathElement;
"pattern": ddeSVGPatternElement;
"polygon": ddeSVGPolygonElement;
"polyline": ddeSVGPolylineElement;
"radialGradient": ddeSVGRadialGradientElement;
"rect": ddeSVGRectElement;
"script": ddeSVGScriptElement;
"set": ddeSVGSetElement;
"stop": ddeSVGStopElement;
"style": ddeSVGStyleElement;
"svg": ddeSVGSVGElement;
"switch": ddeSVGSwitchElement;
"symbol": ddeSVGSymbolElement;
"text": ddeSVGTextElement;
"textPath": ddeSVGTextPathElement;
"title": ddeSVGTitleElement;
"tspan": ddeSVGTSpanElement;
"use": ddeSVGUseElement;
"view": ddeSVGViewElement;
}
}
// editorconfig-checker-disable
interface ddeHTMLAnchorElement extends HTMLAnchorElement{ append: ddeAppend<ddeHTMLAnchorElement>; }
interface ddeHTMLAreaElement extends HTMLAreaElement{ append: ddeAppend<ddeHTMLAreaElement>; }
interface ddeHTMLAudioElement extends HTMLAudioElement{ append: ddeAppend<ddeHTMLAudioElement>; }
interface ddeHTMLBaseElement extends HTMLBaseElement{ append: ddeAppend<ddeHTMLBaseElement>; }
interface ddeHTMLQuoteElement extends HTMLQuoteElement{ append: ddeAppend<ddeHTMLQuoteElement>; }
interface ddeHTMLBodyElement extends HTMLBodyElement{ append: ddeAppend<ddeHTMLBodyElement>; }
interface ddeHTMLBRElement extends HTMLBRElement{ append: ddeAppend<ddeHTMLBRElement>; }
interface ddeHTMLButtonElement extends HTMLButtonElement{ append: ddeAppend<ddeHTMLButtonElement>; }
interface ddeHTMLCanvasElement extends HTMLCanvasElement{ append: ddeAppend<ddeHTMLCanvasElement>; }
interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement{ append: ddeAppend<ddeHTMLTableCaptionElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; }
interface ddeHTMLDataElement extends HTMLDataElement{ append: ddeAppend<ddeHTMLDataElement>; }
interface ddeHTMLDataListElement extends HTMLDataListElement{ append: ddeAppend<ddeHTMLDataListElement>; }
interface ddeHTMLModElement extends HTMLModElement{ append: ddeAppend<ddeHTMLModElement>; }
interface ddeHTMLDetailsElement extends HTMLDetailsElement{ append: ddeAppend<ddeHTMLDetailsElement>; }
interface ddeHTMLDialogElement extends HTMLDialogElement{ append: ddeAppend<ddeHTMLDialogElement>; }
interface ddeHTMLDivElement extends HTMLDivElement{ append: ddeAppend<ddeHTMLDivElement>; }
interface ddeHTMLDListElement extends HTMLDListElement{ append: ddeAppend<ddeHTMLDListElement>; }
interface ddeHTMLEmbedElement extends HTMLEmbedElement{ append: ddeAppend<ddeHTMLEmbedElement>; }
interface ddeHTMLFieldSetElement extends HTMLFieldSetElement{ append: ddeAppend<ddeHTMLFieldSetElement>; }
interface ddeHTMLFormElement extends HTMLFormElement{ append: ddeAppend<ddeHTMLFormElement>; }
interface ddeHTMLHeadingElement extends HTMLHeadingElement{ append: ddeAppend<ddeHTMLHeadingElement>; }
interface ddeHTMLHeadElement extends HTMLHeadElement{ append: ddeAppend<ddeHTMLHeadElement>; }
interface ddeHTMLHRElement extends HTMLHRElement{ append: ddeAppend<ddeHTMLHRElement>; }
interface ddeHTMLHtmlElement extends HTMLHtmlElement{ append: ddeAppend<ddeHTMLHtmlElement>; }
interface ddeHTMLIFrameElement extends HTMLIFrameElement{ append: ddeAppend<ddeHTMLIFrameElement>; }
interface ddeHTMLImageElement extends HTMLImageElement{ append: ddeAppend<ddeHTMLImageElement>; }
interface ddeHTMLInputElement extends HTMLInputElement{ append: ddeAppend<ddeHTMLInputElement>; }
interface ddeHTMLLabelElement extends HTMLLabelElement{ append: ddeAppend<ddeHTMLLabelElement>; }
interface ddeHTMLLegendElement extends HTMLLegendElement{ append: ddeAppend<ddeHTMLLegendElement>; }
interface ddeHTMLLIElement extends HTMLLIElement{ append: ddeAppend<ddeHTMLLIElement>; }
interface ddeHTMLLinkElement extends HTMLLinkElement{ append: ddeAppend<ddeHTMLLinkElement>; }
interface ddeHTMLMapElement extends HTMLMapElement{ append: ddeAppend<ddeHTMLMapElement>; }
interface ddeHTMLMenuElement extends HTMLMenuElement{ append: ddeAppend<ddeHTMLMenuElement>; }
interface ddeHTMLMetaElement extends HTMLMetaElement{ append: ddeAppend<ddeHTMLMetaElement>; }
interface ddeHTMLMeterElement extends HTMLMeterElement{ append: ddeAppend<ddeHTMLMeterElement>; }
interface ddeHTMLObjectElement extends HTMLObjectElement{ append: ddeAppend<ddeHTMLObjectElement>; }
interface ddeHTMLOListElement extends HTMLOListElement{ append: ddeAppend<ddeHTMLOListElement>; }
interface ddeHTMLOptGroupElement extends HTMLOptGroupElement{ append: ddeAppend<ddeHTMLOptGroupElement>; }
interface ddeHTMLOptionElement extends HTMLOptionElement{ append: ddeAppend<ddeHTMLOptionElement>; }
interface ddeHTMLOutputElement extends HTMLOutputElement{ append: ddeAppend<ddeHTMLOutputElement>; }
interface ddeHTMLParagraphElement extends HTMLParagraphElement{ append: ddeAppend<ddeHTMLParagraphElement>; }
interface ddeHTMLPictureElement extends HTMLPictureElement{ append: ddeAppend<ddeHTMLPictureElement>; }
interface ddeHTMLPreElement extends HTMLPreElement{ append: ddeAppend<ddeHTMLPreElement>; }
interface ddeHTMLProgressElement extends HTMLProgressElement{ append: ddeAppend<ddeHTMLProgressElement>; }
interface ddeHTMLScriptElement extends HTMLScriptElement{ append: ddeAppend<ddeHTMLScriptElement>; }
interface ddeHTMLSelectElement extends HTMLSelectElement{ append: ddeAppend<ddeHTMLSelectElement>; }
interface ddeHTMLSlotElement extends HTMLSlotElement{ append: ddeAppend<ddeHTMLSlotElement>; }
interface ddeHTMLSourceElement extends HTMLSourceElement{ append: ddeAppend<ddeHTMLSourceElement>; }
interface ddeHTMLSpanElement extends HTMLSpanElement{ append: ddeAppend<ddeHTMLSpanElement>; }
interface ddeHTMLStyleElement extends HTMLStyleElement{ append: ddeAppend<ddeHTMLStyleElement>; }
interface ddeHTMLTableElement extends HTMLTableElement{ append: ddeAppend<ddeHTMLTableElement>; }
interface ddeHTMLTableSectionElement extends HTMLTableSectionElement{ append: ddeAppend<ddeHTMLTableSectionElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTemplateElement extends HTMLTemplateElement{ append: ddeAppend<ddeHTMLTemplateElement>; }
interface ddeHTMLTextAreaElement extends HTMLTextAreaElement{ append: ddeAppend<ddeHTMLTextAreaElement>; }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; }
interface ddeHTMLTimeElement extends HTMLTimeElement{ append: ddeAppend<ddeHTMLTimeElement>; }
interface ddeHTMLTitleElement extends HTMLTitleElement{ append: ddeAppend<ddeHTMLTitleElement>; }
interface ddeHTMLTableRowElement extends HTMLTableRowElement{ append: ddeAppend<ddeHTMLTableRowElement>; }
interface ddeHTMLTrackElement extends HTMLTrackElement{ append: ddeAppend<ddeHTMLTrackElement>; }
interface ddeHTMLUListElement extends HTMLUListElement{ append: ddeAppend<ddeHTMLUListElement>; }
interface ddeHTMLVideoElement extends HTMLVideoElement{ append: ddeAppend<ddeHTMLVideoElement>; }
interface ddeSVGAElement extends SVGAElement{ append: ddeAppend<ddeSVGAElement>; }
interface ddeSVGAnimateElement extends SVGAnimateElement{ append: ddeAppend<ddeSVGAnimateElement>; }
interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement{ append: ddeAppend<ddeSVGAnimateMotionElement>; }
interface ddeSVGAnimateTransformElement extends SVGAnimateTransformElement{ append: ddeAppend<ddeSVGAnimateTransformElement>; }
interface ddeSVGCircleElement extends SVGCircleElement{ append: ddeAppend<ddeSVGCircleElement>; }
interface ddeSVGClipPathElement extends SVGClipPathElement{ append: ddeAppend<ddeSVGClipPathElement>; }
interface ddeSVGDefsElement extends SVGDefsElement{ append: ddeAppend<ddeSVGDefsElement>; }
interface ddeSVGDescElement extends SVGDescElement{ append: ddeAppend<ddeSVGDescElement>; }
interface ddeSVGEllipseElement extends SVGEllipseElement{ append: ddeAppend<ddeSVGEllipseElement>; }
interface ddeSVGFEBlendElement extends SVGFEBlendElement{ append: ddeAppend<ddeSVGFEBlendElement>; }
interface ddeSVGFEColorMatrixElement extends SVGFEColorMatrixElement{ append: ddeAppend<ddeSVGFEColorMatrixElement>; }
interface ddeSVGFEComponentTransferElement extends SVGFEComponentTransferElement{ append: ddeAppend<ddeSVGFEComponentTransferElement>; }
interface ddeSVGFECompositeElement extends SVGFECompositeElement{ append: ddeAppend<ddeSVGFECompositeElement>; }
interface ddeSVGFEConvolveMatrixElement extends SVGFEConvolveMatrixElement{ append: ddeAppend<ddeSVGFEConvolveMatrixElement>; }
interface ddeSVGFEDiffuseLightingElement extends SVGFEDiffuseLightingElement{ append: ddeAppend<ddeSVGFEDiffuseLightingElement>; }
interface ddeSVGFEDisplacementMapElement extends SVGFEDisplacementMapElement{ append: ddeAppend<ddeSVGFEDisplacementMapElement>; }
interface ddeSVGFEDistantLightElement extends SVGFEDistantLightElement{ append: ddeAppend<ddeSVGFEDistantLightElement>; }
interface ddeSVGFEDropShadowElement extends SVGFEDropShadowElement{ append: ddeAppend<ddeSVGFEDropShadowElement>; }
interface ddeSVGFEFloodElement extends SVGFEFloodElement{ append: ddeAppend<ddeSVGFEFloodElement>; }
interface ddeSVGFEFuncAElement extends SVGFEFuncAElement{ append: ddeAppend<ddeSVGFEFuncAElement>; }
interface ddeSVGFEFuncBElement extends SVGFEFuncBElement{ append: ddeAppend<ddeSVGFEFuncBElement>; }
interface ddeSVGFEFuncGElement extends SVGFEFuncGElement{ append: ddeAppend<ddeSVGFEFuncGElement>; }
interface ddeSVGFEFuncRElement extends SVGFEFuncRElement{ append: ddeAppend<ddeSVGFEFuncRElement>; }
interface ddeSVGFEGaussianBlurElement extends SVGFEGaussianBlurElement{ append: ddeAppend<ddeSVGFEGaussianBlurElement>; }
interface ddeSVGFEImageElement extends SVGFEImageElement{ append: ddeAppend<ddeSVGFEImageElement>; }
interface ddeSVGFEMergeElement extends SVGFEMergeElement{ append: ddeAppend<ddeSVGFEMergeElement>; }
interface ddeSVGFEMergeNodeElement extends SVGFEMergeNodeElement{ append: ddeAppend<ddeSVGFEMergeNodeElement>; }
interface ddeSVGFEMorphologyElement extends SVGFEMorphologyElement{ append: ddeAppend<ddeSVGFEMorphologyElement>; }
interface ddeSVGFEOffsetElement extends SVGFEOffsetElement{ append: ddeAppend<ddeSVGFEOffsetElement>; }
interface ddeSVGFEPointLightElement extends SVGFEPointLightElement{ append: ddeAppend<ddeSVGFEPointLightElement>; }
interface ddeSVGFESpecularLightingElement extends SVGFESpecularLightingElement{ append: ddeAppend<ddeSVGFESpecularLightingElement>; }
interface ddeSVGFESpotLightElement extends SVGFESpotLightElement{ append: ddeAppend<ddeSVGFESpotLightElement>; }
interface ddeSVGFETileElement extends SVGFETileElement{ append: ddeAppend<ddeSVGFETileElement>; }
interface ddeSVGFETurbulenceElement extends SVGFETurbulenceElement{ append: ddeAppend<ddeSVGFETurbulenceElement>; }
interface ddeSVGFilterElement extends SVGFilterElement{ append: ddeAppend<ddeSVGFilterElement>; }
interface ddeSVGForeignObjectElement extends SVGForeignObjectElement{ append: ddeAppend<ddeSVGForeignObjectElement>; }
interface ddeSVGGElement extends SVGGElement{ append: ddeAppend<ddeSVGGElement>; }
interface ddeSVGImageElement extends SVGImageElement{ append: ddeAppend<ddeSVGImageElement>; }
interface ddeSVGLineElement extends SVGLineElement{ append: ddeAppend<ddeSVGLineElement>; }
interface ddeSVGLinearGradientElement extends SVGLinearGradientElement{ append: ddeAppend<ddeSVGLinearGradientElement>; }
interface ddeSVGMarkerElement extends SVGMarkerElement{ append: ddeAppend<ddeSVGMarkerElement>; }
interface ddeSVGMaskElement extends SVGMaskElement{ append: ddeAppend<ddeSVGMaskElement>; }
interface ddeSVGMetadataElement extends SVGMetadataElement{ append: ddeAppend<ddeSVGMetadataElement>; }
interface ddeSVGMPathElement extends SVGMPathElement{ append: ddeAppend<ddeSVGMPathElement>; }
interface ddeSVGPathElement extends SVGPathElement{ append: ddeAppend<ddeSVGPathElement>; }
interface ddeSVGPatternElement extends SVGPatternElement{ append: ddeAppend<ddeSVGPatternElement>; }
interface ddeSVGPolygonElement extends SVGPolygonElement{ append: ddeAppend<ddeSVGPolygonElement>; }
interface ddeSVGPolylineElement extends SVGPolylineElement{ append: ddeAppend<ddeSVGPolylineElement>; }
interface ddeSVGRadialGradientElement extends SVGRadialGradientElement{ append: ddeAppend<ddeSVGRadialGradientElement>; }
interface ddeSVGRectElement extends SVGRectElement{ append: ddeAppend<ddeSVGRectElement>; }
interface ddeSVGScriptElement extends SVGScriptElement{ append: ddeAppend<ddeSVGScriptElement>; }
interface ddeSVGSetElement extends SVGSetElement{ append: ddeAppend<ddeSVGSetElement>; }
interface ddeSVGStopElement extends SVGStopElement{ append: ddeAppend<ddeSVGStopElement>; }
interface ddeSVGStyleElement extends SVGStyleElement{ append: ddeAppend<ddeSVGStyleElement>; }
interface ddeSVGSVGElement extends SVGSVGElement{ append: ddeAppend<ddeSVGSVGElement>; }
interface ddeSVGSwitchElement extends SVGSwitchElement{ append: ddeAppend<ddeSVGSwitchElement>; }
interface ddeSVGSymbolElement extends SVGSymbolElement{ append: ddeAppend<ddeSVGSymbolElement>; }
interface ddeSVGTextElement extends SVGTextElement{ append: ddeAppend<ddeSVGTextElement>; }
interface ddeSVGTextPathElement extends SVGTextPathElement{ append: ddeAppend<ddeSVGTextPathElement>; }
interface ddeSVGTitleElement extends SVGTitleElement{ append: ddeAppend<ddeSVGTitleElement>; }
interface ddeSVGTSpanElement extends SVGTSpanElement{ append: ddeAppend<ddeSVGTSpanElement>; }
interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend<ddeSVGUseElement>; }
interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend<ddeSVGViewElement>; }
// editorconfig-checker-enable

905
dist/esm.d.ts vendored
View File

@ -1,46 +1,118 @@
declare global{ /* ddeSignal */ } // Generated by dts-bundle-generator v9.5.1
type CustomElementTagNameMap= { '#text': Text, '#comment': Comment }
type SupportedElement= export interface Signal<V, A> {
HTMLElementTagNameMap[keyof HTMLElementTagNameMap] /** The current value of the signal */
| SVGElementTagNameMap[keyof SVGElementTagNameMap] get(): V;
| MathMLElementTagNameMap[keyof MathMLElementTagNameMap] /** Set new value of the signal */
| CustomElementTagNameMap[keyof CustomElementTagNameMap] set(value: V): V;
declare global { toJSON(): V;
type ddeComponentAttributes= Record<any, any> | undefined; valueOf(): V;
type ddeElementAddon<El extends SupportedElement | DocumentFragment | Node>= (element: El)=> any;
type ddeString= string | ddeSignal<string>
type ddeStringable= ddeString | number | ddeSignal<number>
} }
type PascalCase= export type Action<V> = (this: {
`${Capitalize<string>}${string}`; value: V;
type AttrsModified= { stopPropagation(): void;
}, ...a: any[]) => typeof signal._ | void;
//type SymbolSignal= Symbol;
export type SymbolOnclear = symbol;
export type Actions<V> = Record<string | SymbolOnclear, Action<V>>;
export type OnListenerOptions = Pick<AddEventListenerOptions, "signal"> & {
first_time?: boolean;
};
export interface signal {
_: Symbol;
/**
* Computations signal. This creates a signal which is computed from other signals.
* */
<V extends () => any>(computation: V): Signal<ReturnType<V>, {}>;
/**
* Simple example:
* ```js
* const hello= S("Hello Signal");
* ```
* simple todo signal:
* ```js
* const todos= S([], {
* add(v){ this.value.push(S(v)); },
* remove(i){ this.value.splice(i, 1); },
* [S.symbols.onclear](){ S.clear(...this.value); },
* });
* ```
* computed signal:
* ```js
* const name= S("Jan");
* const surname= S("Andrle");
* const fullname= S(()=> name.get()+" "+surname.get());
* ```
* @param value Initial signal value. Or function computing value from other signals.
* @param actions Use to define actions on the signal. Such as add item to the array.
* There is also a reserved function `S.symbol.onclear` which is called when the signal is cleared
* by `S.clear`.
* */
<V, A extends Actions<V>>(value: V, actions?: A): Signal<V, A>;
action<S extends Signal<any, Actions<any>>, A extends (S extends Signal<any, infer A> ? A : never), N extends keyof A>(signal: S, name: N, ...params: A[N] extends (...args: infer P) => any ? P : never): void;
clear(...signals: Signal<any, any>[]): void;
on<T>(signal: Signal<T, any>, onchange: (a: T) => void, options?: OnListenerOptions): void;
symbols: {
//signal: SymbolSignal;
onclear: SymbolOnclear;
};
/**
* Reactive element, which is rendered based on the given signal.
* ```js
* S.el(signal, value=> value ? el("b", "True") : el("i", "False"));
* S.el(listS, list=> list.map(li=> el("li", li)));
* ```
* */
el<S extends any>(signal: Signal<S, any>, el: (v: S) => Element | Element[] | DocumentFragment): DocumentFragment;
observedAttributes(custom_element: HTMLElement): Record<string, Signal<string, {}>>;
}
declare const signal: signal;
declare global {
type ddeSignal<T, A = {}> = Signal<T, A>;
type ddeAction<V> = Action<V>;
type ddeActions<V> = Actions<V>;
}
export type CustomElementTagNameMap = {
"#text": Text;
"#comment": Comment;
};
export type SupportedElement = HTMLElementTagNameMap[keyof HTMLElementTagNameMap] | SVGElementTagNameMap[keyof SVGElementTagNameMap] | MathMLElementTagNameMap[keyof MathMLElementTagNameMap] | CustomElementTagNameMap[keyof CustomElementTagNameMap];
declare global {
type ddeComponentAttributes = Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment | Node> = (element: El) => any;
type ddeString = string | Signal<string, {}>;
type ddeStringable = ddeString | number | Signal<number, {}>;
}
export type PascalCase = `${Capitalize<string>}${string}`;
export type AttrsModified = {
/** /**
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API). * Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/ */
style: Partial<CSSStyleDeclaration> | ddeString style: Partial<CSSStyleDeclaration> | ddeString | Partial<{
| Partial<{ [K in keyof CSSStyleDeclaration]: ddeSignal<CSSStyleDeclaration[K]> }> [K in keyof CSSStyleDeclaration]: Signal<CSSStyleDeclaration[K], {}>;
}>;
/** /**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. * Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1.
* In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` * In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))`
* for others. * for others.
*/ */
classList: Record<string,-1|0|1|boolean|ddeSignal<-1|0|1|boolean>>, classList: Record<string, -1 | 0 | 1 | boolean | Signal<-1 | 0 | 1 | boolean, {}>>;
/** /**
* Used by the dataset HTML attribute to represent data for custom attributes added to elements. * Used by the dataset HTML attribute to represent data for custom attributes added to elements.
* Values are converted to string (see {@link DOMStringMap}). * Values are converted to string (see {@link DOMStringMap}).
* *
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMStringMap) * [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMStringMap)
* */ * */
dataset: Record<string, ddeStringable>, dataset: Record<string, ddeStringable>;
/** /**
* Sets `aria-*` simiraly to `dataset` * Sets `aria-*` simiraly to `dataset`
* */ * */
ariaset: Record<string, ddeString>, ariaset: Record<string, ddeString>;
} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, ddeString> } & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, ddeString> & Record<`.${string}`, any>;
& Record<`.${string}`, any> export type _fromElsInterfaces<EL extends SupportedElement> = Omit<EL, keyof AttrsModified>;
type _fromElsInterfaces<EL extends SupportedElement>= Omit<EL, keyof AttrsModified>; export type IsReadonly<T, K extends keyof T> = T extends {
type IsReadonly<T, K extends keyof T> = readonly [P in K]: T[K];
T extends { readonly [P in K]: T[K] } ? true : false; } ? true : false;
/** /**
* Just element attributtes * Just element attributtes
* *
@ -51,199 +123,132 @@ type IsReadonly<T, K extends keyof T> =
* There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives. * There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives.
* @private * @private
*/ */
type ElementAttributes<T extends SupportedElement>= Partial<{ export type ElementAttributes<T extends SupportedElement> = Partial<{
[K in keyof _fromElsInterfaces<T>]: IsReadonly<_fromElsInterfaces<T>, K> extends false [K in keyof _fromElsInterfaces<T>]: _fromElsInterfaces<T>[K] extends ((...p: any[]) => any) ? _fromElsInterfaces<T>[K] | ((...p: Parameters<_fromElsInterfaces<T>[K]>) => Signal<ReturnType<_fromElsInterfaces<T>[K]>, {}>) : (IsReadonly<_fromElsInterfaces<T>, K> extends false ? _fromElsInterfaces<T>[K] | Signal<_fromElsInterfaces<T>[K], {}> : ddeStringable);
? _fromElsInterfaces<T>[K] | ddeSignal<_fromElsInterfaces<T>[K]>
: ddeStringable
} & AttrsModified> & Record<string, any>; } & AttrsModified> & Record<string, any>;
export function classListDeclarative<El extends SupportedElement>( export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El;
element: El, export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El;
classList: AttrsModified["classList"] export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT];
): El export type ExtendedHTMLElementTagNameMap = HTMLElementTagNameMap & CustomElementTagNameMap;
export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El export namespace el {
export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>( /**
element: El, * Creates a marker comment for elements
attr: ATT, *
value: ElementAttributes<El>[ATT] * @param attrs - Marker attributes
): ElementAttributes<El>[ATT] * @param [is_open=false] - Whether the marker is open-ended
* @returns Comment node marker
type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap; */
export function el< export function mark(attrs: {
TAG extends keyof ExtendedHTMLElementTagNameMap, type: "component" | "reactive" | "later";
>( name?: string;
tag_name: TAG, host?: "this" | "parentElement";
attrs?: ElementAttributes<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]> | ddeStringable, }, is_open?: boolean): Comment;
...addons: ddeElementAddon< }
ExtendedHTMLElementTagNameMap[NoInfer<TAG>] export function el<A extends ddeComponentAttributes, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>, ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
>[], // TODO: for now addons must have the same element export function el<A extends {
): TAG extends keyof ddeHTMLElementTagNameMap ? ddeHTMLElementTagNameMap[TAG] : ddeHTMLElement textContent: ddeStringable;
export function el( }, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>["textContent"], ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
tag_name?: "<>", export function el<TAG extends keyof ExtendedHTMLElementTagNameMap>(tag_name: TAG, attrs?: ElementAttributes<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]> | ddeStringable, ...addons: ddeElementAddon<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]>[]): TAG extends keyof ddeHTMLElementTagNameMap ? ddeHTMLElementTagNameMap[TAG] : ddeHTMLElement;
): ddeDocumentFragment export function el(tag_name?: "<>"): ddeDocumentFragment;
export function el( export function el(tag_name: string, attrs?: ElementAttributes<HTMLElement> | ddeStringable, ...addons: ddeElementAddon<HTMLElement>[]): ddeHTMLElement;
tag_name: string, export function elNS(namespace: "http://www.w3.org/2000/svg"): <TAG extends keyof SVGElementTagNameMap & string, EL extends (TAG extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[TAG] : SVGElement)>(tag_name: TAG, attrs?: ElementAttributes<NoInfer<EL>> | ddeStringable, ...addons: ddeElementAddon<NoInfer<EL>>[]) => TAG extends keyof ddeSVGElementTagNameMap ? ddeSVGElementTagNameMap[TAG] : ddeSVGElement;
attrs?: ElementAttributes<HTMLElement> | ddeStringable, export function elNS(namespace: "http://www.w3.org/1998/Math/MathML"): <TAG extends keyof MathMLElementTagNameMap & string, EL extends (TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement)>(tag_name: TAG, attrs?: ddeStringable | Partial<{
...addons: ddeElementAddon<HTMLElement>[] [key in keyof EL]: EL[key] | Signal<EL[key], {}> | string | number | boolean;
): ddeHTMLElement }>, ...addons: ddeElementAddon<NoInfer<EL>>[]) => ddeMathMLElement;
export function elNS(namespace: string): (tag_name: string, attrs?: string | ddeStringable | Record<string, any>, ...addons: ddeElementAddon<SupportedElement>[]) => SupportedElement;
export function el<
C extends (attr: ddeComponentAttributes)=> SupportedElement | ddeDocumentFragment
>(
component: C,
attrs?: Parameters<C>[0] | ddeStringable,
...addons: ddeElementAddon<ReturnType<C>>[]
): ReturnType<C> extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap]
? ReturnType<C>
: ( ReturnType<C> extends ddeDocumentFragment ? ReturnType<C> : ddeHTMLElement )
export { el as createElement }
export function elNS(
namespace: "http://www.w3.org/2000/svg"
): <
TAG extends keyof SVGElementTagNameMap & string,
EL extends ( TAG extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[TAG] : SVGElement ),
>(
tag_name: TAG,
attrs?: ElementAttributes<NoInfer<EL>> | ddeStringable,
...addons: ddeElementAddon<NoInfer<EL>>[]
)=> TAG extends keyof ddeSVGElementTagNameMap ? ddeSVGElementTagNameMap[TAG] : ddeSVGElement
export function elNS(
namespace: "http://www.w3.org/1998/Math/MathML"
): <
TAG extends keyof MathMLElementTagNameMap & string,
EL extends ( TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement ),
>(
tag_name: TAG,
attrs?: ddeStringable | Partial<{
[key in keyof EL]: EL[key] | ddeSignal<EL[key]> | string | number | boolean
}>,
...addons: ddeElementAddon<NoInfer<EL>>[]
)=> ddeMathMLElement
export function elNS(
namespace: string
): (
tag_name: string,
attrs?: string | ddeStringable | Record<string, any>,
...addons: ddeElementAddon<SupportedElement>[]
)=> SupportedElement
export { elNS as createElementNS }
export function chainableAppend<EL extends SupportedElement>(el: EL): EL; export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
/** Simulate slots for ddeComponents */ /** Simulate slots for ddeComponents */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>( export function simulateSlots<EL extends SupportedElement | DocumentFragment>(root: EL): EL;
root: EL,
): EL
/** /**
* Simulate slots in Custom Elements without using `shadowRoot`. * Simulate slots in Custom Elements without using `shadowRoot`.
* @param el Custom Element root element * @param el Custom Element root element
* @param body Body of the custom element * @param body Body of the custom element
* */ * */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>( export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: HTMLElement, body: EL): EL;
el: HTMLElement, declare function dispatchEvent$1(name: keyof DocumentEventMap | string, element: SupportedElement): (data?: any) => void;
body: EL, declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options?: EventInit): (element: SupportedElement, data?: any) => void;
): EL declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, element: SupportedElement | (() => SupportedElement)): (data?: any) => void;
export interface On {
export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit):
(element: SupportedElement, data?: any)=> void;
export function dispatchEvent(
name: keyof DocumentEventMap | string,
options: EventInit | null,
element: SupportedElement | (()=> SupportedElement)
): (data?: any)=> void;
interface On{
/** Listens to the DOM event. See {@link Document.addEventListener} */ /** Listens to the DOM event. See {@link Document.addEventListener} */
< <Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE;
Event extends keyof DocumentEventMap, <EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE;
EE extends ddeElementAddon<SupportedElement>= ddeElementAddon<HTMLElement>, /** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
>( connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE;
type: Event, /** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE;
options?: AddEventListenerOptions /** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
) : EE; attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[
< string,
EE extends ddeElementAddon<SupportedElement>= ddeElementAddon<HTMLElement>, string
>( ]>) => any, options?: AddEventListenerOptions): EE;
type: string,
listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent ) => any,
options?: AddEventListenerOptions
) : EE;
/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line
connected<
EE extends ddeElementAddon<SupportedElement>,
El extends ( EE extends ddeElementAddon<infer El> ? El : never )
>(
listener: (this: El, event: CustomEvent<El>) => any,
options?: AddEventListenerOptions
) : EE;
/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line
disconnected<
EE extends ddeElementAddon<SupportedElement>,
El extends ( EE extends ddeElementAddon<infer El> ? El : never )
>(
listener: (this: El, event: CustomEvent<void>) => any,
options?: AddEventListenerOptions
) : EE;
/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */// editorconfig-checker-disable-line
attributeChanged<
EE extends ddeElementAddon<SupportedElement>,
El extends ( EE extends ddeElementAddon<infer El> ? El : never )
>(
listener: (this: El, event: CustomEvent<[ string, string ]>) => any,
options?: AddEventListenerOptions
) : EE;
} }
export const on: On; export const on: On;
export type Scope = {
type Scope= { scope: Node | Function | Object;
scope: Node | Function | Object, host: ddeElementAddon<any>;
host: ddeElementAddon<any>, custom_element: false | HTMLElement;
custom_element: false | HTMLElement, prevent: boolean;
prevent: boolean
}; };
/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */ /** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */
export const scope: { export const scope: {
current: Scope, current: Scope;
/** Stops all automatizations. E. g. signals used as attributes in current scope /** Stops all automatizations. E. g. signals used as attributes in current scope
* registers removing these listeners (and clean signal if no other listeners are detected) * registers removing these listeners (and clean signal if no other listeners are detected)
* on `disconnected` event. */ * on `disconnected` event. */
preventDefault<T extends boolean>(prevent: T): T, preventDefault<T extends boolean>(prevent: T): T;
/** /**
* This represents reference to the current host element `scope.host()`. * This represents reference to the current host element `scope.host()`.
* It can be also used to register Addon(s) (functions to be called when component is initized) * It can be also used to register Addon(s) (functions to be called when component is initized)
* `scope.host(on.connected(console.log))`. * `scope.host(on.connected(console.log))`.
* */ * */
host: (...addons: ddeElementAddon<SupportedElement>[])=> HTMLElement, host: (...addons: ddeElementAddon<SupportedElement>[]) => HTMLElement;
state: Scope[];
state: Scope[],
/** Adds new child scope. All attributes are inherited by default. */ /** Adds new child scope. All attributes are inherited by default. */
push(scope: Partial<Scope>): ReturnType<Array<Scope>["push"]>, push(scope?: Partial<Scope>): ReturnType<Array<Scope>["push"]>;
/** Adds root scope as a child of the current scope. */ /** Adds root scope as a child of the current scope. */
pushRoot(): ReturnType<Array<Scope>["push"]>, pushRoot(): ReturnType<Array<Scope>["push"]>;
/** Removes last/current child scope. */ /** Removes last/current child scope. */
pop(): ReturnType<Array<Scope>["pop"]>, pop(): ReturnType<Array<Scope>["pop"]>;
}; };
export function customElementRender<EL extends HTMLElement, P extends any = Record<string, string | Signal<string, {}>>>(target: ShadowRoot | EL, render: (props: P) => SupportedElement | DocumentFragment, props?: P | ((el: EL) => P)): EL;
export function customElementRender< export function customElementWithDDE<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
EL extends HTMLElement, export function lifecyclesToEvents<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
P extends any = Record<string, string | ddeSignal<string>> export function observedAttributes(custom_element: HTMLElement): Record<string, string>;
>( /**
target: ShadowRoot | EL, * This is used primarly for server side rendering. To be sure that all async operations
render: (props: P)=> SupportedElement | DocumentFragment, * are finished before the page is sent to the client.
props?: P | ((el: EL)=> P) * ```
): EL * // on component
export function customElementWithDDE<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL * function component(){
export function lifecyclesToEvents<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL *
export function observedAttributes(custom_element: HTMLElement): Record<string, string> * queue(fetch(...).then(...));
* }
*
* // building the page
* async function build(){
* const { component }= await import("./component.js");
* document.body.append(el(component));
* await queue();
* retutn document.body.innerHTML;
* }
* ```
* */
export function queue(promise?: Promise<unknown>): Promise<unknown>;
/* TypeScript MEH */ /* TypeScript MEH */
declare global{ declare global {
type ddeAppend<el>= (...nodes: (Node | string)[])=> el; type ddeAppend<el> = (...nodes: (Node | string)[]) => el;
interface ddeDocumentFragment extends DocumentFragment {
interface ddeDocumentFragment extends DocumentFragment{ append: ddeAppend<ddeDocumentFragment>; } append: ddeAppend<ddeDocumentFragment>;
interface ddeHTMLElement extends HTMLElement{ append: ddeAppend<ddeHTMLElement>; } }
interface ddeSVGElement extends SVGElement{ append: ddeAppend<ddeSVGElement>; } interface ddeHTMLElement extends HTMLElement {
interface ddeMathMLElement extends MathMLElement{ append: ddeAppend<ddeMathMLElement>; } append: ddeAppend<ddeHTMLElement>;
}
interface ddeSVGElement extends SVGElement {
append: ddeAppend<ddeSVGElement>;
}
interface ddeMathMLElement extends MathMLElement {
append: ddeAppend<ddeMathMLElement>;
}
interface ddeHTMLElementTagNameMap { interface ddeHTMLElementTagNameMap {
"a": ddeHTMLAnchorElement; "a": ddeHTMLAnchorElement;
"area": ddeHTMLAreaElement; "area": ddeHTMLAreaElement;
@ -385,133 +390,393 @@ declare global{
"view": ddeSVGViewElement; "view": ddeSVGViewElement;
} }
} }
// editorconfig-checker-disable // editorconfig-checker-disable
interface ddeHTMLAnchorElement extends HTMLAnchorElement{ append: ddeAppend<ddeHTMLAnchorElement>; } export interface ddeHTMLAnchorElement extends HTMLAnchorElement {
interface ddeHTMLAreaElement extends HTMLAreaElement{ append: ddeAppend<ddeHTMLAreaElement>; } append: ddeAppend<ddeHTMLAnchorElement>;
interface ddeHTMLAudioElement extends HTMLAudioElement{ append: ddeAppend<ddeHTMLAudioElement>; } }
interface ddeHTMLBaseElement extends HTMLBaseElement{ append: ddeAppend<ddeHTMLBaseElement>; } export interface ddeHTMLAreaElement extends HTMLAreaElement {
interface ddeHTMLQuoteElement extends HTMLQuoteElement{ append: ddeAppend<ddeHTMLQuoteElement>; } append: ddeAppend<ddeHTMLAreaElement>;
interface ddeHTMLBodyElement extends HTMLBodyElement{ append: ddeAppend<ddeHTMLBodyElement>; } }
interface ddeHTMLBRElement extends HTMLBRElement{ append: ddeAppend<ddeHTMLBRElement>; } export interface ddeHTMLAudioElement extends HTMLAudioElement {
interface ddeHTMLButtonElement extends HTMLButtonElement{ append: ddeAppend<ddeHTMLButtonElement>; } append: ddeAppend<ddeHTMLAudioElement>;
interface ddeHTMLCanvasElement extends HTMLCanvasElement{ append: ddeAppend<ddeHTMLCanvasElement>; } }
interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement{ append: ddeAppend<ddeHTMLTableCaptionElement>; } export interface ddeHTMLBaseElement extends HTMLBaseElement {
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; } append: ddeAppend<ddeHTMLBaseElement>;
interface ddeHTMLTableColElement extends HTMLTableColElement{ append: ddeAppend<ddeHTMLTableColElement>; } }
interface ddeHTMLDataElement extends HTMLDataElement{ append: ddeAppend<ddeHTMLDataElement>; } export interface ddeHTMLQuoteElement extends HTMLQuoteElement {
interface ddeHTMLDataListElement extends HTMLDataListElement{ append: ddeAppend<ddeHTMLDataListElement>; } append: ddeAppend<ddeHTMLQuoteElement>;
interface ddeHTMLModElement extends HTMLModElement{ append: ddeAppend<ddeHTMLModElement>; } }
interface ddeHTMLDetailsElement extends HTMLDetailsElement{ append: ddeAppend<ddeHTMLDetailsElement>; } export interface ddeHTMLBodyElement extends HTMLBodyElement {
interface ddeHTMLDialogElement extends HTMLDialogElement{ append: ddeAppend<ddeHTMLDialogElement>; } append: ddeAppend<ddeHTMLBodyElement>;
interface ddeHTMLDivElement extends HTMLDivElement{ append: ddeAppend<ddeHTMLDivElement>; } }
interface ddeHTMLDListElement extends HTMLDListElement{ append: ddeAppend<ddeHTMLDListElement>; } export interface ddeHTMLBRElement extends HTMLBRElement {
interface ddeHTMLEmbedElement extends HTMLEmbedElement{ append: ddeAppend<ddeHTMLEmbedElement>; } append: ddeAppend<ddeHTMLBRElement>;
interface ddeHTMLFieldSetElement extends HTMLFieldSetElement{ append: ddeAppend<ddeHTMLFieldSetElement>; } }
interface ddeHTMLFormElement extends HTMLFormElement{ append: ddeAppend<ddeHTMLFormElement>; } export interface ddeHTMLButtonElement extends HTMLButtonElement {
interface ddeHTMLHeadingElement extends HTMLHeadingElement{ append: ddeAppend<ddeHTMLHeadingElement>; } append: ddeAppend<ddeHTMLButtonElement>;
interface ddeHTMLHeadElement extends HTMLHeadElement{ append: ddeAppend<ddeHTMLHeadElement>; } }
interface ddeHTMLHRElement extends HTMLHRElement{ append: ddeAppend<ddeHTMLHRElement>; } export interface ddeHTMLCanvasElement extends HTMLCanvasElement {
interface ddeHTMLHtmlElement extends HTMLHtmlElement{ append: ddeAppend<ddeHTMLHtmlElement>; } append: ddeAppend<ddeHTMLCanvasElement>;
interface ddeHTMLIFrameElement extends HTMLIFrameElement{ append: ddeAppend<ddeHTMLIFrameElement>; } }
interface ddeHTMLImageElement extends HTMLImageElement{ append: ddeAppend<ddeHTMLImageElement>; } export interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement {
interface ddeHTMLInputElement extends HTMLInputElement{ append: ddeAppend<ddeHTMLInputElement>; } append: ddeAppend<ddeHTMLTableCaptionElement>;
interface ddeHTMLLabelElement extends HTMLLabelElement{ append: ddeAppend<ddeHTMLLabelElement>; } }
interface ddeHTMLLegendElement extends HTMLLegendElement{ append: ddeAppend<ddeHTMLLegendElement>; } export interface ddeHTMLTableColElement extends HTMLTableColElement {
interface ddeHTMLLIElement extends HTMLLIElement{ append: ddeAppend<ddeHTMLLIElement>; } append: ddeAppend<ddeHTMLTableColElement>;
interface ddeHTMLLinkElement extends HTMLLinkElement{ append: ddeAppend<ddeHTMLLinkElement>; } }
interface ddeHTMLMapElement extends HTMLMapElement{ append: ddeAppend<ddeHTMLMapElement>; } export interface ddeHTMLTableColElement extends HTMLTableColElement {
interface ddeHTMLMenuElement extends HTMLMenuElement{ append: ddeAppend<ddeHTMLMenuElement>; } append: ddeAppend<ddeHTMLTableColElement>;
interface ddeHTMLMetaElement extends HTMLMetaElement{ append: ddeAppend<ddeHTMLMetaElement>; } }
interface ddeHTMLMeterElement extends HTMLMeterElement{ append: ddeAppend<ddeHTMLMeterElement>; } export interface ddeHTMLDataElement extends HTMLDataElement {
interface ddeHTMLObjectElement extends HTMLObjectElement{ append: ddeAppend<ddeHTMLObjectElement>; } append: ddeAppend<ddeHTMLDataElement>;
interface ddeHTMLOListElement extends HTMLOListElement{ append: ddeAppend<ddeHTMLOListElement>; } }
interface ddeHTMLOptGroupElement extends HTMLOptGroupElement{ append: ddeAppend<ddeHTMLOptGroupElement>; } export interface ddeHTMLDataListElement extends HTMLDataListElement {
interface ddeHTMLOptionElement extends HTMLOptionElement{ append: ddeAppend<ddeHTMLOptionElement>; } append: ddeAppend<ddeHTMLDataListElement>;
interface ddeHTMLOutputElement extends HTMLOutputElement{ append: ddeAppend<ddeHTMLOutputElement>; } }
interface ddeHTMLParagraphElement extends HTMLParagraphElement{ append: ddeAppend<ddeHTMLParagraphElement>; } export interface ddeHTMLModElement extends HTMLModElement {
interface ddeHTMLPictureElement extends HTMLPictureElement{ append: ddeAppend<ddeHTMLPictureElement>; } append: ddeAppend<ddeHTMLModElement>;
interface ddeHTMLPreElement extends HTMLPreElement{ append: ddeAppend<ddeHTMLPreElement>; } }
interface ddeHTMLProgressElement extends HTMLProgressElement{ append: ddeAppend<ddeHTMLProgressElement>; } export interface ddeHTMLDetailsElement extends HTMLDetailsElement {
interface ddeHTMLScriptElement extends HTMLScriptElement{ append: ddeAppend<ddeHTMLScriptElement>; } append: ddeAppend<ddeHTMLDetailsElement>;
interface ddeHTMLSelectElement extends HTMLSelectElement{ append: ddeAppend<ddeHTMLSelectElement>; } }
interface ddeHTMLSlotElement extends HTMLSlotElement{ append: ddeAppend<ddeHTMLSlotElement>; } export interface ddeHTMLDialogElement extends HTMLDialogElement {
interface ddeHTMLSourceElement extends HTMLSourceElement{ append: ddeAppend<ddeHTMLSourceElement>; } append: ddeAppend<ddeHTMLDialogElement>;
interface ddeHTMLSpanElement extends HTMLSpanElement{ append: ddeAppend<ddeHTMLSpanElement>; } }
interface ddeHTMLStyleElement extends HTMLStyleElement{ append: ddeAppend<ddeHTMLStyleElement>; } export interface ddeHTMLDivElement extends HTMLDivElement {
interface ddeHTMLTableElement extends HTMLTableElement{ append: ddeAppend<ddeHTMLTableElement>; } append: ddeAppend<ddeHTMLDivElement>;
interface ddeHTMLTableSectionElement extends HTMLTableSectionElement{ append: ddeAppend<ddeHTMLTableSectionElement>; } }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; } export interface ddeHTMLDListElement extends HTMLDListElement {
interface ddeHTMLTemplateElement extends HTMLTemplateElement{ append: ddeAppend<ddeHTMLTemplateElement>; } append: ddeAppend<ddeHTMLDListElement>;
interface ddeHTMLTextAreaElement extends HTMLTextAreaElement{ append: ddeAppend<ddeHTMLTextAreaElement>; } }
interface ddeHTMLTableCellElement extends HTMLTableCellElement{ append: ddeAppend<ddeHTMLTableCellElement>; } export interface ddeHTMLEmbedElement extends HTMLEmbedElement {
interface ddeHTMLTimeElement extends HTMLTimeElement{ append: ddeAppend<ddeHTMLTimeElement>; } append: ddeAppend<ddeHTMLEmbedElement>;
interface ddeHTMLTitleElement extends HTMLTitleElement{ append: ddeAppend<ddeHTMLTitleElement>; } }
interface ddeHTMLTableRowElement extends HTMLTableRowElement{ append: ddeAppend<ddeHTMLTableRowElement>; } export interface ddeHTMLFieldSetElement extends HTMLFieldSetElement {
interface ddeHTMLTrackElement extends HTMLTrackElement{ append: ddeAppend<ddeHTMLTrackElement>; } append: ddeAppend<ddeHTMLFieldSetElement>;
interface ddeHTMLUListElement extends HTMLUListElement{ append: ddeAppend<ddeHTMLUListElement>; } }
interface ddeHTMLVideoElement extends HTMLVideoElement{ append: ddeAppend<ddeHTMLVideoElement>; } export interface ddeHTMLFormElement extends HTMLFormElement {
interface ddeSVGAElement extends SVGAElement{ append: ddeAppend<ddeSVGAElement>; } append: ddeAppend<ddeHTMLFormElement>;
interface ddeSVGAnimateElement extends SVGAnimateElement{ append: ddeAppend<ddeSVGAnimateElement>; } }
interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement{ append: ddeAppend<ddeSVGAnimateMotionElement>; } export interface ddeHTMLHeadingElement extends HTMLHeadingElement {
interface ddeSVGAnimateTransformElement extends SVGAnimateTransformElement{ append: ddeAppend<ddeSVGAnimateTransformElement>; } append: ddeAppend<ddeHTMLHeadingElement>;
interface ddeSVGCircleElement extends SVGCircleElement{ append: ddeAppend<ddeSVGCircleElement>; } }
interface ddeSVGClipPathElement extends SVGClipPathElement{ append: ddeAppend<ddeSVGClipPathElement>; } export interface ddeHTMLHeadElement extends HTMLHeadElement {
interface ddeSVGDefsElement extends SVGDefsElement{ append: ddeAppend<ddeSVGDefsElement>; } append: ddeAppend<ddeHTMLHeadElement>;
interface ddeSVGDescElement extends SVGDescElement{ append: ddeAppend<ddeSVGDescElement>; } }
interface ddeSVGEllipseElement extends SVGEllipseElement{ append: ddeAppend<ddeSVGEllipseElement>; } export interface ddeHTMLHRElement extends HTMLHRElement {
interface ddeSVGFEBlendElement extends SVGFEBlendElement{ append: ddeAppend<ddeSVGFEBlendElement>; } append: ddeAppend<ddeHTMLHRElement>;
interface ddeSVGFEColorMatrixElement extends SVGFEColorMatrixElement{ append: ddeAppend<ddeSVGFEColorMatrixElement>; } }
interface ddeSVGFEComponentTransferElement extends SVGFEComponentTransferElement{ append: ddeAppend<ddeSVGFEComponentTransferElement>; } export interface ddeHTMLHtmlElement extends HTMLHtmlElement {
interface ddeSVGFECompositeElement extends SVGFECompositeElement{ append: ddeAppend<ddeSVGFECompositeElement>; } append: ddeAppend<ddeHTMLHtmlElement>;
interface ddeSVGFEConvolveMatrixElement extends SVGFEConvolveMatrixElement{ append: ddeAppend<ddeSVGFEConvolveMatrixElement>; } }
interface ddeSVGFEDiffuseLightingElement extends SVGFEDiffuseLightingElement{ append: ddeAppend<ddeSVGFEDiffuseLightingElement>; } export interface ddeHTMLIFrameElement extends HTMLIFrameElement {
interface ddeSVGFEDisplacementMapElement extends SVGFEDisplacementMapElement{ append: ddeAppend<ddeSVGFEDisplacementMapElement>; } append: ddeAppend<ddeHTMLIFrameElement>;
interface ddeSVGFEDistantLightElement extends SVGFEDistantLightElement{ append: ddeAppend<ddeSVGFEDistantLightElement>; } }
interface ddeSVGFEDropShadowElement extends SVGFEDropShadowElement{ append: ddeAppend<ddeSVGFEDropShadowElement>; } export interface ddeHTMLImageElement extends HTMLImageElement {
interface ddeSVGFEFloodElement extends SVGFEFloodElement{ append: ddeAppend<ddeSVGFEFloodElement>; } append: ddeAppend<ddeHTMLImageElement>;
interface ddeSVGFEFuncAElement extends SVGFEFuncAElement{ append: ddeAppend<ddeSVGFEFuncAElement>; } }
interface ddeSVGFEFuncBElement extends SVGFEFuncBElement{ append: ddeAppend<ddeSVGFEFuncBElement>; } export interface ddeHTMLInputElement extends HTMLInputElement {
interface ddeSVGFEFuncGElement extends SVGFEFuncGElement{ append: ddeAppend<ddeSVGFEFuncGElement>; } append: ddeAppend<ddeHTMLInputElement>;
interface ddeSVGFEFuncRElement extends SVGFEFuncRElement{ append: ddeAppend<ddeSVGFEFuncRElement>; } }
interface ddeSVGFEGaussianBlurElement extends SVGFEGaussianBlurElement{ append: ddeAppend<ddeSVGFEGaussianBlurElement>; } export interface ddeHTMLLabelElement extends HTMLLabelElement {
interface ddeSVGFEImageElement extends SVGFEImageElement{ append: ddeAppend<ddeSVGFEImageElement>; } append: ddeAppend<ddeHTMLLabelElement>;
interface ddeSVGFEMergeElement extends SVGFEMergeElement{ append: ddeAppend<ddeSVGFEMergeElement>; } }
interface ddeSVGFEMergeNodeElement extends SVGFEMergeNodeElement{ append: ddeAppend<ddeSVGFEMergeNodeElement>; } export interface ddeHTMLLegendElement extends HTMLLegendElement {
interface ddeSVGFEMorphologyElement extends SVGFEMorphologyElement{ append: ddeAppend<ddeSVGFEMorphologyElement>; } append: ddeAppend<ddeHTMLLegendElement>;
interface ddeSVGFEOffsetElement extends SVGFEOffsetElement{ append: ddeAppend<ddeSVGFEOffsetElement>; } }
interface ddeSVGFEPointLightElement extends SVGFEPointLightElement{ append: ddeAppend<ddeSVGFEPointLightElement>; } export interface ddeHTMLLIElement extends HTMLLIElement {
interface ddeSVGFESpecularLightingElement extends SVGFESpecularLightingElement{ append: ddeAppend<ddeSVGFESpecularLightingElement>; } append: ddeAppend<ddeHTMLLIElement>;
interface ddeSVGFESpotLightElement extends SVGFESpotLightElement{ append: ddeAppend<ddeSVGFESpotLightElement>; } }
interface ddeSVGFETileElement extends SVGFETileElement{ append: ddeAppend<ddeSVGFETileElement>; } export interface ddeHTMLLinkElement extends HTMLLinkElement {
interface ddeSVGFETurbulenceElement extends SVGFETurbulenceElement{ append: ddeAppend<ddeSVGFETurbulenceElement>; } append: ddeAppend<ddeHTMLLinkElement>;
interface ddeSVGFilterElement extends SVGFilterElement{ append: ddeAppend<ddeSVGFilterElement>; } }
interface ddeSVGForeignObjectElement extends SVGForeignObjectElement{ append: ddeAppend<ddeSVGForeignObjectElement>; } export interface ddeHTMLMapElement extends HTMLMapElement {
interface ddeSVGGElement extends SVGGElement{ append: ddeAppend<ddeSVGGElement>; } append: ddeAppend<ddeHTMLMapElement>;
interface ddeSVGImageElement extends SVGImageElement{ append: ddeAppend<ddeSVGImageElement>; } }
interface ddeSVGLineElement extends SVGLineElement{ append: ddeAppend<ddeSVGLineElement>; } export interface ddeHTMLMenuElement extends HTMLMenuElement {
interface ddeSVGLinearGradientElement extends SVGLinearGradientElement{ append: ddeAppend<ddeSVGLinearGradientElement>; } append: ddeAppend<ddeHTMLMenuElement>;
interface ddeSVGMarkerElement extends SVGMarkerElement{ append: ddeAppend<ddeSVGMarkerElement>; } }
interface ddeSVGMaskElement extends SVGMaskElement{ append: ddeAppend<ddeSVGMaskElement>; } export interface ddeHTMLMetaElement extends HTMLMetaElement {
interface ddeSVGMetadataElement extends SVGMetadataElement{ append: ddeAppend<ddeSVGMetadataElement>; } append: ddeAppend<ddeHTMLMetaElement>;
interface ddeSVGMPathElement extends SVGMPathElement{ append: ddeAppend<ddeSVGMPathElement>; } }
interface ddeSVGPathElement extends SVGPathElement{ append: ddeAppend<ddeSVGPathElement>; } export interface ddeHTMLMeterElement extends HTMLMeterElement {
interface ddeSVGPatternElement extends SVGPatternElement{ append: ddeAppend<ddeSVGPatternElement>; } append: ddeAppend<ddeHTMLMeterElement>;
interface ddeSVGPolygonElement extends SVGPolygonElement{ append: ddeAppend<ddeSVGPolygonElement>; } }
interface ddeSVGPolylineElement extends SVGPolylineElement{ append: ddeAppend<ddeSVGPolylineElement>; } export interface ddeHTMLObjectElement extends HTMLObjectElement {
interface ddeSVGRadialGradientElement extends SVGRadialGradientElement{ append: ddeAppend<ddeSVGRadialGradientElement>; } append: ddeAppend<ddeHTMLObjectElement>;
interface ddeSVGRectElement extends SVGRectElement{ append: ddeAppend<ddeSVGRectElement>; } }
interface ddeSVGScriptElement extends SVGScriptElement{ append: ddeAppend<ddeSVGScriptElement>; } export interface ddeHTMLOListElement extends HTMLOListElement {
interface ddeSVGSetElement extends SVGSetElement{ append: ddeAppend<ddeSVGSetElement>; } append: ddeAppend<ddeHTMLOListElement>;
interface ddeSVGStopElement extends SVGStopElement{ append: ddeAppend<ddeSVGStopElement>; } }
interface ddeSVGStyleElement extends SVGStyleElement{ append: ddeAppend<ddeSVGStyleElement>; } export interface ddeHTMLOptGroupElement extends HTMLOptGroupElement {
interface ddeSVGSVGElement extends SVGSVGElement{ append: ddeAppend<ddeSVGSVGElement>; } append: ddeAppend<ddeHTMLOptGroupElement>;
interface ddeSVGSwitchElement extends SVGSwitchElement{ append: ddeAppend<ddeSVGSwitchElement>; } }
interface ddeSVGSymbolElement extends SVGSymbolElement{ append: ddeAppend<ddeSVGSymbolElement>; } export interface ddeHTMLOptionElement extends HTMLOptionElement {
interface ddeSVGTextElement extends SVGTextElement{ append: ddeAppend<ddeSVGTextElement>; } append: ddeAppend<ddeHTMLOptionElement>;
interface ddeSVGTextPathElement extends SVGTextPathElement{ append: ddeAppend<ddeSVGTextPathElement>; } }
interface ddeSVGTitleElement extends SVGTitleElement{ append: ddeAppend<ddeSVGTitleElement>; } export interface ddeHTMLOutputElement extends HTMLOutputElement {
interface ddeSVGTSpanElement extends SVGTSpanElement{ append: ddeAppend<ddeSVGTSpanElement>; } append: ddeAppend<ddeHTMLOutputElement>;
interface ddeSVGUseElement extends SVGUseElement{ append: ddeAppend<ddeSVGUseElement>; } }
interface ddeSVGViewElement extends SVGViewElement{ append: ddeAppend<ddeSVGViewElement>; } export interface ddeHTMLParagraphElement extends HTMLParagraphElement {
// editorconfig-checker-enable append: ddeAppend<ddeHTMLParagraphElement>;
}
export interface ddeHTMLPictureElement extends HTMLPictureElement {
append: ddeAppend<ddeHTMLPictureElement>;
}
export interface ddeHTMLPreElement extends HTMLPreElement {
append: ddeAppend<ddeHTMLPreElement>;
}
export interface ddeHTMLProgressElement extends HTMLProgressElement {
append: ddeAppend<ddeHTMLProgressElement>;
}
export interface ddeHTMLScriptElement extends HTMLScriptElement {
append: ddeAppend<ddeHTMLScriptElement>;
}
export interface ddeHTMLSelectElement extends HTMLSelectElement {
append: ddeAppend<ddeHTMLSelectElement>;
}
export interface ddeHTMLSlotElement extends HTMLSlotElement {
append: ddeAppend<ddeHTMLSlotElement>;
}
export interface ddeHTMLSourceElement extends HTMLSourceElement {
append: ddeAppend<ddeHTMLSourceElement>;
}
export interface ddeHTMLSpanElement extends HTMLSpanElement {
append: ddeAppend<ddeHTMLSpanElement>;
}
export interface ddeHTMLStyleElement extends HTMLStyleElement {
append: ddeAppend<ddeHTMLStyleElement>;
}
export interface ddeHTMLTableElement extends HTMLTableElement {
append: ddeAppend<ddeHTMLTableElement>;
}
export interface ddeHTMLTableSectionElement extends HTMLTableSectionElement {
append: ddeAppend<ddeHTMLTableSectionElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTemplateElement extends HTMLTemplateElement {
append: ddeAppend<ddeHTMLTemplateElement>;
}
export interface ddeHTMLTextAreaElement extends HTMLTextAreaElement {
append: ddeAppend<ddeHTMLTextAreaElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTimeElement extends HTMLTimeElement {
append: ddeAppend<ddeHTMLTimeElement>;
}
export interface ddeHTMLTitleElement extends HTMLTitleElement {
append: ddeAppend<ddeHTMLTitleElement>;
}
export interface ddeHTMLTableRowElement extends HTMLTableRowElement {
append: ddeAppend<ddeHTMLTableRowElement>;
}
export interface ddeHTMLTrackElement extends HTMLTrackElement {
append: ddeAppend<ddeHTMLTrackElement>;
}
export interface ddeHTMLUListElement extends HTMLUListElement {
append: ddeAppend<ddeHTMLUListElement>;
}
export interface ddeHTMLVideoElement extends HTMLVideoElement {
append: ddeAppend<ddeHTMLVideoElement>;
}
export interface ddeSVGAElement extends SVGAElement {
append: ddeAppend<ddeSVGAElement>;
}
export interface ddeSVGAnimateElement extends SVGAnimateElement {
append: ddeAppend<ddeSVGAnimateElement>;
}
export interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement {
append: ddeAppend<ddeSVGAnimateMotionElement>;
}
export interface ddeSVGAnimateTransformElement extends SVGAnimateTransformElement {
append: ddeAppend<ddeSVGAnimateTransformElement>;
}
export interface ddeSVGCircleElement extends SVGCircleElement {
append: ddeAppend<ddeSVGCircleElement>;
}
export interface ddeSVGClipPathElement extends SVGClipPathElement {
append: ddeAppend<ddeSVGClipPathElement>;
}
export interface ddeSVGDefsElement extends SVGDefsElement {
append: ddeAppend<ddeSVGDefsElement>;
}
export interface ddeSVGDescElement extends SVGDescElement {
append: ddeAppend<ddeSVGDescElement>;
}
export interface ddeSVGEllipseElement extends SVGEllipseElement {
append: ddeAppend<ddeSVGEllipseElement>;
}
export interface ddeSVGFEBlendElement extends SVGFEBlendElement {
append: ddeAppend<ddeSVGFEBlendElement>;
}
export interface ddeSVGFEColorMatrixElement extends SVGFEColorMatrixElement {
append: ddeAppend<ddeSVGFEColorMatrixElement>;
}
export interface ddeSVGFEComponentTransferElement extends SVGFEComponentTransferElement {
append: ddeAppend<ddeSVGFEComponentTransferElement>;
}
export interface ddeSVGFECompositeElement extends SVGFECompositeElement {
append: ddeAppend<ddeSVGFECompositeElement>;
}
export interface ddeSVGFEConvolveMatrixElement extends SVGFEConvolveMatrixElement {
append: ddeAppend<ddeSVGFEConvolveMatrixElement>;
}
export interface ddeSVGFEDiffuseLightingElement extends SVGFEDiffuseLightingElement {
append: ddeAppend<ddeSVGFEDiffuseLightingElement>;
}
export interface ddeSVGFEDisplacementMapElement extends SVGFEDisplacementMapElement {
append: ddeAppend<ddeSVGFEDisplacementMapElement>;
}
export interface ddeSVGFEDistantLightElement extends SVGFEDistantLightElement {
append: ddeAppend<ddeSVGFEDistantLightElement>;
}
export interface ddeSVGFEDropShadowElement extends SVGFEDropShadowElement {
append: ddeAppend<ddeSVGFEDropShadowElement>;
}
export interface ddeSVGFEFloodElement extends SVGFEFloodElement {
append: ddeAppend<ddeSVGFEFloodElement>;
}
export interface ddeSVGFEFuncAElement extends SVGFEFuncAElement {
append: ddeAppend<ddeSVGFEFuncAElement>;
}
export interface ddeSVGFEFuncBElement extends SVGFEFuncBElement {
append: ddeAppend<ddeSVGFEFuncBElement>;
}
export interface ddeSVGFEFuncGElement extends SVGFEFuncGElement {
append: ddeAppend<ddeSVGFEFuncGElement>;
}
export interface ddeSVGFEFuncRElement extends SVGFEFuncRElement {
append: ddeAppend<ddeSVGFEFuncRElement>;
}
export interface ddeSVGFEGaussianBlurElement extends SVGFEGaussianBlurElement {
append: ddeAppend<ddeSVGFEGaussianBlurElement>;
}
export interface ddeSVGFEImageElement extends SVGFEImageElement {
append: ddeAppend<ddeSVGFEImageElement>;
}
export interface ddeSVGFEMergeElement extends SVGFEMergeElement {
append: ddeAppend<ddeSVGFEMergeElement>;
}
export interface ddeSVGFEMergeNodeElement extends SVGFEMergeNodeElement {
append: ddeAppend<ddeSVGFEMergeNodeElement>;
}
export interface ddeSVGFEMorphologyElement extends SVGFEMorphologyElement {
append: ddeAppend<ddeSVGFEMorphologyElement>;
}
export interface ddeSVGFEOffsetElement extends SVGFEOffsetElement {
append: ddeAppend<ddeSVGFEOffsetElement>;
}
export interface ddeSVGFEPointLightElement extends SVGFEPointLightElement {
append: ddeAppend<ddeSVGFEPointLightElement>;
}
export interface ddeSVGFESpecularLightingElement extends SVGFESpecularLightingElement {
append: ddeAppend<ddeSVGFESpecularLightingElement>;
}
export interface ddeSVGFESpotLightElement extends SVGFESpotLightElement {
append: ddeAppend<ddeSVGFESpotLightElement>;
}
export interface ddeSVGFETileElement extends SVGFETileElement {
append: ddeAppend<ddeSVGFETileElement>;
}
export interface ddeSVGFETurbulenceElement extends SVGFETurbulenceElement {
append: ddeAppend<ddeSVGFETurbulenceElement>;
}
export interface ddeSVGFilterElement extends SVGFilterElement {
append: ddeAppend<ddeSVGFilterElement>;
}
export interface ddeSVGForeignObjectElement extends SVGForeignObjectElement {
append: ddeAppend<ddeSVGForeignObjectElement>;
}
export interface ddeSVGGElement extends SVGGElement {
append: ddeAppend<ddeSVGGElement>;
}
export interface ddeSVGImageElement extends SVGImageElement {
append: ddeAppend<ddeSVGImageElement>;
}
export interface ddeSVGLineElement extends SVGLineElement {
append: ddeAppend<ddeSVGLineElement>;
}
export interface ddeSVGLinearGradientElement extends SVGLinearGradientElement {
append: ddeAppend<ddeSVGLinearGradientElement>;
}
export interface ddeSVGMarkerElement extends SVGMarkerElement {
append: ddeAppend<ddeSVGMarkerElement>;
}
export interface ddeSVGMaskElement extends SVGMaskElement {
append: ddeAppend<ddeSVGMaskElement>;
}
export interface ddeSVGMetadataElement extends SVGMetadataElement {
append: ddeAppend<ddeSVGMetadataElement>;
}
export interface ddeSVGMPathElement extends SVGMPathElement {
append: ddeAppend<ddeSVGMPathElement>;
}
export interface ddeSVGPathElement extends SVGPathElement {
append: ddeAppend<ddeSVGPathElement>;
}
export interface ddeSVGPatternElement extends SVGPatternElement {
append: ddeAppend<ddeSVGPatternElement>;
}
export interface ddeSVGPolygonElement extends SVGPolygonElement {
append: ddeAppend<ddeSVGPolygonElement>;
}
export interface ddeSVGPolylineElement extends SVGPolylineElement {
append: ddeAppend<ddeSVGPolylineElement>;
}
export interface ddeSVGRadialGradientElement extends SVGRadialGradientElement {
append: ddeAppend<ddeSVGRadialGradientElement>;
}
export interface ddeSVGRectElement extends SVGRectElement {
append: ddeAppend<ddeSVGRectElement>;
}
export interface ddeSVGScriptElement extends SVGScriptElement {
append: ddeAppend<ddeSVGScriptElement>;
}
export interface ddeSVGSetElement extends SVGSetElement {
append: ddeAppend<ddeSVGSetElement>;
}
export interface ddeSVGStopElement extends SVGStopElement {
append: ddeAppend<ddeSVGStopElement>;
}
export interface ddeSVGStyleElement extends SVGStyleElement {
append: ddeAppend<ddeSVGStyleElement>;
}
export interface ddeSVGSVGElement extends SVGSVGElement {
append: ddeAppend<ddeSVGSVGElement>;
}
export interface ddeSVGSwitchElement extends SVGSwitchElement {
append: ddeAppend<ddeSVGSwitchElement>;
}
export interface ddeSVGSymbolElement extends SVGSymbolElement {
append: ddeAppend<ddeSVGSymbolElement>;
}
export interface ddeSVGTextElement extends SVGTextElement {
append: ddeAppend<ddeSVGTextElement>;
}
export interface ddeSVGTextPathElement extends SVGTextPathElement {
append: ddeAppend<ddeSVGTextPathElement>;
}
export interface ddeSVGTitleElement extends SVGTitleElement {
append: ddeAppend<ddeSVGTitleElement>;
}
export interface ddeSVGTSpanElement extends SVGTSpanElement {
append: ddeAppend<ddeSVGTSpanElement>;
}
export interface ddeSVGUseElement extends SVGUseElement {
append: ddeAppend<ddeSVGUseElement>;
}
export interface ddeSVGViewElement extends SVGViewElement {
append: ddeAppend<ddeSVGViewElement>;
}
export {
dispatchEvent$1 as dispatchEvent,
el as createElement,
elNS as createElementNS,
};
export {};

853
dist/esm.js vendored
View File

@ -1,451 +1,662 @@
// src/signals-common.js
var C = {
isSignal(t) {
return !1;
},
processReactiveAttribute(t, e, r, n) {
return r;
}
};
function Z(t, e = !0) {
return e ? Object.assign(C, t) : (Object.setPrototypeOf(t, C), t);
}
function S(t) {
return C.isPrototypeOf(t) && t !== C ? t : C;
}
// src/helpers.js // src/helpers.js
function m(t) { function isUndef(value) {
return typeof t > "u"; return typeof value === "undefined";
} }
function L(t, e) { function isInstance(obj, cls) {
if (!t || !(t instanceof AbortSignal)) return obj instanceof cls;
return !0;
if (!t.aborted)
return t.addEventListener("abort", e), function() {
t.removeEventListener("abort", e);
};
} }
function q(t, e) { function isProtoFrom(obj, cls) {
let { observedAttributes: r = [] } = t.constructor; return Object.prototype.isPrototypeOf.call(cls, obj);
return r.reduce(function(n, o) { }
return n[G(o)] = e(t, o), n; function oAssign(...o) {
return Object.assign(...o);
}
function onAbort(signal, listener) {
if (!signal || !isInstance(signal, AbortSignal))
return true;
if (signal.aborted)
return;
signal.addEventListener("abort", listener);
return function cleanUp() {
signal.removeEventListener("abort", listener);
};
}
function observedAttributes(instance, observedAttribute) {
const { observedAttributes: observedAttributes3 = [] } = instance.constructor;
return observedAttributes3.reduce(function(out, name) {
out[kebabToCamel(name)] = observedAttribute(instance, name);
return out;
}, {}); }, {});
} }
function G(t) { function kebabToCamel(name) {
return t.replace(/-./g, (e) => e[1].toUpperCase()); return name.replace(/-./g, (x) => x[1].toUpperCase());
}
// src/signals-lib/common.js
var signals_global = {
/**
* Checks if a value is a signal
* @param {any} attributes - Value to check
* @returns {boolean} Whether the value is a signal
*/
isSignal(attributes) {
return false;
},
/**
* Processes an attribute that might be reactive
* @param {Element} obj - Element that owns the attribute
* @param {string} key - Attribute name
* @param {any} attr - Attribute value
* @param {Function} set - Function to set the attribute
* @returns {any} Processed attribute value
*/
processReactiveAttribute(obj, key, attr, set) {
return attr;
}
};
function registerReactivity(def, global = true) {
if (global) return oAssign(signals_global, def);
Object.setPrototypeOf(def, signals_global);
return def;
}
function signals(_this) {
return isProtoFrom(_this, signals_global) && _this !== signals_global ? _this : signals_global;
} }
// src/dom-common.js // src/dom-common.js
var a = { var enviroment = {
setDeleteAttr: V, setDeleteAttr,
ssr: "", ssr: "",
D: globalThis.document, D: globalThis.document,
F: globalThis.DocumentFragment, F: globalThis.DocumentFragment,
H: globalThis.HTMLElement, H: globalThis.HTMLElement,
S: globalThis.SVGElement, S: globalThis.SVGElement,
M: globalThis.MutationObserver, M: globalThis.MutationObserver,
q: (t) => t || Promise.resolve() q: (p) => p || Promise.resolve()
}; };
function V(t, e, r) { function setDeleteAttr(obj, prop, val) {
if (Reflect.set(t, e, r), !!m(r)) { Reflect.set(obj, prop, val);
if (Reflect.deleteProperty(t, e), t instanceof a.H && t.getAttribute(e) === "undefined") if (!isUndef(val)) return;
return t.removeAttribute(e); Reflect.deleteProperty(obj, prop);
if (Reflect.get(t, e) === "undefined") if (isInstance(obj, enviroment.H) && obj.getAttribute(prop) === "undefined")
return Reflect.set(t, e, ""); return obj.removeAttribute(prop);
} if (Reflect.get(obj, prop) === "undefined")
return Reflect.set(obj, prop, "");
} }
var x = "__dde_lifecyclesToEvents", v = "dde:connected", w = "dde:disconnected", y = "dde:attributeChanged"; var keyLTE = "__dde_lifecyclesToEvents";
var evc = "dde:connected";
var evd = "dde:disconnected";
var eva = "dde:attributeChanged";
// src/dom.js // src/dom.js
function dt(t) { function queue(promise) {
return a.q(t); return enviroment.q(promise);
} }
var g = [{ var scopes = [{
get scope() { get scope() {
return a.D.body; return enviroment.D.body;
}, },
host: (t) => t ? t(a.D.body) : a.D.body, host: (c) => c ? c(enviroment.D.body) : enviroment.D.body,
prevent: !0 prevent: true
}], O = { }];
var scope = {
/**
* Gets the current scope
* @returns {Object} Current scope context
*/
get current() { get current() {
return g[g.length - 1]; return scopes[scopes.length - 1];
}, },
/**
* Gets the host element of the current scope
* @returns {Function} Host accessor function
*/
get host() { get host() {
return this.current.host; return this.current.host;
}, },
/**
* Prevents default behavior in the current scope
* @returns {Object} Current scope context
*/
preventDefault() { preventDefault() {
let { current: t } = this; const { current } = this;
return t.prevent = !0, t; current.prevent = true;
return current;
}, },
/**
* Gets a copy of the current scope stack
* @returns {Array} Copy of scope stack
*/
get state() { get state() {
return [...g]; return [...scopes];
}, },
push(t = {}) { /**
return g.push(Object.assign({}, this.current, { prevent: !1 }, t)); * Pushes a new scope to the stack
* @param {Object} [s={}] - Scope object to push
* @returns {number} New length of the scope stack
*/
push(s = {}) {
return scopes.push(oAssign({}, this.current, { prevent: false }, s));
}, },
/**
* Pushes the root scope to the stack
* @returns {number} New length of the scope stack
*/
pushRoot() { pushRoot() {
return g.push(g[0]); return scopes.push(scopes[0]);
}, },
/**
* Pops the current scope from the stack
* @returns {Object|undefined} Popped scope or undefined if only one scope remains
*/
pop() { pop() {
if (g.length !== 1) if (scopes.length === 1) return;
return g.pop(); return scopes.pop();
} }
}; };
function k(...t) { function append(...els) {
return this.appendOriginal(...t), this; this.appendOriginal(...els);
return this;
} }
function J(t) { function chainableAppend(el) {
return t.append === k || (t.appendOriginal = t.append, t.append = k), t; if (el.append === append) return el;
el.appendOriginal = el.append;
el.append = append;
return el;
} }
var T; var namespace;
function P(t, e, ...r) { function createElement(tag, attributes, ...addons) {
let n = S(this), o = 0, c, d; const s = signals(this);
switch ((Object(e) !== e || n.isSignal(e)) && (e = { textContent: e }), !0) { let scoped = 0;
case typeof t == "function": { let el, el_host;
o = 1; if (Object(attributes) !== attributes || s.isSignal(attributes))
let f = (...l) => l.length ? (o === 1 ? r.unshift(...l) : l.forEach((E) => E(d)), void 0) : d; attributes = { textContent: attributes };
O.push({ scope: t, host: f }), c = t(e || void 0); switch (true) {
let p = c instanceof a.F; case typeof tag === "function": {
if (c.nodeName === "#comment") break; scoped = 1;
let b = P.mark({ const host = (...c) => !c.length ? el_host : (scoped === 1 ? addons.unshift(...c) : c.forEach((c2) => c2(el_host)), void 0);
scope.push({ scope: tag, host });
el = tag(attributes || void 0);
const is_fragment = isInstance(el, enviroment.F);
if (el.nodeName === "#comment") break;
const el_mark = createElement.mark({
type: "component", type: "component",
name: t.name, name: tag.name,
host: p ? "this" : "parentElement" host: is_fragment ? "this" : "parentElement"
}); });
c.prepend(b), p && (d = b); el.prepend(el_mark);
if (is_fragment) el_host = el_mark;
break; break;
} }
case t === "#text": case tag === "#text":
c = R.call(this, a.D.createTextNode(""), e); el = assign.call(this, enviroment.D.createTextNode(""), attributes);
break; break;
case (t === "<>" || !t): case (tag === "<>" || !tag):
c = R.call(this, a.D.createDocumentFragment(), e); el = assign.call(this, enviroment.D.createDocumentFragment(), attributes);
break; break;
case !!T: case Boolean(namespace):
c = R.call(this, a.D.createElementNS(T, t), e); el = assign.call(this, enviroment.D.createElementNS(namespace, tag), attributes);
break; break;
case !c: case !el:
c = R.call(this, a.D.createElement(t), e); el = assign.call(this, enviroment.D.createElement(tag), attributes);
} }
return J(c), d || (d = c), r.forEach((f) => f(d)), o && O.pop(), o = 2, c; chainableAppend(el);
if (!el_host) el_host = el;
addons.forEach((c) => c(el_host));
if (scoped) scope.pop();
scoped = 2;
return el;
} }
P.mark = function(t, e = !1) { createElement.mark = function(attrs, is_open = false) {
t = Object.entries(t).map(([o, c]) => o + `="${c}"`).join(" "); attrs = Object.entries(attrs).map(([n, v]) => n + `="${v}"`).join(" ");
let r = e ? "" : "/", n = a.D.createComment(`<dde:mark ${t}${a.ssr}${r}>`); const end = is_open ? "" : "/";
return e && (n.end = a.D.createComment("</dde:mark>")), n; const out = enviroment.D.createComment(`<dde:mark ${attrs}${enviroment.ssr}${end}>`);
if (is_open) out.end = enviroment.D.createComment("</dde:mark>");
return out;
}; };
function pt(t) { function createElementNS(ns) {
let e = this; const _this = this;
return function(...n) { return function createElementNSCurried(...rest) {
T = t; namespace = ns;
let o = P.call(e, ...n); const el = createElement.call(_this, ...rest);
return T = void 0, o; namespace = void 0;
return el;
}; };
} }
function lt(t, e = t) { function simulateSlots(element, root = element) {
let r = "\xB9\u2070", n = "\u2713", o = Object.fromEntries( const mark_e = "\xB9\u2070", mark_s = "\u2713";
Array.from(e.querySelectorAll("slot")).filter((c) => !c.name.endsWith(r)).map((c) => [c.name += r, c]) const slots = Object.fromEntries(
Array.from(root.querySelectorAll("slot")).filter((s) => !s.name.endsWith(mark_e)).map((s) => [s.name += mark_e, s])
); );
if (t.append = new Proxy(t.append, { element.append = new Proxy(element.append, {
apply(c, d, f) { apply(orig, _, els) {
if (f[0] === e) return c.apply(t, f); if (els[0] === root) return orig.apply(element, els);
for (let p of f) { for (const el of els) {
let b = (p.slot || "") + r; const name = (el.slot || "") + mark_e;
try { try {
Q(p, "remove", "slot"); elementAttribute(el, "remove", "slot");
} catch { } catch (_error) {
} }
let l = o[b]; const slot = slots[name];
if (!l) return; if (!slot) return;
l.name.startsWith(n) || (l.childNodes.forEach((E) => E.remove()), l.name = n + b), l.append(p); if (!slot.name.startsWith(mark_s)) {
slot.childNodes.forEach((c) => c.remove());
slot.name = mark_s + name;
}
slot.append(el);
} }
return t.append = c, t; element.append = orig;
return element;
} }
}), t !== e) { });
let c = Array.from(t.childNodes); if (element !== root) {
t.append(...c); const els = Array.from(element.childNodes);
element.append(...els);
} }
return e; return root;
} }
var N = /* @__PURE__ */ new WeakMap(), { setDeleteAttr: $ } = a; var assign_context = /* @__PURE__ */ new WeakMap();
function R(t, ...e) { var { setDeleteAttr: setDeleteAttr2 } = enviroment;
if (!e.length) return t; function assign(element, ...attributes) {
N.set(t, H(t, this)); if (!attributes.length) return element;
for (let [r, n] of Object.entries(Object.assign({}, ...e))) assign_context.set(element, assignContext(element, this));
U.call(this, t, r, n); for (const [key, value] of Object.entries(oAssign({}, ...attributes)))
return N.delete(t), t; assignAttribute.call(this, element, key, value);
assign_context.delete(element);
return element;
} }
function U(t, e, r) { function assignAttribute(element, key, value) {
let { setRemoveAttr: n, s: o } = H(t, this), c = this; const { setRemoveAttr, s } = assignContext(element, this);
r = o.processReactiveAttribute( const _this = this;
t, value = s.processReactiveAttribute(
e, element,
r, key,
(f, p) => U.call(c, t, f, p) value,
(key2, value2) => assignAttribute.call(_this, element, key2, value2)
); );
let [d] = e; const [k] = key;
if (d === "=") return n(e.slice(1), r); if ("=" === k) return setRemoveAttr(key.slice(1), value);
if (d === ".") return F(t, e.slice(1), r); if ("." === k) return setDelete(element, key.slice(1), value);
if (/(aria|data)([A-Z])/.test(e)) if (/(aria|data)([A-Z])/.test(key)) {
return e = e.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(), n(e, r); key = key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
switch (e === "className" && (e = "class"), e) { return setRemoveAttr(key, value);
}
if ("className" === key) key = "class";
switch (key) {
case "xlink:href": case "xlink:href":
return n(e, r, "http://www.w3.org/1999/xlink"); return setRemoveAttr(key, value, "http://www.w3.org/1999/xlink");
case "textContent": case "textContent":
return $(t, e, r); return setDeleteAttr2(element, key, value);
case "style": case "style":
if (typeof r != "object") break; if (typeof value !== "object") break;
/* falls through */ /* falls through */
case "dataset": case "dataset":
return M(o, e, t, r, F.bind(null, t[e])); return forEachEntries(s, key, element, value, setDelete.bind(null, element[key]));
case "ariaset": case "ariaset":
return M(o, e, t, r, (f, p) => n("aria-" + f, p)); return forEachEntries(s, key, element, value, (key2, val) => setRemoveAttr("aria-" + key2, val));
case "classList": case "classList":
return K.call(c, t, r); return classListDeclarative.call(_this, element, value);
} }
return X(t, e) ? $(t, e, r) : n(e, r); return isPropSetter(element, key) ? setDeleteAttr2(element, key, value) : setRemoveAttr(key, value);
} }
function H(t, e) { function assignContext(element, _this) {
if (N.has(t)) return N.get(t); if (assign_context.has(element)) return assign_context.get(element);
let n = (t instanceof a.S ? tt : Y).bind(null, t, "Attribute"), o = S(e); const is_svg = isInstance(element, enviroment.S);
return { setRemoveAttr: n, s: o }; const setRemoveAttr = (is_svg ? setRemoveNS : setRemove).bind(null, element, "Attribute");
const s = signals(_this);
return { setRemoveAttr, s };
} }
function K(t, e) { function classListDeclarative(element, toggle) {
let r = S(this); const s = signals(this);
return M( forEachEntries(
r, s,
"classList", "classList",
t, element,
e, toggle,
(n, o) => t.classList.toggle(n, o === -1 ? void 0 : !!o) (class_name, val) => element.classList.toggle(class_name, val === -1 ? void 0 : Boolean(val))
), t; );
return element;
} }
function Q(t, e, r, n) { function elementAttribute(element, op, key, value) {
return t instanceof a.H ? t[e + "Attribute"](r, n) : t[e + "AttributeNS"](null, r, n); if (isInstance(element, enviroment.H))
return element[op + "Attribute"](key, value);
return element[op + "AttributeNS"](null, key, value);
} }
function X(t, e) { function isPropSetter(el, key) {
if (!(e in t)) return !1; if (!(key in el)) return false;
let r = z(t, e); const des = getPropDescriptor(el, key);
return !m(r.set); return !isUndef(des.set);
} }
function z(t, e) { function getPropDescriptor(p, key) {
if (t = Object.getPrototypeOf(t), !t) return {}; p = Object.getPrototypeOf(p);
let r = Object.getOwnPropertyDescriptor(t, e); if (!p) return {};
return r || z(t, e); const des = Object.getOwnPropertyDescriptor(p, key);
if (!des) return getPropDescriptor(p, key);
return des;
} }
function M(t, e, r, n, o) { function forEachEntries(s, target, element, obj, cb) {
let c = String; const S = String;
if (!(typeof n != "object" || n === null)) if (typeof obj !== "object" || obj === null) return;
return Object.entries(n).forEach(function([f, p]) { return Object.entries(obj).forEach(function process([key, val]) {
f && (f = new c(f), f.target = e, p = t.processReactiveAttribute(r, f, p, o), o(f, p)); if (!key) return;
}); key = new S(key);
key.target = target;
val = s.processReactiveAttribute(element, key, val, cb);
cb(key, val);
});
} }
function Y(t, e, r, n) { function setRemove(obj, prop, key, val) {
return t[(m(n) ? "remove" : "set") + e](r, n); return obj[(isUndef(val) ? "remove" : "set") + prop](key, val);
} }
function tt(t, e, r, n, o = null) { function setRemoveNS(obj, prop, key, val, ns = null) {
return t[(m(n) ? "remove" : "set") + e + "NS"](o, r, n); return obj[(isUndef(val) ? "remove" : "set") + prop + "NS"](ns, key, val);
} }
function F(t, e, r) { function setDelete(obj, key, val) {
if (Reflect.set(t, e, r), !!m(r)) Reflect.set(obj, key, val);
return Reflect.deleteProperty(t, e); if (!isUndef(val)) return;
return Reflect.deleteProperty(obj, key);
} }
// src/events-observer.js // src/events-observer.js
var _ = a.M ? et() : new Proxy({}, { var c_ch_o = enviroment.M ? connectionsChangesObserverConstructor() : new Proxy({}, {
get() { get() {
return () => { return () => {
}; };
} }
}); });
function et() { function connectionsChangesObserverConstructor() {
let t = /* @__PURE__ */ new Map(), e = !1, r = (s) => function(u) { const store = /* @__PURE__ */ new Map();
for (let i of u) let is_observing = false;
if (i.type === "childList") { const observerListener = (stop2) => function(mutations) {
if (l(i.addedNodes, !0)) { for (const mutation of mutations) {
s(); if (mutation.type !== "childList") continue;
continue; if (observerAdded(mutation.addedNodes, true)) {
} stop2();
E(i.removedNodes, !0) && s(); continue;
} }
}, n = new a.M(r(f)); if (observerRemoved(mutation.removedNodes, true))
return { stop2();
observe(s) {
let u = new a.M(r(() => {
}));
return u.observe(s, { childList: !0, subtree: !0 }), () => u.disconnect();
},
onConnected(s, u) {
d();
let i = c(s);
i.connected.has(u) || (i.connected.add(u), i.length_c += 1);
},
offConnected(s, u) {
if (!t.has(s)) return;
let i = t.get(s);
i.connected.has(u) && (i.connected.delete(u), i.length_c -= 1, o(s, i));
},
onDisconnected(s, u) {
d();
let i = c(s);
i.disconnected.has(u) || (i.disconnected.add(u), i.length_d += 1);
},
offDisconnected(s, u) {
if (!t.has(s)) return;
let i = t.get(s);
i.disconnected.has(u) && (i.disconnected.delete(u), i.length_d -= 1, o(s, i));
} }
}; };
function o(s, u) { const observer = new enviroment.M(observerListener(stop));
u.length_c || u.length_d || (t.delete(s), f()); return {
/**
* Creates an observer for a specific element
* @param {Element} element - Element to observe
* @returns {Function} Cleanup function
*/
observe(element) {
const o = new enviroment.M(observerListener(() => {
}));
o.observe(element, { childList: true, subtree: true });
return () => o.disconnect();
},
/**
* Register a connection listener for an element
* @param {Element} element - Element to watch
* @param {Function} listener - Callback for connection event
*/
onConnected(element, listener) {
start();
const listeners = getElementStore(element);
if (listeners.connected.has(listener)) return;
listeners.connected.add(listener);
listeners.length_c += 1;
},
/**
* Unregister a connection listener
* @param {Element} element - Element being watched
* @param {Function} listener - Callback to remove
*/
offConnected(element, listener) {
if (!store.has(element)) return;
const ls = store.get(element);
if (!ls.connected.has(listener)) return;
ls.connected.delete(listener);
ls.length_c -= 1;
cleanWhenOff(element, ls);
},
/**
* Register a disconnection listener for an element
* @param {Element} element - Element to watch
* @param {Function} listener - Callback for disconnection event
*/
onDisconnected(element, listener) {
start();
const listeners = getElementStore(element);
if (listeners.disconnected.has(listener)) return;
listeners.disconnected.add(listener);
listeners.length_d += 1;
},
/**
* Unregister a disconnection listener
* @param {Element} element - Element being watched
* @param {Function} listener - Callback to remove
*/
offDisconnected(element, listener) {
if (!store.has(element)) return;
const ls = store.get(element);
ls.disconnected.delete(listener);
ls.length_d -= 1;
cleanWhenOff(element, ls);
}
};
function cleanWhenOff(element, ls) {
if (ls.length_c || ls.length_d)
return;
store.delete(element);
stop();
} }
function c(s) { function getElementStore(element) {
if (t.has(s)) return t.get(s); if (store.has(element)) return store.get(element);
let u = { const out = {
connected: /* @__PURE__ */ new WeakSet(), connected: /* @__PURE__ */ new WeakSet(),
length_c: 0, length_c: 0,
disconnected: /* @__PURE__ */ new WeakSet(), disconnected: /* @__PURE__ */ new WeakSet(),
length_d: 0 length_d: 0
}; };
return t.set(s, u), u; store.set(element, out);
return out;
} }
function d() { function start() {
e || (e = !0, n.observe(a.D.body, { childList: !0, subtree: !0 })); if (is_observing) return;
is_observing = true;
observer.observe(enviroment.D.body, { childList: true, subtree: true });
} }
function f() { function stop() {
!e || t.size || (e = !1, n.disconnect()); if (!is_observing || store.size) return;
is_observing = false;
observer.disconnect();
} }
function p() { function requestIdle() {
return new Promise(function(s) { return new Promise(function(resolve) {
(requestIdleCallback || requestAnimationFrame)(s); (requestIdleCallback || requestAnimationFrame)(resolve);
}); });
} }
async function b(s) { async function collectChildren(element) {
t.size > 30 && await p(); if (store.size > 30)
let u = []; await requestIdle();
if (!(s instanceof Node)) return u; const out = [];
for (let i of t.keys()) if (!isInstance(element, Node)) return out;
i === s || !(i instanceof Node) || s.contains(i) && u.push(i); for (const el of store.keys()) {
return u; if (el === element || !isInstance(el, Node)) continue;
} if (element.contains(el))
function l(s, u) { out.push(el);
let i = !1;
for (let h of s) {
if (u && b(h).then(l), !t.has(h)) continue;
let A = t.get(h);
A.length_c && (h.dispatchEvent(new Event(v)), A.connected = /* @__PURE__ */ new WeakSet(), A.length_c = 0, A.length_d || t.delete(h), i = !0);
} }
return i; return out;
} }
function E(s, u) { function observerAdded(addedNodes, is_root) {
let i = !1; let out = false;
for (let h of s) for (const element of addedNodes) {
u && b(h).then(E), !(!t.has(h) || !t.get(h).length_d) && ((globalThis.queueMicrotask || setTimeout)(I(h)), i = !0); if (is_root) collectChildren(element).then(observerAdded);
return i; if (!store.has(element)) continue;
const ls = store.get(element);
if (!ls.length_c) continue;
element.dispatchEvent(new Event(evc));
ls.connected = /* @__PURE__ */ new WeakSet();
ls.length_c = 0;
if (!ls.length_d) store.delete(element);
out = true;
}
return out;
} }
function I(s) { function observerRemoved(removedNodes, is_root) {
let out = false;
for (const element of removedNodes) {
if (is_root) collectChildren(element).then(observerRemoved);
if (!store.has(element)) continue;
const ls = store.get(element);
if (!ls.length_d) continue;
(globalThis.queueMicrotask || setTimeout)(dispatchRemove(element));
out = true;
}
return out;
}
function dispatchRemove(element) {
return () => { return () => {
s.isConnected || (s.dispatchEvent(new Event(w)), t.delete(s)); if (element.isConnected) return;
element.dispatchEvent(new Event(evd));
store.delete(element);
}; };
} }
} }
// src/customElement.js // src/customElement.js
function wt(t, e, r = rt) { function customElementRender(target, render, props = observedAttributes2) {
let n = t.host || t; const custom_element = target.host || target;
O.push({ scope.push({
scope: n, scope: custom_element,
host: (...d) => d.length ? d.forEach((f) => f(n)) : n host: (...c) => c.length ? c.forEach((c2) => c2(custom_element)) : custom_element
}), typeof r == "function" && (r = r.call(n, n)); });
let o = n[x]; if (typeof props === "function") props = props.call(custom_element, custom_element);
o || nt(n); const is_lte = custom_element[keyLTE];
let c = e.call(n, r); if (!is_lte) lifecyclesToEvents(custom_element);
return o || n.dispatchEvent(new Event(v)), t.nodeType === 11 && typeof t.mode == "string" && n.addEventListener(w, _.observe(t), { once: !0 }), O.pop(), t.append(c); const out = render.call(custom_element, props);
if (!is_lte) custom_element.dispatchEvent(new Event(evc));
if (target.nodeType === 11 && typeof target.mode === "string")
custom_element.addEventListener(evd, c_ch_o.observe(target), { once: true });
scope.pop();
return target.append(out);
} }
function nt(t) { function lifecyclesToEvents(class_declaration) {
return j(t.prototype, "connectedCallback", function(e, r, n) { wrapMethod(class_declaration.prototype, "connectedCallback", function(target, thisArg, detail) {
e.apply(r, n), r.dispatchEvent(new Event(v)); target.apply(thisArg, detail);
}), j(t.prototype, "disconnectedCallback", function(e, r, n) { thisArg.dispatchEvent(new Event(evc));
e.apply(r, n), (globalThis.queueMicrotask || setTimeout)( });
() => !r.isConnected && r.dispatchEvent(new Event(w)) wrapMethod(class_declaration.prototype, "disconnectedCallback", function(target, thisArg, detail) {
target.apply(thisArg, detail);
(globalThis.queueMicrotask || setTimeout)(
() => !thisArg.isConnected && thisArg.dispatchEvent(new Event(evd))
); );
}), j(t.prototype, "attributeChangedCallback", function(e, r, n) { });
let [o, , c] = n; wrapMethod(class_declaration.prototype, "attributeChangedCallback", function(target, thisArg, detail) {
r.dispatchEvent(new CustomEvent(y, { const [attribute, , value] = detail;
detail: [o, c] thisArg.dispatchEvent(new CustomEvent(eva, {
})), e.apply(r, n); detail: [attribute, value]
}), t.prototype[x] = !0, t; }));
target.apply(thisArg, detail);
});
class_declaration.prototype[keyLTE] = true;
return class_declaration;
} }
function j(t, e, r) { function wrapMethod(obj, method, apply) {
t[e] = new Proxy(t[e] || (() => { obj[method] = new Proxy(obj[method] || (() => {
}), { apply: r }); }), { apply });
} }
function rt(t) { function observedAttributes2(instance) {
return q(t, (e, r) => e.getAttribute(r)); return observedAttributes(instance, (i, n) => i.getAttribute(n));
} }
// src/events.js // src/events.js
function yt(t, e, r) { function dispatchEvent(name, options, host) {
return e || (e = {}), function(o, ...c) { if (typeof options === "function") {
r && (c.unshift(o), o = typeof r == "function" ? r() : r); host = options;
let d = c.length ? new CustomEvent(t, Object.assign({ detail: c[0] }, e)) : new Event(t, e); options = null;
return o.dispatchEvent(d); }
if (!options) options = {};
return function dispatch(element, ...d) {
if (host) {
d.unshift(element);
element = typeof host === "function" ? host() : host;
}
const event = d.length ? new CustomEvent(name, oAssign({ detail: d[0] }, options)) : new Event(name, options);
return element.dispatchEvent(event);
}; };
} }
function D(t, e, r) { function on(event, listener, options) {
return function(o) { return function registerElement(element) {
return o.addEventListener(t, e, r), o; element.addEventListener(event, listener, options);
return element;
}; };
} }
var B = (t) => Object.assign({}, typeof t == "object" ? t : null, { once: !0 }); var lifeOptions = (obj) => oAssign({}, typeof obj === "object" ? obj : null, { once: true });
D.connected = function(t, e) { on.connected = function(listener, options) {
return e = B(e), function(n) { options = lifeOptions(options);
return n.addEventListener(v, t, e), n[x] ? n : n.isConnected ? (n.dispatchEvent(new Event(v)), n) : (L(e.signal, () => _.offConnected(n, t)) && _.onConnected(n, t), n); return function registerElement(element) {
element.addEventListener(evc, listener, options);
if (element[keyLTE]) return element;
if (element.isConnected) return element.dispatchEvent(new Event(evc)), element;
const c = onAbort(options.signal, () => c_ch_o.offConnected(element, listener));
if (c) c_ch_o.onConnected(element, listener);
return element;
}; };
}; };
D.disconnected = function(t, e) { on.disconnected = function(listener, options) {
return e = B(e), function(n) { options = lifeOptions(options);
return n.addEventListener(w, t, e), n[x] || L(e.signal, () => _.offDisconnected(n, t)) && _.onDisconnected(n, t), n; return function registerElement(element) {
element.addEventListener(evd, listener, options);
if (element[keyLTE]) return element;
const c = onAbort(options.signal, () => c_ch_o.offDisconnected(element, listener));
if (c) c_ch_o.onDisconnected(element, listener);
return element;
}; };
}; };
var W = /* @__PURE__ */ new WeakMap(); var store_abort = /* @__PURE__ */ new WeakMap();
D.disconnectedAsAbort = function(t) { on.disconnectedAsAbort = function(host) {
if (W.has(t)) return W.get(t); if (store_abort.has(host)) return store_abort.get(host);
let e = new AbortController(); const a = new AbortController();
return W.set(t, e), t(D.disconnected(() => e.abort())), e; store_abort.set(host, a);
host(on.disconnected(() => a.abort()));
return a.signal;
}; };
var ot = /* @__PURE__ */ new WeakSet(); var els_attribute_store = /* @__PURE__ */ new WeakSet();
D.attributeChanged = function(t, e) { on.attributeChanged = function(listener, options) {
return typeof e != "object" && (e = {}), function(n) { if (typeof options !== "object")
if (n.addEventListener(y, t, e), n[x] || ot.has(n) || !a.M) return n; options = {};
let o = new a.M(function(d) { return function registerElement(element) {
for (let { attributeName: f, target: p } of d) element.addEventListener(eva, listener, options);
p.dispatchEvent( if (element[keyLTE] || els_attribute_store.has(element))
new CustomEvent(y, { detail: [f, p.getAttribute(f)] }) return element;
if (!enviroment.M) return element;
const observer = new enviroment.M(function(mutations) {
for (const { attributeName, target } of mutations)
target.dispatchEvent(
new CustomEvent(eva, { detail: [attributeName, target.getAttribute(attributeName)] })
); );
}); });
return L(e.signal, () => o.disconnect()) && o.observe(n, { attributes: !0 }), n; const c = onAbort(options.signal, () => observer.disconnect());
if (c) observer.observe(element, { attributes: true });
return element;
}; };
}; };
export { export {
R as assign, assign,
U as assignAttribute, assignAttribute,
J as chainableAppend, chainableAppend,
K as classListDeclarative, classListDeclarative,
P as createElement, createElement,
pt as createElementNS, createElementNS,
wt as customElementRender, customElementRender,
nt as customElementWithDDE, lifecyclesToEvents as customElementWithDDE,
yt as dispatchEvent, dispatchEvent,
P as el, createElement as el,
pt as elNS, createElementNS as elNS,
Q as elementAttribute, elementAttribute,
nt as lifecyclesToEvents, lifecyclesToEvents,
rt as observedAttributes, observedAttributes2 as observedAttributes,
D as on, on,
dt as queue, queue,
Z as registerReactivity, registerReactivity,
O as scope, scope,
lt as simulateSlots simulateSlots
}; };

782
dist/esm.min.d.ts vendored Normal file
View File

@ -0,0 +1,782 @@
// Generated by dts-bundle-generator v9.5.1
export interface Signal<V, A> {
/** The current value of the signal */
get(): V;
/** Set new value of the signal */
set(value: V): V;
toJSON(): V;
valueOf(): V;
}
export type Action<V> = (this: {
value: V;
stopPropagation(): void;
}, ...a: any[]) => typeof signal._ | void;
//type SymbolSignal= Symbol;
export type SymbolOnclear = symbol;
export type Actions<V> = Record<string | SymbolOnclear, Action<V>>;
export type OnListenerOptions = Pick<AddEventListenerOptions, "signal"> & {
first_time?: boolean;
};
export interface signal {
_: Symbol;
/**
* Computations signal. This creates a signal which is computed from other signals.
* */
<V extends () => any>(computation: V): Signal<ReturnType<V>, {}>;
/**
* Simple example:
* ```js
* const hello= S("Hello Signal");
* ```
* simple todo signal:
* ```js
* const todos= S([], {
* add(v){ this.value.push(S(v)); },
* remove(i){ this.value.splice(i, 1); },
* [S.symbols.onclear](){ S.clear(...this.value); },
* });
* ```
* computed signal:
* ```js
* const name= S("Jan");
* const surname= S("Andrle");
* const fullname= S(()=> name.get()+" "+surname.get());
* ```
* @param value Initial signal value. Or function computing value from other signals.
* @param actions Use to define actions on the signal. Such as add item to the array.
* There is also a reserved function `S.symbol.onclear` which is called when the signal is cleared
* by `S.clear`.
* */
<V, A extends Actions<V>>(value: V, actions?: A): Signal<V, A>;
action<S extends Signal<any, Actions<any>>, A extends (S extends Signal<any, infer A> ? A : never), N extends keyof A>(signal: S, name: N, ...params: A[N] extends (...args: infer P) => any ? P : never): void;
clear(...signals: Signal<any, any>[]): void;
on<T>(signal: Signal<T, any>, onchange: (a: T) => void, options?: OnListenerOptions): void;
symbols: {
//signal: SymbolSignal;
onclear: SymbolOnclear;
};
/**
* Reactive element, which is rendered based on the given signal.
* ```js
* S.el(signal, value=> value ? el("b", "True") : el("i", "False"));
* S.el(listS, list=> list.map(li=> el("li", li)));
* ```
* */
el<S extends any>(signal: Signal<S, any>, el: (v: S) => Element | Element[] | DocumentFragment): DocumentFragment;
observedAttributes(custom_element: HTMLElement): Record<string, Signal<string, {}>>;
}
declare const signal: signal;
declare global {
type ddeSignal<T, A = {}> = Signal<T, A>;
type ddeAction<V> = Action<V>;
type ddeActions<V> = Actions<V>;
}
export type CustomElementTagNameMap = {
"#text": Text;
"#comment": Comment;
};
export type SupportedElement = HTMLElementTagNameMap[keyof HTMLElementTagNameMap] | SVGElementTagNameMap[keyof SVGElementTagNameMap] | MathMLElementTagNameMap[keyof MathMLElementTagNameMap] | CustomElementTagNameMap[keyof CustomElementTagNameMap];
declare global {
type ddeComponentAttributes = Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment | Node> = (element: El) => any;
type ddeString = string | Signal<string, {}>;
type ddeStringable = ddeString | number | Signal<number, {}>;
}
export type PascalCase = `${Capitalize<string>}${string}`;
export type AttrsModified = {
/**
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/
style: Partial<CSSStyleDeclaration> | ddeString | Partial<{
[K in keyof CSSStyleDeclaration]: Signal<CSSStyleDeclaration[K], {}>;
}>;
/**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1.
* In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))`
* for others.
*/
classList: Record<string, -1 | 0 | 1 | boolean | Signal<-1 | 0 | 1 | boolean, {}>>;
/**
* Used by the dataset HTML attribute to represent data for custom attributes added to elements.
* Values are converted to string (see {@link DOMStringMap}).
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/DOMStringMap)
* */
dataset: Record<string, ddeStringable>;
/**
* Sets `aria-*` simiraly to `dataset`
* */
ariaset: Record<string, ddeString>;
} & Record<`=${string}` | `data${PascalCase}` | `aria${PascalCase}`, ddeString> & Record<`.${string}`, any>;
export type _fromElsInterfaces<EL extends SupportedElement> = Omit<EL, keyof AttrsModified>;
export type IsReadonly<T, K extends keyof T> = T extends {
readonly [P in K]: T[K];
} ? true : false;
/**
* Just element attributtes
*
* In most cases, you can use native propertie such as
* [MDN WEB/API/Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) and so on
* (e.g. [`Text`](https://developer.mozilla.org/en-US/docs/Web/API/Text)).
*
* There is added support for `data[A-Z].*`/`aria[A-Z].*` to be converted to the kebab-case alternatives.
* @private
*/
export type ElementAttributes<T extends SupportedElement> = Partial<{
[K in keyof _fromElsInterfaces<T>]: _fromElsInterfaces<T>[K] extends ((...p: any[]) => any) ? _fromElsInterfaces<T>[K] | ((...p: Parameters<_fromElsInterfaces<T>[K]>) => Signal<ReturnType<_fromElsInterfaces<T>[K]>, {}>) : (IsReadonly<_fromElsInterfaces<T>, K> extends false ? _fromElsInterfaces<T>[K] | Signal<_fromElsInterfaces<T>[K], {}> : ddeStringable);
} & AttrsModified> & Record<string, any>;
export function classListDeclarative<El extends SupportedElement>(element: El, classList: AttrsModified["classList"]): El;
export function assign<El extends SupportedElement>(element: El, ...attrs_array: ElementAttributes<El>[]): El;
export function assignAttribute<El extends SupportedElement, ATT extends keyof ElementAttributes<El>>(element: El, attr: ATT, value: ElementAttributes<El>[ATT]): ElementAttributes<El>[ATT];
export type ExtendedHTMLElementTagNameMap = HTMLElementTagNameMap & CustomElementTagNameMap;
export namespace el {
/**
* Creates a marker comment for elements
*
* @param attrs - Marker attributes
* @param [is_open=false] - Whether the marker is open-ended
* @returns Comment node marker
*/
export function mark(attrs: {
type: "component" | "reactive" | "later";
name?: string;
host?: "this" | "parentElement";
}, is_open?: boolean): Comment;
}
export function el<A extends ddeComponentAttributes, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>, ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
export function el<A extends {
textContent: ddeStringable;
}, EL extends SupportedElement | ddeDocumentFragment>(component: (attr: A, ...rest: any[]) => EL, attrs?: NoInfer<A>["textContent"], ...addons: ddeElementAddon<EL>[]): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap] ? EL : (EL extends ddeDocumentFragment ? EL : ddeHTMLElement);
export function el<TAG extends keyof ExtendedHTMLElementTagNameMap>(tag_name: TAG, attrs?: ElementAttributes<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]> | ddeStringable, ...addons: ddeElementAddon<ExtendedHTMLElementTagNameMap[NoInfer<TAG>]>[]): TAG extends keyof ddeHTMLElementTagNameMap ? ddeHTMLElementTagNameMap[TAG] : ddeHTMLElement;
export function el(tag_name?: "<>"): ddeDocumentFragment;
export function el(tag_name: string, attrs?: ElementAttributes<HTMLElement> | ddeStringable, ...addons: ddeElementAddon<HTMLElement>[]): ddeHTMLElement;
export function elNS(namespace: "http://www.w3.org/2000/svg"): <TAG extends keyof SVGElementTagNameMap & string, EL extends (TAG extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[TAG] : SVGElement)>(tag_name: TAG, attrs?: ElementAttributes<NoInfer<EL>> | ddeStringable, ...addons: ddeElementAddon<NoInfer<EL>>[]) => TAG extends keyof ddeSVGElementTagNameMap ? ddeSVGElementTagNameMap[TAG] : ddeSVGElement;
export function elNS(namespace: "http://www.w3.org/1998/Math/MathML"): <TAG extends keyof MathMLElementTagNameMap & string, EL extends (TAG extends keyof MathMLElementTagNameMap ? MathMLElementTagNameMap[TAG] : MathMLElement)>(tag_name: TAG, attrs?: ddeStringable | Partial<{
[key in keyof EL]: EL[key] | Signal<EL[key], {}> | string | number | boolean;
}>, ...addons: ddeElementAddon<NoInfer<EL>>[]) => ddeMathMLElement;
export function elNS(namespace: string): (tag_name: string, attrs?: string | ddeStringable | Record<string, any>, ...addons: ddeElementAddon<SupportedElement>[]) => SupportedElement;
export function chainableAppend<EL extends SupportedElement>(el: EL): EL;
/** Simulate slots for ddeComponents */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(root: EL): EL;
/**
* Simulate slots in Custom Elements without using `shadowRoot`.
* @param el Custom Element root element
* @param body Body of the custom element
* */
export function simulateSlots<EL extends SupportedElement | DocumentFragment>(el: HTMLElement, body: EL): EL;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, element: SupportedElement): (data?: any) => void;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options?: EventInit): (element: SupportedElement, data?: any) => void;
declare function dispatchEvent$1(name: keyof DocumentEventMap | string, options: EventInit | null, element: SupportedElement | (() => SupportedElement)): (data?: any) => void;
export interface On {
/** Listens to the DOM event. See {@link Document.addEventListener} */
<Event extends keyof DocumentEventMap, EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: Event, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: DocumentEventMap[Event]) => any, options?: AddEventListenerOptions): EE;
<EE extends ddeElementAddon<SupportedElement> = ddeElementAddon<HTMLElement>>(type: string, listener: (this: EE extends ddeElementAddon<infer El> ? El : never, ev: Event | CustomEvent) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element is connected to the live DOM. In case of custom elements uses [`connectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
connected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<El>) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element is disconnected from the live DOM. In case of custom elements uses [`disconnectedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
disconnected<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<void>) => any, options?: AddEventListenerOptions): EE;
/** Listens to the element attribute changes. In case of custom elements uses [`attributeChangedCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks), or {@link MutationObserver} else where */ // editorconfig-checker-disable-line
attributeChanged<EE extends ddeElementAddon<SupportedElement>, El extends (EE extends ddeElementAddon<infer El> ? El : never)>(listener: (this: El, event: CustomEvent<[
string,
string
]>) => any, options?: AddEventListenerOptions): EE;
}
export const on: On;
export type Scope = {
scope: Node | Function | Object;
host: ddeElementAddon<any>;
custom_element: false | HTMLElement;
prevent: boolean;
};
/** Current scope created last time the `el(Function)` was invoke. (Or {@link scope.push}) */
export const scope: {
current: Scope;
/** Stops all automatizations. E. g. signals used as attributes in current scope
* registers removing these listeners (and clean signal if no other listeners are detected)
* on `disconnected` event. */
preventDefault<T extends boolean>(prevent: T): T;
/**
* This represents reference to the current host element `scope.host()`.
* It can be also used to register Addon(s) (functions to be called when component is initized)
* `scope.host(on.connected(console.log))`.
* */
host: (...addons: ddeElementAddon<SupportedElement>[]) => HTMLElement;
state: Scope[];
/** Adds new child scope. All attributes are inherited by default. */
push(scope?: Partial<Scope>): ReturnType<Array<Scope>["push"]>;
/** Adds root scope as a child of the current scope. */
pushRoot(): ReturnType<Array<Scope>["push"]>;
/** Removes last/current child scope. */
pop(): ReturnType<Array<Scope>["pop"]>;
};
export function customElementRender<EL extends HTMLElement, P extends any = Record<string, string | Signal<string, {}>>>(target: ShadowRoot | EL, render: (props: P) => SupportedElement | DocumentFragment, props?: P | ((el: EL) => P)): EL;
export function customElementWithDDE<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
export function lifecyclesToEvents<EL extends (new () => HTMLElement)>(custom_element: EL): EL;
export function observedAttributes(custom_element: HTMLElement): Record<string, string>;
/**
* This is used primarly for server side rendering. To be sure that all async operations
* are finished before the page is sent to the client.
* ```
* // on component
* function component(){
*
* queue(fetch(...).then(...));
* }
*
* // building the page
* async function build(){
* const { component }= await import("./component.js");
* document.body.append(el(component));
* await queue();
* retutn document.body.innerHTML;
* }
* ```
* */
export function queue(promise?: Promise<unknown>): Promise<unknown>;
/* TypeScript MEH */
declare global {
type ddeAppend<el> = (...nodes: (Node | string)[]) => el;
interface ddeDocumentFragment extends DocumentFragment {
append: ddeAppend<ddeDocumentFragment>;
}
interface ddeHTMLElement extends HTMLElement {
append: ddeAppend<ddeHTMLElement>;
}
interface ddeSVGElement extends SVGElement {
append: ddeAppend<ddeSVGElement>;
}
interface ddeMathMLElement extends MathMLElement {
append: ddeAppend<ddeMathMLElement>;
}
interface ddeHTMLElementTagNameMap {
"a": ddeHTMLAnchorElement;
"area": ddeHTMLAreaElement;
"audio": ddeHTMLAudioElement;
"base": ddeHTMLBaseElement;
"blockquote": ddeHTMLQuoteElement;
"body": ddeHTMLBodyElement;
"br": ddeHTMLBRElement;
"button": ddeHTMLButtonElement;
"canvas": ddeHTMLCanvasElement;
"caption": ddeHTMLTableCaptionElement;
"col": ddeHTMLTableColElement;
"colgroup": ddeHTMLTableColElement;
"data": ddeHTMLDataElement;
"datalist": ddeHTMLDataListElement;
"del": ddeHTMLModElement;
"details": ddeHTMLDetailsElement;
"dialog": ddeHTMLDialogElement;
"div": ddeHTMLDivElement;
"dl": ddeHTMLDListElement;
"embed": ddeHTMLEmbedElement;
"fieldset": ddeHTMLFieldSetElement;
"form": ddeHTMLFormElement;
"h1": ddeHTMLHeadingElement;
"h2": ddeHTMLHeadingElement;
"h3": ddeHTMLHeadingElement;
"h4": ddeHTMLHeadingElement;
"h5": ddeHTMLHeadingElement;
"h6": ddeHTMLHeadingElement;
"head": ddeHTMLHeadElement;
"hr": ddeHTMLHRElement;
"html": ddeHTMLHtmlElement;
"iframe": ddeHTMLIFrameElement;
"img": ddeHTMLImageElement;
"input": ddeHTMLInputElement;
"ins": ddeHTMLModElement;
"label": ddeHTMLLabelElement;
"legend": ddeHTMLLegendElement;
"li": ddeHTMLLIElement;
"link": ddeHTMLLinkElement;
"map": ddeHTMLMapElement;
"menu": ddeHTMLMenuElement;
"meta": ddeHTMLMetaElement;
"meter": ddeHTMLMeterElement;
"object": ddeHTMLObjectElement;
"ol": ddeHTMLOListElement;
"optgroup": ddeHTMLOptGroupElement;
"option": ddeHTMLOptionElement;
"output": ddeHTMLOutputElement;
"p": ddeHTMLParagraphElement;
"picture": ddeHTMLPictureElement;
"pre": ddeHTMLPreElement;
"progress": ddeHTMLProgressElement;
"q": ddeHTMLQuoteElement;
"script": ddeHTMLScriptElement;
"select": ddeHTMLSelectElement;
"slot": ddeHTMLSlotElement;
"source": ddeHTMLSourceElement;
"span": ddeHTMLSpanElement;
"style": ddeHTMLStyleElement;
"table": ddeHTMLTableElement;
"tbody": ddeHTMLTableSectionElement;
"td": ddeHTMLTableCellElement;
"template": ddeHTMLTemplateElement;
"textarea": ddeHTMLTextAreaElement;
"tfoot": ddeHTMLTableSectionElement;
"th": ddeHTMLTableCellElement;
"thead": ddeHTMLTableSectionElement;
"time": ddeHTMLTimeElement;
"title": ddeHTMLTitleElement;
"tr": ddeHTMLTableRowElement;
"track": ddeHTMLTrackElement;
"ul": ddeHTMLUListElement;
"video": ddeHTMLVideoElement;
}
interface ddeSVGElementTagNameMap {
"a": ddeSVGAElement;
"animate": ddeSVGAnimateElement;
"animateMotion": ddeSVGAnimateMotionElement;
"animateTransform": ddeSVGAnimateTransformElement;
"circle": ddeSVGCircleElement;
"clipPath": ddeSVGClipPathElement;
"defs": ddeSVGDefsElement;
"desc": ddeSVGDescElement;
"ellipse": ddeSVGEllipseElement;
"feBlend": ddeSVGFEBlendElement;
"feColorMatrix": ddeSVGFEColorMatrixElement;
"feComponentTransfer": ddeSVGFEComponentTransferElement;
"feComposite": ddeSVGFECompositeElement;
"feConvolveMatrix": ddeSVGFEConvolveMatrixElement;
"feDiffuseLighting": ddeSVGFEDiffuseLightingElement;
"feDisplacementMap": ddeSVGFEDisplacementMapElement;
"feDistantLight": ddeSVGFEDistantLightElement;
"feDropShadow": ddeSVGFEDropShadowElement;
"feFlood": ddeSVGFEFloodElement;
"feFuncA": ddeSVGFEFuncAElement;
"feFuncB": ddeSVGFEFuncBElement;
"feFuncG": ddeSVGFEFuncGElement;
"feFuncR": ddeSVGFEFuncRElement;
"feGaussianBlur": ddeSVGFEGaussianBlurElement;
"feImage": ddeSVGFEImageElement;
"feMerge": ddeSVGFEMergeElement;
"feMergeNode": ddeSVGFEMergeNodeElement;
"feMorphology": ddeSVGFEMorphologyElement;
"feOffset": ddeSVGFEOffsetElement;
"fePointLight": ddeSVGFEPointLightElement;
"feSpecularLighting": ddeSVGFESpecularLightingElement;
"feSpotLight": ddeSVGFESpotLightElement;
"feTile": ddeSVGFETileElement;
"feTurbulence": ddeSVGFETurbulenceElement;
"filter": ddeSVGFilterElement;
"foreignObject": ddeSVGForeignObjectElement;
"g": ddeSVGGElement;
"image": ddeSVGImageElement;
"line": ddeSVGLineElement;
"linearGradient": ddeSVGLinearGradientElement;
"marker": ddeSVGMarkerElement;
"mask": ddeSVGMaskElement;
"metadata": ddeSVGMetadataElement;
"mpath": ddeSVGMPathElement;
"path": ddeSVGPathElement;
"pattern": ddeSVGPatternElement;
"polygon": ddeSVGPolygonElement;
"polyline": ddeSVGPolylineElement;
"radialGradient": ddeSVGRadialGradientElement;
"rect": ddeSVGRectElement;
"script": ddeSVGScriptElement;
"set": ddeSVGSetElement;
"stop": ddeSVGStopElement;
"style": ddeSVGStyleElement;
"svg": ddeSVGSVGElement;
"switch": ddeSVGSwitchElement;
"symbol": ddeSVGSymbolElement;
"text": ddeSVGTextElement;
"textPath": ddeSVGTextPathElement;
"title": ddeSVGTitleElement;
"tspan": ddeSVGTSpanElement;
"use": ddeSVGUseElement;
"view": ddeSVGViewElement;
}
}
// editorconfig-checker-disable
export interface ddeHTMLAnchorElement extends HTMLAnchorElement {
append: ddeAppend<ddeHTMLAnchorElement>;
}
export interface ddeHTMLAreaElement extends HTMLAreaElement {
append: ddeAppend<ddeHTMLAreaElement>;
}
export interface ddeHTMLAudioElement extends HTMLAudioElement {
append: ddeAppend<ddeHTMLAudioElement>;
}
export interface ddeHTMLBaseElement extends HTMLBaseElement {
append: ddeAppend<ddeHTMLBaseElement>;
}
export interface ddeHTMLQuoteElement extends HTMLQuoteElement {
append: ddeAppend<ddeHTMLQuoteElement>;
}
export interface ddeHTMLBodyElement extends HTMLBodyElement {
append: ddeAppend<ddeHTMLBodyElement>;
}
export interface ddeHTMLBRElement extends HTMLBRElement {
append: ddeAppend<ddeHTMLBRElement>;
}
export interface ddeHTMLButtonElement extends HTMLButtonElement {
append: ddeAppend<ddeHTMLButtonElement>;
}
export interface ddeHTMLCanvasElement extends HTMLCanvasElement {
append: ddeAppend<ddeHTMLCanvasElement>;
}
export interface ddeHTMLTableCaptionElement extends HTMLTableCaptionElement {
append: ddeAppend<ddeHTMLTableCaptionElement>;
}
export interface ddeHTMLTableColElement extends HTMLTableColElement {
append: ddeAppend<ddeHTMLTableColElement>;
}
export interface ddeHTMLTableColElement extends HTMLTableColElement {
append: ddeAppend<ddeHTMLTableColElement>;
}
export interface ddeHTMLDataElement extends HTMLDataElement {
append: ddeAppend<ddeHTMLDataElement>;
}
export interface ddeHTMLDataListElement extends HTMLDataListElement {
append: ddeAppend<ddeHTMLDataListElement>;
}
export interface ddeHTMLModElement extends HTMLModElement {
append: ddeAppend<ddeHTMLModElement>;
}
export interface ddeHTMLDetailsElement extends HTMLDetailsElement {
append: ddeAppend<ddeHTMLDetailsElement>;
}
export interface ddeHTMLDialogElement extends HTMLDialogElement {
append: ddeAppend<ddeHTMLDialogElement>;
}
export interface ddeHTMLDivElement extends HTMLDivElement {
append: ddeAppend<ddeHTMLDivElement>;
}
export interface ddeHTMLDListElement extends HTMLDListElement {
append: ddeAppend<ddeHTMLDListElement>;
}
export interface ddeHTMLEmbedElement extends HTMLEmbedElement {
append: ddeAppend<ddeHTMLEmbedElement>;
}
export interface ddeHTMLFieldSetElement extends HTMLFieldSetElement {
append: ddeAppend<ddeHTMLFieldSetElement>;
}
export interface ddeHTMLFormElement extends HTMLFormElement {
append: ddeAppend<ddeHTMLFormElement>;
}
export interface ddeHTMLHeadingElement extends HTMLHeadingElement {
append: ddeAppend<ddeHTMLHeadingElement>;
}
export interface ddeHTMLHeadElement extends HTMLHeadElement {
append: ddeAppend<ddeHTMLHeadElement>;
}
export interface ddeHTMLHRElement extends HTMLHRElement {
append: ddeAppend<ddeHTMLHRElement>;
}
export interface ddeHTMLHtmlElement extends HTMLHtmlElement {
append: ddeAppend<ddeHTMLHtmlElement>;
}
export interface ddeHTMLIFrameElement extends HTMLIFrameElement {
append: ddeAppend<ddeHTMLIFrameElement>;
}
export interface ddeHTMLImageElement extends HTMLImageElement {
append: ddeAppend<ddeHTMLImageElement>;
}
export interface ddeHTMLInputElement extends HTMLInputElement {
append: ddeAppend<ddeHTMLInputElement>;
}
export interface ddeHTMLLabelElement extends HTMLLabelElement {
append: ddeAppend<ddeHTMLLabelElement>;
}
export interface ddeHTMLLegendElement extends HTMLLegendElement {
append: ddeAppend<ddeHTMLLegendElement>;
}
export interface ddeHTMLLIElement extends HTMLLIElement {
append: ddeAppend<ddeHTMLLIElement>;
}
export interface ddeHTMLLinkElement extends HTMLLinkElement {
append: ddeAppend<ddeHTMLLinkElement>;
}
export interface ddeHTMLMapElement extends HTMLMapElement {
append: ddeAppend<ddeHTMLMapElement>;
}
export interface ddeHTMLMenuElement extends HTMLMenuElement {
append: ddeAppend<ddeHTMLMenuElement>;
}
export interface ddeHTMLMetaElement extends HTMLMetaElement {
append: ddeAppend<ddeHTMLMetaElement>;
}
export interface ddeHTMLMeterElement extends HTMLMeterElement {
append: ddeAppend<ddeHTMLMeterElement>;
}
export interface ddeHTMLObjectElement extends HTMLObjectElement {
append: ddeAppend<ddeHTMLObjectElement>;
}
export interface ddeHTMLOListElement extends HTMLOListElement {
append: ddeAppend<ddeHTMLOListElement>;
}
export interface ddeHTMLOptGroupElement extends HTMLOptGroupElement {
append: ddeAppend<ddeHTMLOptGroupElement>;
}
export interface ddeHTMLOptionElement extends HTMLOptionElement {
append: ddeAppend<ddeHTMLOptionElement>;
}
export interface ddeHTMLOutputElement extends HTMLOutputElement {
append: ddeAppend<ddeHTMLOutputElement>;
}
export interface ddeHTMLParagraphElement extends HTMLParagraphElement {
append: ddeAppend<ddeHTMLParagraphElement>;
}
export interface ddeHTMLPictureElement extends HTMLPictureElement {
append: ddeAppend<ddeHTMLPictureElement>;
}
export interface ddeHTMLPreElement extends HTMLPreElement {
append: ddeAppend<ddeHTMLPreElement>;
}
export interface ddeHTMLProgressElement extends HTMLProgressElement {
append: ddeAppend<ddeHTMLProgressElement>;
}
export interface ddeHTMLScriptElement extends HTMLScriptElement {
append: ddeAppend<ddeHTMLScriptElement>;
}
export interface ddeHTMLSelectElement extends HTMLSelectElement {
append: ddeAppend<ddeHTMLSelectElement>;
}
export interface ddeHTMLSlotElement extends HTMLSlotElement {
append: ddeAppend<ddeHTMLSlotElement>;
}
export interface ddeHTMLSourceElement extends HTMLSourceElement {
append: ddeAppend<ddeHTMLSourceElement>;
}
export interface ddeHTMLSpanElement extends HTMLSpanElement {
append: ddeAppend<ddeHTMLSpanElement>;
}
export interface ddeHTMLStyleElement extends HTMLStyleElement {
append: ddeAppend<ddeHTMLStyleElement>;
}
export interface ddeHTMLTableElement extends HTMLTableElement {
append: ddeAppend<ddeHTMLTableElement>;
}
export interface ddeHTMLTableSectionElement extends HTMLTableSectionElement {
append: ddeAppend<ddeHTMLTableSectionElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTemplateElement extends HTMLTemplateElement {
append: ddeAppend<ddeHTMLTemplateElement>;
}
export interface ddeHTMLTextAreaElement extends HTMLTextAreaElement {
append: ddeAppend<ddeHTMLTextAreaElement>;
}
export interface ddeHTMLTableCellElement extends HTMLTableCellElement {
append: ddeAppend<ddeHTMLTableCellElement>;
}
export interface ddeHTMLTimeElement extends HTMLTimeElement {
append: ddeAppend<ddeHTMLTimeElement>;
}
export interface ddeHTMLTitleElement extends HTMLTitleElement {
append: ddeAppend<ddeHTMLTitleElement>;
}
export interface ddeHTMLTableRowElement extends HTMLTableRowElement {
append: ddeAppend<ddeHTMLTableRowElement>;
}
export interface ddeHTMLTrackElement extends HTMLTrackElement {
append: ddeAppend<ddeHTMLTrackElement>;
}
export interface ddeHTMLUListElement extends HTMLUListElement {
append: ddeAppend<ddeHTMLUListElement>;
}
export interface ddeHTMLVideoElement extends HTMLVideoElement {
append: ddeAppend<ddeHTMLVideoElement>;
}
export interface ddeSVGAElement extends SVGAElement {
append: ddeAppend<ddeSVGAElement>;
}
export interface ddeSVGAnimateElement extends SVGAnimateElement {
append: ddeAppend<ddeSVGAnimateElement>;
}
export interface ddeSVGAnimateMotionElement extends SVGAnimateMotionElement {
append: ddeAppend<ddeSVGAnimateMotionElement>;
}
export interface ddeSVGAnimateTransformElement extends SVGAnimateTransformElement {
append: ddeAppend<ddeSVGAnimateTransformElement>;
}
export interface ddeSVGCircleElement extends SVGCircleElement {
append: ddeAppend<ddeSVGCircleElement>;
}
export interface ddeSVGClipPathElement extends SVGClipPathElement {
append: ddeAppend<ddeSVGClipPathElement>;
}
export interface ddeSVGDefsElement extends SVGDefsElement {
append: ddeAppend<ddeSVGDefsElement>;
}
export interface ddeSVGDescElement extends SVGDescElement {
append: ddeAppend<ddeSVGDescElement>;
}
export interface ddeSVGEllipseElement extends SVGEllipseElement {
append: ddeAppend<ddeSVGEllipseElement>;
}
export interface ddeSVGFEBlendElement extends SVGFEBlendElement {
append: ddeAppend<ddeSVGFEBlendElement>;
}
export interface ddeSVGFEColorMatrixElement extends SVGFEColorMatrixElement {
append: ddeAppend<ddeSVGFEColorMatrixElement>;
}
export interface ddeSVGFEComponentTransferElement extends SVGFEComponentTransferElement {
append: ddeAppend<ddeSVGFEComponentTransferElement>;
}
export interface ddeSVGFECompositeElement extends SVGFECompositeElement {
append: ddeAppend<ddeSVGFECompositeElement>;
}
export interface ddeSVGFEConvolveMatrixElement extends SVGFEConvolveMatrixElement {
append: ddeAppend<ddeSVGFEConvolveMatrixElement>;
}
export interface ddeSVGFEDiffuseLightingElement extends SVGFEDiffuseLightingElement {
append: ddeAppend<ddeSVGFEDiffuseLightingElement>;
}
export interface ddeSVGFEDisplacementMapElement extends SVGFEDisplacementMapElement {
append: ddeAppend<ddeSVGFEDisplacementMapElement>;
}
export interface ddeSVGFEDistantLightElement extends SVGFEDistantLightElement {
append: ddeAppend<ddeSVGFEDistantLightElement>;
}
export interface ddeSVGFEDropShadowElement extends SVGFEDropShadowElement {
append: ddeAppend<ddeSVGFEDropShadowElement>;
}
export interface ddeSVGFEFloodElement extends SVGFEFloodElement {
append: ddeAppend<ddeSVGFEFloodElement>;
}
export interface ddeSVGFEFuncAElement extends SVGFEFuncAElement {
append: ddeAppend<ddeSVGFEFuncAElement>;
}
export interface ddeSVGFEFuncBElement extends SVGFEFuncBElement {
append: ddeAppend<ddeSVGFEFuncBElement>;
}
export interface ddeSVGFEFuncGElement extends SVGFEFuncGElement {
append: ddeAppend<ddeSVGFEFuncGElement>;
}
export interface ddeSVGFEFuncRElement extends SVGFEFuncRElement {
append: ddeAppend<ddeSVGFEFuncRElement>;
}
export interface ddeSVGFEGaussianBlurElement extends SVGFEGaussianBlurElement {
append: ddeAppend<ddeSVGFEGaussianBlurElement>;
}
export interface ddeSVGFEImageElement extends SVGFEImageElement {
append: ddeAppend<ddeSVGFEImageElement>;
}
export interface ddeSVGFEMergeElement extends SVGFEMergeElement {
append: ddeAppend<ddeSVGFEMergeElement>;
}
export interface ddeSVGFEMergeNodeElement extends SVGFEMergeNodeElement {
append: ddeAppend<ddeSVGFEMergeNodeElement>;
}
export interface ddeSVGFEMorphologyElement extends SVGFEMorphologyElement {
append: ddeAppend<ddeSVGFEMorphologyElement>;
}
export interface ddeSVGFEOffsetElement extends SVGFEOffsetElement {
append: ddeAppend<ddeSVGFEOffsetElement>;
}
export interface ddeSVGFEPointLightElement extends SVGFEPointLightElement {
append: ddeAppend<ddeSVGFEPointLightElement>;
}
export interface ddeSVGFESpecularLightingElement extends SVGFESpecularLightingElement {
append: ddeAppend<ddeSVGFESpecularLightingElement>;
}
export interface ddeSVGFESpotLightElement extends SVGFESpotLightElement {
append: ddeAppend<ddeSVGFESpotLightElement>;
}
export interface ddeSVGFETileElement extends SVGFETileElement {
append: ddeAppend<ddeSVGFETileElement>;
}
export interface ddeSVGFETurbulenceElement extends SVGFETurbulenceElement {
append: ddeAppend<ddeSVGFETurbulenceElement>;
}
export interface ddeSVGFilterElement extends SVGFilterElement {
append: ddeAppend<ddeSVGFilterElement>;
}
export interface ddeSVGForeignObjectElement extends SVGForeignObjectElement {
append: ddeAppend<ddeSVGForeignObjectElement>;
}
export interface ddeSVGGElement extends SVGGElement {
append: ddeAppend<ddeSVGGElement>;
}
export interface ddeSVGImageElement extends SVGImageElement {
append: ddeAppend<ddeSVGImageElement>;
}
export interface ddeSVGLineElement extends SVGLineElement {
append: ddeAppend<ddeSVGLineElement>;
}
export interface ddeSVGLinearGradientElement extends SVGLinearGradientElement {
append: ddeAppend<ddeSVGLinearGradientElement>;
}
export interface ddeSVGMarkerElement extends SVGMarkerElement {
append: ddeAppend<ddeSVGMarkerElement>;
}
export interface ddeSVGMaskElement extends SVGMaskElement {
append: ddeAppend<ddeSVGMaskElement>;
}
export interface ddeSVGMetadataElement extends SVGMetadataElement {
append: ddeAppend<ddeSVGMetadataElement>;
}
export interface ddeSVGMPathElement extends SVGMPathElement {
append: ddeAppend<ddeSVGMPathElement>;
}
export interface ddeSVGPathElement extends SVGPathElement {
append: ddeAppend<ddeSVGPathElement>;
}
export interface ddeSVGPatternElement extends SVGPatternElement {
append: ddeAppend<ddeSVGPatternElement>;
}
export interface ddeSVGPolygonElement extends SVGPolygonElement {
append: ddeAppend<ddeSVGPolygonElement>;
}
export interface ddeSVGPolylineElement extends SVGPolylineElement {
append: ddeAppend<ddeSVGPolylineElement>;
}
export interface ddeSVGRadialGradientElement extends SVGRadialGradientElement {
append: ddeAppend<ddeSVGRadialGradientElement>;
}
export interface ddeSVGRectElement extends SVGRectElement {
append: ddeAppend<ddeSVGRectElement>;
}
export interface ddeSVGScriptElement extends SVGScriptElement {
append: ddeAppend<ddeSVGScriptElement>;
}
export interface ddeSVGSetElement extends SVGSetElement {
append: ddeAppend<ddeSVGSetElement>;
}
export interface ddeSVGStopElement extends SVGStopElement {
append: ddeAppend<ddeSVGStopElement>;
}
export interface ddeSVGStyleElement extends SVGStyleElement {
append: ddeAppend<ddeSVGStyleElement>;
}
export interface ddeSVGSVGElement extends SVGSVGElement {
append: ddeAppend<ddeSVGSVGElement>;
}
export interface ddeSVGSwitchElement extends SVGSwitchElement {
append: ddeAppend<ddeSVGSwitchElement>;
}
export interface ddeSVGSymbolElement extends SVGSymbolElement {
append: ddeAppend<ddeSVGSymbolElement>;
}
export interface ddeSVGTextElement extends SVGTextElement {
append: ddeAppend<ddeSVGTextElement>;
}
export interface ddeSVGTextPathElement extends SVGTextPathElement {
append: ddeAppend<ddeSVGTextPathElement>;
}
export interface ddeSVGTitleElement extends SVGTitleElement {
append: ddeAppend<ddeSVGTitleElement>;
}
export interface ddeSVGTSpanElement extends SVGTSpanElement {
append: ddeAppend<ddeSVGTSpanElement>;
}
export interface ddeSVGUseElement extends SVGUseElement {
append: ddeAppend<ddeSVGUseElement>;
}
export interface ddeSVGViewElement extends SVGViewElement {
append: ddeAppend<ddeSVGViewElement>;
}
export {
dispatchEvent$1 as dispatchEvent,
el as createElement,
elNS as createElementNS,
};
export {};

1
dist/esm.min.js vendored Normal file

File diff suppressed because one or more lines are too long

60
docs/assets/favicon.svg Normal file
View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="64"
height="64"
viewBox="0 0 64 64"
version="1.1"
id="svg2"
sodipodi:docname="favicon.svg"
xml:space="preserve"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs2" /><sodipodi:namedview
id="namedview2"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="9.3249707"
inkscape:cx="38.230683"
inkscape:cy="28.150223"
inkscape:window-width="1278"
inkscape:window-height="1023"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" /><rect
x="0"
y="0"
width="64"
height="64"
rx="10"
fill="#2b2b2b"
id="rect1" /><g
transform="matrix(0.98009485,0,0,1.1964871,0.58334513,-7.2134367)"
id="g2"
style="stroke:#666666"><g
id="g3"
transform="matrix(1.0027126,0,0,0.88864615,3.8540039,4.3371297)"
style="stroke:#666666"><path
d="M 8.880742,11.550781 2.9817709,32 8.880742,52.449219"
stroke="#ff5252"
stroke-width="4.25375"
fill="none"
id="path1"
style="stroke:#666666" /><path
d="M 47.330923,11.568743 53.261141,32 47.330923,52.431257"
stroke="#ff5252"
stroke-width="4.26309"
fill="none"
id="path2"
style="stroke:#666666" /></g></g><path
d="m 11.726038,32.656946 q 0,-2.685867 0.823088,-4.721927 0.823088,-2.036061 2.166022,-3.404987 1.342933,-1.360261 3.07575,-2.053387 1.732818,-0.693128 3.552275,-0.693128 4.505325,0 6.844629,2.659875 2.339303,2.668539 2.339303,7.780349 0,0.519846 -0.01733,1.083011 -0.02599,0.563166 -0.06931,0.90973 H 17.227733 q 0,1.992739 1.646176,3.145062 1.646176,1.14366 4.245402,1.14366 1.602856,0 3.058423,-0.346564 1.446902,-0.346563 2.443272,-0.693127 l 0.736447,4.548646 q -1.386253,0.476525 -2.945789,0.797097 -1.559536,0.329235 -3.508954,0.329235 -2.599226,0 -4.652615,-0.675799 -2.062053,-0.667135 -3.508955,-1.984075 -1.455566,-1.325605 -2.235335,-3.275025 -0.779767,-1.94942 -0.779767,-4.548646 m 13.645936,-2.1227 q 0,-0.823088 -0.216602,-1.585528 -0.216602,-0.753776 -0.693127,-1.360263 -0.476525,-0.606485 -1.212973,-0.979042 -0.736447,-0.363891 -1.819457,-0.363891 -1.039691,0 -1.793467,0.346563 -0.762439,0.346564 -1.264955,0.95305 -0.493854,0.606485 -0.771105,1.386253 -0.285915,0.77977 -0.372555,1.602856 z m 26.901988,11.263311 q -0.129961,0.08664 -0.589158,0.303244 -0.450533,0.216602 -1.18698,0.459196 -0.736448,0.23393 -1.793466,0.407211 -1.065682,0.173282 -2.408616,0.173282 -3.682236,0 -5.371734,-2.192014 -1.689496,-2.18335 -1.689496,-6.385432 V 17.278193 H 33.602856 V 12.85951 h 10.960069 v 22.093419 q 0,2.079381 0.823089,2.815829 0.823088,0.736447 2.07938,0.736447 1.602856,0 2.685867,-0.433204 1.08301,-0.433205 1.429574,-0.563166 z"
id="path1-1"
style="fill:#ff5252;stroke-width:0.866409" /></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

71
docs/assets/logo.svg Normal file
View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="256"
height="256"
viewBox="0 0 256 256"
version="1.1"
id="svg5"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs4"><linearGradient
id="bgGradient"
x1="18"
y1="18"
x2="238"
y2="238"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1363636,0,0,1.1363636,-17.454544,-17.454544)"><stop
offset="0"
stop-color="#3b3b3b"
id="stop1" /><stop
offset="1"
stop-color="#2b2b2b"
id="stop2" /></linearGradient><filter
id="glow"
x="-0.089563958"
y="-0.082460006"
width="1.1791279"
height="1.16492"><feGaussianBlur
stdDeviation="4"
result="blur"
id="feGaussianBlur4"
in="SourceGraphic" /><feComposite
in="SourceGraphic"
in2="blur"
operator="over"
id="feComposite4"
result="composite-0" /></filter></defs><rect
x="3"
y="3"
width="250"
height="250"
fill="url(#bgGradient)"
id="rect4"
style="fill:url(#bgGradient);stroke-width:1.13636"
ry="50" /><g
id="g2"
transform="translate(-3.5569814,-1.5165883)"><g
id="g1"
transform="matrix(1.5900346,0,0,1.5900346,-121.12651,-66.626074)"><g
opacity="0.25"
fill="#ffffff"
filter="url(#glow)"
id="g5"
transform="matrix(0.55415879,0,0,0.56134669,110.90661,51.505106)"><path
d="m 80,60 -30,68 30,68"
stroke="#ffffff"
stroke-width="8"
fill="none"
id="path4" /><path
d="m 176,60 30,68 -30,68"
stroke="#ffffff"
stroke-width="8"
fill="none"
id="path5" /></g><path
d="m 152.28246,124.58038 q 0,-4.06854 1.24681,-7.15275 1.24681,-3.08421 3.28107,-5.15785 2.03427,-2.06051 4.65913,-3.11046 2.62486,-1.04994 5.38096,-1.04994 6.82464,0 10.3682,4.02916 3.54356,4.04228 3.54356,11.78562 0,0.78746 -0.0263,1.64054 -0.0394,0.85308 -0.10499,1.37805 h -20.01456 q 0,3.01859 2.49362,4.76412 2.49362,1.73241 6.43091,1.73241 2.42799,0 4.63287,-0.52497 2.19176,-0.52497 3.70106,-1.04995 l 1.11556,6.89026 q -2.09989,0.72184 -4.46226,1.20744 -2.36237,0.49872 -5.31534,0.49872 -3.93729,0 -7.04775,-1.02369 -3.12359,-1.01058 -5.31534,-3.00547 -2.20489,-2.00802 -3.38607,-4.96098 -1.18114,-2.95297 -1.18114,-6.89026 m 20.67077,-3.21546 q 0,-1.2468 -0.3281,-2.40174 -0.32811,-1.14182 -1.04995,-2.06052 -0.72183,-0.9187 -1.8374,-1.48304 -1.11557,-0.55123 -2.7561,-0.55123 -1.57492,0 -2.71673,0.52498 -1.15494,0.52497 -1.91615,1.44367 -0.74809,0.9187 -1.16806,2.09989 -0.43311,1.18119 -0.56435,2.42799 z m 40.75096,17.06159 q -0.19687,0.13125 -0.89245,0.45936 -0.68247,0.3281 -1.79803,0.69558 -1.11557,0.35436 -2.71673,0.61685 -1.61429,0.26248 -3.64856,0.26248 -5.57783,0 -8.13707,-3.32045 -2.55923,-3.30732 -2.55923,-9.67261 v -26.18298 h -8.5308 v -6.693389 h 16.60224 v 33.466969 q 0,3.14983 1.24681,4.26539 1.24681,1.11557 3.14983,1.11557 2.428,0 4.06853,-0.65621 1.64054,-0.65622 2.16551,-0.85308 z"
id="path1-3"
style="fill:#ff5252;stroke-width:1.31243" /></g><path
d="m 27.256467,130.12148 q 0,6.64555 2.489444,10.86495 2.468347,4.21939 7.953563,4.21939 1.582274,0 2.953578,-0.10548 1.371303,-0.10549 2.848092,-0.31646 v -27.00413 q -1.476789,-0.84388 -3.375517,-1.4346 -1.898728,-0.56962 -4.008427,-0.56962 -4.641336,0 -6.751034,3.69197 -2.109699,3.69198 -2.109699,10.65398 m 29.219322,23.62862 q -3.586487,1.16034 -8.755248,1.89873 -5.168761,0.7384 -10.126552,0.7384 -11.603341,0 -17.55269,-6.85651 -5.970447,-6.85652 -5.970447,-18.77632 0,-12.13076 5.021083,-19.15606 4.999985,-7.0042 14.810082,-7.0042 2.637123,0 5.168761,0.56962 2.531638,0.59072 4.430366,1.64557 V 84.235539 l 12.974645,-2.215183 z m 23.523136,-23.62862 q 0,6.64555 2.489444,10.86495 2.468344,4.21939 7.953559,4.21939 1.582268,0 2.953578,-0.10548 1.3713,-0.10549 2.84809,-0.31646 v -27.00413 q -1.47679,-0.84388 -3.37552,-1.4346 -1.89873,-0.56962 -4.008423,-0.56962 -4.64133,0 -6.75103,3.69197 -2.109698,3.69198 -2.109698,10.65398 m 29.219315,23.62862 q -3.58648,1.16034 -8.75524,1.89873 -5.168774,0.7384 -10.126562,0.7384 -11.603332,0 -17.552681,-6.85651 -5.970446,-6.85652 -5.970446,-18.77632 0,-12.13076 4.999984,-19.15606 5.021082,-7.0042 14.831178,-7.0042 2.63712,0 5.168753,0.56962 2.53164,0.59072 4.43037,1.64557 V 84.235539 l 12.974644,-2.215183 z"
id="path1"
style="fill:#ff5252;stroke-width:2.1097;fill-opacity:0.66479665" /></g></svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -1,28 +1,179 @@
import { registerClientFile, styles } from "../ssr.js"; import { registerClientFile, styles } from "../ssr.js";
const host= "."+code.name; const host= "."+code.name;
styles.css` styles.css`
${host}{ /* Code block styling */
--shiki-color-text: #e9eded; ${host} {
--shiki-color-background: #212121; /* Theme for dark mode - matches Flems/CodeMirror dark theme */
--shiki-color-text: #f8f8f2;
--shiki-color-background: var(--code-bg);
--shiki-token-constant: #82b1ff; --shiki-token-constant: #82b1ff;
--shiki-token-string: #c3e88d; --shiki-token-string: #c3e88d;
--shiki-token-comment: #546e7a; --shiki-token-comment: #546e7a;
--shiki-token-keyword: #c792ea; --shiki-token-keyword: #c792ea;
--shiki-token-parameter: #AA0000; --shiki-token-parameter: #fd971f;
--shiki-token-function: #80cbae; --shiki-token-function: #80cbae;
--shiki-token-string-expression: #c3e88d; --shiki-token-string-expression: #c3e88d;
--shiki-token-punctuation: var(--code); --shiki-token-punctuation: #89ddff;
--shiki-token-link: #EE0000; --shiki-token-link: #82aaff;
--shiki-token-variable: #f8f8f2;
--shiki-token-number: #f78c6c;
--shiki-token-boolean: #82b1ff;
--shiki-token-tag: #f07178;
--shiki-token-attribute: #ffcb6b;
--shiki-token-property: #82b1ff;
--shiki-token-operator: #89ddff;
--shiki-token-regex: #c3e88d;
--shiki-token-class: #ffcb6b;
/* Basic styling */
white-space: pre; white-space: pre;
tab-size: 2; /* TODO: allow custom tab size?! */ tab-size: 2;
overflow: scroll; overflow: auto;
border-radius: var(--border-radius);
font-family: var(--font-mono);
font-size: .85rem;
line-height: 1.5;
position: relative;
margin-block: 1rem;
max-width: 100%;
} }
${host}[data-js=todo]{
/* Light mode overrides to match GitHub-like theme */
@media (prefers-color-scheme: light) {
${host} {
--shiki-color-text: #24292e;
--shiki-color-background: var(--code-bg);
--shiki-token-constant: #005cc5;
--shiki-token-string: #22863a;
--shiki-token-comment: #6a737d;
--shiki-token-keyword: #d73a49;
--shiki-token-parameter: #e36209;
--shiki-token-function: #6f42c1;
--shiki-token-string-expression: #22863a;
--shiki-token-punctuation: #24292e;
--shiki-token-link: #0366d6;
--shiki-token-variable: #24292e;
--shiki-token-number: #005cc5;
--shiki-token-boolean: #005cc5;
--shiki-token-tag: #22863a;
--shiki-token-attribute: #005cc5;
--shiki-token-property: #005cc5;
--shiki-token-operator: #d73a49;
--shiki-token-regex: #032f62;
--shiki-token-class: #6f42c1;
}
}
/* Support for theme toggles */
html[data-theme="light"] ${host} {
--shiki-color-text: #24292e;
--shiki-color-background: var(--code-bg);
--shiki-token-constant: #005cc5;
--shiki-token-string: #22863a;
--shiki-token-comment: #6a737d;
--shiki-token-keyword: #d73a49;
--shiki-token-parameter: #e36209;
--shiki-token-function: #6f42c1;
--shiki-token-string-expression: #22863a;
--shiki-token-punctuation: #24292e;
--shiki-token-link: #0366d6;
--shiki-token-variable: #24292e;
--shiki-token-number: #005cc5;
--shiki-token-boolean: #005cc5;
--shiki-token-tag: #22863a;
--shiki-token-attribute: #005cc5;
--shiki-token-property: #005cc5;
--shiki-token-operator: #d73a49;
--shiki-token-regex: #032f62;
--shiki-token-class: #6f42c1;
}
html[data-theme="dark"] ${host} {
--shiki-color-text: #f8f8f2;
--shiki-color-background: var(--code-bg);
--shiki-token-constant: #82b1ff;
--shiki-token-string: #c3e88d;
--shiki-token-comment: #546e7a;
--shiki-token-keyword: #c792ea;
--shiki-token-parameter: #fd971f;
--shiki-token-function: #80cbae;
--shiki-token-string-expression: #c3e88d;
--shiki-token-punctuation: #89ddff;
--shiki-token-link: #82aaff;
--shiki-token-variable: #f8f8f2;
--shiki-token-number: #f78c6c;
--shiki-token-boolean: #82b1ff;
--shiki-token-tag: #f07178;
--shiki-token-attribute: #ffcb6b;
--shiki-token-property: #82b1ff;
--shiki-token-operator: #89ddff;
--shiki-token-regex: #c3e88d;
--shiki-token-class: #ffcb6b;
}
/* Code block with syntax highlighting waiting for JS */
${host}[data-js=todo] {
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--standard-border-radius); border-radius: var(--border-radius);
margin-bottom: 1rem; padding: 1rem;
margin-top: 18.4px; /* to fix shift when → dataJS=done */ background-color: var(--code-bg);
padding: 1rem 1.4rem; position: relative;
}
/* Add a subtle loading indicator */
${host}[data-js=todo]::before {
content: "Loading syntax highlighting...";
position: absolute;
top: 0.5rem;
right: 0.5rem;
font-size: 0.75rem;
color: var(--text-light);
background-color: var(--bg);
padding: 0.25rem 0.5rem;
border-radius: var(--border-radius);
opacity: 0.7;
}
/* All code blocks should have consistent font and sizing */
${host} code {
font-family: var(--font-mono);
font-size: inherit;
line-height: 1.5;
padding: 0;
}
${host} pre {
margin-block: 0;
font-size: inherit;
}
/* Ensure line numbers (if added) are styled appropriately */
${host} .line-number {
user-select: none;
opacity: 0.5;
margin-right: 1rem;
min-width: 1.5rem;
display: inline-block;
text-align: right;
}
/* If there's a copy button, style it */
${host} .copy-button {
position: absolute;
top: 0.5rem;
right: 0.5rem;
background-color: var(--bg);
color: var(--text);
border: 1px solid var(--border);
border-radius: var(--border-radius);
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
cursor: pointer;
opacity: 0;
transition: opacity 0.2s ease;
}
${host}:hover .copy-button {
opacity: 1;
} }
`; `;
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
@ -43,8 +194,8 @@ export function code({ id, src, content, language= "js", className= host.slice(1
registerClientPart(page_id); registerClientPart(page_id);
dataJS= "todo"; dataJS= "todo";
} }
return el("div", { id, className, dataJS }).append( return el("div", { id, className, dataJS, tabIndex: 0 }).append(
el("code", { className: "language-"+language, textContent: content }) el("code", { className: "language-"+language, textContent: content.trim() })
); );
} }
let is_registered= {}; let is_registered= {};
@ -52,12 +203,45 @@ let is_registered= {};
function registerClientPart(page_id){ function registerClientPart(page_id){
if(is_registered[page_id]) return; if(is_registered[page_id]) return;
// Add Shiki with a more reliable loading method
document.head.append( document.head.append(
el("script", { src: "https://cdn.jsdelivr.net/npm/shiki@0.9", defer: true }), // Use a newer version of Shiki with better performance
el("script", { src: "https://cdn.jsdelivr.net/npm/shiki@0.14.3/dist/index.unpkg.iife.js", defer: true }),
// Make sure we can match Flems styling in dark/light mode
el("style", `
/* Ensure CodeMirror and Shiki use the same font */
.CodeMirror *, .shiki * {
font-family: var(--font-mono) !important;
}
/* Style Shiki's output to match our theme */
.shiki {
background-color: var(--shiki-color-background) !important;
color: var(--shiki-color-text) !important;
padding: 1rem;
border-radius: var(--border-radius);
tab-size: 2;
}
/* Ensure Shiki code tokens use our CSS variables */
.shiki .keyword { color: var(--shiki-token-keyword) !important; }
.shiki .constant { color: var(--shiki-token-constant) !important; }
.shiki .string { color: var(--shiki-token-string) !important; }
.shiki .comment { color: var(--shiki-token-comment) !important; }
.shiki .function { color: var(--shiki-token-function) !important; }
.shiki .operator, .shiki .punctuation { color: var(--shiki-token-punctuation) !important; }
.shiki .parameter { color: var(--shiki-token-parameter) !important; }
.shiki .variable { color: var(--shiki-token-variable) !important; }
.shiki .property { color: var(--shiki-token-property) !important; }
`),
); );
registerClientFile( registerClientFile(
new URL("./code.js.js", import.meta.url), new URL("./code.js.js", import.meta.url),
el("script", { type: "module" }) {
head: el("script", { type: "module" }),
}
); );
is_registered[page_id]= true; is_registered[page_id]= true;
} }

View File

@ -1,12 +1,61 @@
const highlighter= await globalThis.shiki.getHighlighter({ try {
theme: "css-variables", // Initialize Shiki with our custom theme
langs: ["js", "ts", "css", "html", "shell"], const highlighter = await globalThis.shiki.getHighlighter({
}); theme: "css-variables",
const codeBlocks= document.querySelectorAll('code[class*="language-"]'); langs: ["javascript", "typescript", "css", "html", "shell"],
});
codeBlocks.forEach((block)=> { // Find all code blocks that need highlighting
const lang= block.className.replace("language-", ""); const codeBlocks = document.querySelectorAll('div[data-js="todo"] code[class*="language-"]');
block.parentElement.dataset.js= "done";
const html= highlighter.codeToHtml(block.textContent, { lang }); // Process each code block
block.innerHTML= html; codeBlocks.forEach((block) => {
}); try {
// Get the language from the class
const langClass = block.className.match(/language-(\w+)/);
// Map the language to Shiki format
let lang = langClass ? langClass[1] : 'javascript';
if (lang === 'js') lang = 'javascript';
if (lang === 'ts') lang = 'typescript';
// Mark the container as processed
block.parentElement.dataset.js = "done";
// Highlight the code
const code = block.textContent;
const html = highlighter.codeToHtml(code, { lang });
// Insert the highlighted HTML
block.innerHTML = html;
// Add copy button functionality
const copyBtn = document.createElement('button');
copyBtn.className = 'copy-button';
copyBtn.textContent = 'Copy';
copyBtn.setAttribute('aria-label', 'Copy code to clipboard');
copyBtn.addEventListener('click', () => {
navigator.clipboard.writeText(code).then(() => {
copyBtn.textContent = 'Copied!';
setTimeout(() => {
copyBtn.textContent = 'Copy';
}, 2000);
});
});
// Add the copy button to the code block container
block.parentElement.appendChild(copyBtn);
} catch (err) {
console.error('Error highlighting code block:', err);
// Make sure we don't leave the block in a pending state
block.parentElement.dataset.js = "error";
}
});
} catch (err) {
console.error('Failed to initialize Shiki:', err);
// Fallback: at least mark blocks as processed so they don't show loading indicator
document.querySelectorAll('div[data-js="todo"]').forEach(block => {
block.dataset.js = "error";
});
}

View File

@ -1,16 +1,100 @@
import { styles } from "../ssr.js"; import { styles } from "../ssr.js";
const host= "."+example.name; const host= "."+example.name;
styles.css` styles.css`
${host}{ ${host} {
grid-column: full-main; grid-column: full-main;
width: 100%; width: calc(100% - .75em);
max-width: calc(9/5 * var(--body-max-width)); height: calc(4/6 * var(--body-max-width));
height: calc(3/5 * var(--body-max-width)); border-radius: var(--border-radius);
margin-inline: auto; box-shadow: var(--shadow);
border: 1px solid var(--border);
} }
${host} .runtime {
background-color: whitesmoke;
}
/* CodeMirror styling to match our theme */
.CodeMirror {
height: 100% !important;
font-family: var(--font-mono) !important;
font-size: .85rem !important;
line-height: 1.5 !important;
}
/* Dark mode styles for CodeMirror */
.CodeMirror, .CodeMirror-gutters { .CodeMirror, .CodeMirror-gutters {
background: #212121 !important; background: var(--code-bg) !important;
border: 1px solid white; color: var(--text) !important;
}
/* Light mode adjustments for CodeMirror - using CSS variables */
@media (prefers-color-scheme: light) {
/* Core syntax elements */
.cm-s-material .cm-keyword { color: var(--shiki-token-keyword, #d73a49) !important; }
.cm-s-material .cm-atom { color: var(--shiki-token-constant, #005cc5) !important; }
.cm-s-material .cm-number { color: var(--shiki-token-number, #005cc5) !important; }
.cm-s-material .cm-def { color: var(--shiki-token-function, #6f42c1) !important; }
.cm-s-material .cm-variable { color: var(--shiki-token-variable, #24292e) !important; }
.cm-s-material .cm-variable-2 { color: var(--shiki-token-variable, #24292e) !important; }
.cm-s-material .cm-variable-3 { color: var(--shiki-token-variable, #24292e) !important; }
.cm-s-material .cm-property { color: var(--shiki-token-property, #005cc5) !important; }
.cm-s-material .cm-operator { color: var(--shiki-token-operator, #d73a49) !important; }
.cm-s-material .cm-comment { color: var(--shiki-token-comment, #6a737d) !important; }
.cm-s-material .cm-string { color: var(--shiki-token-string, #22863a) !important; }
.cm-s-material .cm-string-2 { color: var(--shiki-token-string, #22863a) !important; }
.cm-s-material .cm-tag { color: var(--shiki-token-tag, #22863a) !important; }
.cm-s-material .cm-attribute { color: var(--shiki-token-attribute, #005cc5) !important; }
.cm-s-material .cm-bracket { color: var(--shiki-token-punctuation, #24292e) !important; }
.cm-s-material .cm-punctuation { color: var(--shiki-token-punctuation, #24292e) !important; }
.cm-s-material .cm-link { color: var(--shiki-token-link, #0366d6) !important; }
.cm-s-material .cm-error { color: #f44336 !important; }
}
/* Handle theme toggle */
html[data-theme="light"] .CodeMirror {
background: #f5f7fa !important;
}
html[data-theme="light"] .CodeMirror-gutters {
background: #f5f7fa !important;
border-right: 1px solid #e5e7eb !important;
}
/* Also apply the same styles to CodeMirror with data-theme */
html[data-theme="light"] .cm-s-material .cm-keyword { color: var(--shiki-token-keyword, #d73a49) !important; }
html[data-theme="light"] .cm-s-material .cm-atom { color: var(--shiki-token-constant, #005cc5) !important; }
html[data-theme="light"] .cm-s-material .cm-number { color: var(--shiki-token-number, #005cc5) !important; }
html[data-theme="light"] .cm-s-material .cm-def { color: var(--shiki-token-function, #6f42c1) !important; }
html[data-theme="light"] .cm-s-material .cm-variable { color: var(--shiki-token-variable, #24292e) !important; }
html[data-theme="light"] .cm-s-material .cm-variable-2 { color: var(--shiki-token-variable, #24292e) !important; }
html[data-theme="light"] .cm-s-material .cm-variable-3 { color: var(--shiki-token-variable, #24292e) !important; }
html[data-theme="light"] .cm-s-material .cm-property { color: var(--shiki-token-property, #005cc5) !important; }
html[data-theme="light"] .cm-s-material .cm-operator { color: var(--shiki-token-operator, #d73a49) !important; }
html[data-theme="light"] .cm-s-material .cm-comment { color: var(--shiki-token-comment, #6a737d) !important; }
html[data-theme="light"] .cm-s-material .cm-string { color: var(--shiki-token-string, #22863a) !important; }
html[data-theme="light"] .cm-s-material .cm-string-2 { color: var(--shiki-token-string, #22863a) !important; }
html[data-theme="light"] .cm-s-material .cm-tag { color: var(--shiki-token-tag, #22863a) !important; }
html[data-theme="light"] .cm-s-material .cm-attribute { color: var(--shiki-token-attribute, #005cc5) !important; }
html[data-theme="light"] .cm-s-material .cm-bracket { color: var(--shiki-token-punctuation, #24292e) !important; }
html[data-theme="light"] .cm-s-material .cm-punctuation { color: var(--shiki-token-punctuation, #24292e) !important; }
html[data-theme="light"] .cm-s-material .cm-link { color: var(--shiki-token-link, #0366d6) !important; }
html[data-theme="light"] .cm-s-material .cm-error { color: #f44336 !important; }
/* Mobile adjustments */
@media (max-width: 767px) {
${host} {
height: 50vh;
max-width: 100%;
}
${host} main {
flex-grow: 1;
display: flex;
flex-direction: column;
}
${host} main > * {
width: 100%;
max-width: 100% !important;
}
} }
`; `;

View File

@ -26,7 +26,7 @@ function ddeComponent({ attr }){
on.connected(e=> console.log(( /** @type {HTMLParagraphElement} */ (e.target)).outerHTML)), on.connected(e=> console.log(( /** @type {HTMLParagraphElement} */ (e.target)).outerHTML)),
); );
return el().append( return el().append(
el("p", S(()=> `Hello from Custom Element with attribute '${attr()}'`)) el("p", S(()=> `Hello from Custom Element with attribute '${attr.get()}'`))
); );
} }
customElementWithDDE(HTMLCustomElement); customElementWithDDE(HTMLCustomElement);

View File

@ -0,0 +1,15 @@
// Debugging a (derived) signal with `console.log`
import { S } from "deka-dom-el/signals";
const name= S("Alice");
const greeting = S(() => {
// log derived signals
const log = "Hello, " + name.get();
console.log(log);
console.log(name.valueOf());
return log;
});
// log signals in general
S.on(greeting, value => console.log("Greeting changed to:", value));
name.set("Bob"); // Should trigger computation and listener`)

View File

@ -0,0 +1,15 @@
import { S } from "deka-dom-el/signals";
// Debouncing signal updates
function debounce(func, wait) {
let timeout;
return (...args)=> {
clearTimeout(timeout);
timeout= setTimeout(() => func(...args), wait);
};
}
const inputSignal= S("");
const debouncedSet= debounce(value => inputSignal.set(value), 300);
// In your input handler
inputElement.addEventListener("input", e=> debouncedSet(e.target.value));

View File

@ -0,0 +1,4 @@
// Example of reactive element marker
<!--<dde:mark type=\"reactive\" source=\"...\">-->
<!-- content that updates when signal changes -->
<!--</dde:mark>-->

View File

@ -0,0 +1,15 @@
import { S } from "deka-dom-el/signals";
// Wrong - direct mutation doesn't trigger updates
const todos1 = S([{ text: "Learn signals", completed: false }]);
todos1.get().push({ text: "Debug signals", completed: false }); // Won't trigger updates!
// Correct - using .set() with a new array
todos1.set([...todos1.get(), { text: "Debug signals", completed: false }]);
// Better - using actions
const todos2 = S([], {
add(text) {
this.value.push({ text, completed: false });
}
});
S.action(todos2, "add", "Debug signals");

View File

@ -0,0 +1,14 @@
import { el } from "deka-dom-el";
// Create element with properties
const button = el("button", {
textContent: "Click me",
className: "primary",
disabled: true
});
// Shorter and more expressive
// than the native approach
// Add to DOM
document.body.append(button);

View File

@ -0,0 +1,11 @@
import { el } from "deka-dom-el";
// Chainable, natural nesting
// append() returns parent element
// making chains easy and intuitive
document.body.append(
el("div").append(
el("h1", "Title"),
el("p", "Paragraph")
)
);

View File

@ -0,0 +1,19 @@
// Create element with properties
const button = document.createElement('button');
button.textContent = "Click me";
button.className = "primary";
button.disabled = true;
// Or using Object.assign()
const button2 = Object.assign(
document.createElement('button'),
{
textContent: "Click me",
className: "primary",
disabled: true
}
);
// Add to DOM
document.body.appendChild(button);
document.body.appendChild(button2);

View File

@ -0,0 +1,15 @@
// Verbose, needs temp variables
const div = document.createElement('div');
const h1 = document.createElement('h1');
h1.textContent = 'Title';
div.appendChild(h1);
const p = document.createElement('p');
p.textContent = 'Paragraph';
div.appendChild(p);
// appendChild doesn't return parent
// so chaining is not possible
// Add to DOM
document.body.appendChild(div);

View File

@ -0,0 +1,8 @@
import { el, on } from "deka-dom-el";
// Third approach - append with on addon
el("button", {
textContent: "click me"
}).append(
on("click", (e) => console.log("Clicked!", e))
);

View File

@ -0,0 +1,7 @@
import { el } from "deka-dom-el";
// Using events with HTML attribute style
el("button", {
textContent: "click me",
"=onclick": "console.log(event)"
});

View File

@ -0,0 +1,8 @@
import { el, on } from "deka-dom-el";
// Using events as addons - chainable approach
el("button", {
textContent: "click me",
},
on("click", (e) => console.log("Clicked!", e))
);

View File

@ -0,0 +1,2 @@
// Standard DOM event listener approach
element.addEventListener('click', callback, options);

View File

@ -0,0 +1,7 @@
import { el } from "deka-dom-el";
// Using events with property assignment
el("button", {
textContent: "click me",
onclick: console.log
});

View File

@ -0,0 +1,14 @@
// pseudocode
// Mixed concerns make code hard to maintain
const button = document.querySelector('button');
let count = 0;
button.addEventListener('click', () => {
count++;
document.querySelector('p').textContent =
'Clicked ' + count + ' times';
if (count > 10) {
button.disabled = true;
}
});

View File

@ -1,6 +1,14 @@
// pseudo code! // pseudocode
const onchage= // 1. Create state
event=> const count = S(0);
console.log("Reacting to the:", event); // A
input.addEventListener("change", onchange); // B // 2. React to state changes
input.dispatchEvent(new Event("change")); // C S.on(count, value => {
updateUI(value);
if (value > 10) disableButton();
});
// 3. Update state on events
button.addEventListener('click', () => {
count.set(count.get() + 1);
});

View File

@ -1,19 +1,30 @@
import { el } from "deka-dom-el"; import { el, on } from "deka-dom-el";
import { S } from "deka-dom-el/signals"; import { S } from "deka-dom-el/signals";
const threePS= ({ emoji= "🚀" })=> {
const clicks= S(0); // A
return el().append(
el("p", S(()=>
"Hello World "+emoji.repeat(clicks()) // B
)),
el("button", {
type: "button",
onclick: ()=> clicks(clicks()+1), // C
textContent: "Fire",
})
);
};
document.body.append(
el(threePS, { emoji: "🎉" }),
);
// A HelloWorld component using the 3PS pattern
function HelloWorld({ emoji = "🚀" }) {
// PART 1: Create reactive state
const clicks = S(0);
return el().append(
// PART 2: Bind state to UI elements
el("p", {
className: "greeting",
// This paragraph automatically updates when clicks changes
textContent: S(() => `Hello World ${emoji.repeat(clicks.get())}`)
}),
// PART 3: Update state in response to events
el("button", {
type: "button",
textContent: "Add emoji",
// When clicked, update the state
onclick: () => clicks.set(clicks.get() + 1)
})
);
}
// Use the component in your app
document.body.append(
el(HelloWorld, { emoji: "🎉" })
);

View File

@ -0,0 +1,37 @@
import { el } from "deka-dom-el";
import { S } from "deka-dom-el/signals";
const className = "client-side-counter";
document.body.append(
el("style").append(`
.${className} {
border: 1px dashed #ccc;
padding: 1em;
margin: 1em;
}
`.trim())
);
export function CounterStandard() {
// Create reactive state with a signal
const count = S(0);
// Create UI components that react to state changes
return el("div", { className }).append(
el("h4", "Client-Side Counter"),
el("div", {
// The textContent updates automatically when count changes
textContent: S(() => `Count: ${count.get()}`),
}),
el("div", { className: "controls" }).append(
el("button", {
onclick: () => count.set(count.get() - 1),
textContent: "-",
}),
el("button", {
onclick: () => count.set(count.get() + 1),
textContent: "+",
})
)
);
}

View File

@ -0,0 +1,14 @@
import { scope } from "deka-dom-el";
import { S } from "deka-dom-el/signals";
function customSignalLogic() {
// Create an isolated scope for a specific operation
scope.push(); // Start new scope
// These signals are in the new scope
const isolatedCount = S(0);
const isolatedDerived = S(() => isolatedCount.get() * 2);
// Clean up by returning to previous scope
scope.pop();
}

View File

@ -1,35 +1,26 @@
/* PSEUDO-CODE!!! */
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
import { S } from "deka-dom-el/signals"; import { S } from "deka-dom-el/signals";
function component(){ function Counter() {
/* prepare changeable data */ // Define state
const dataA= S("data"); const count = S(0);
const dataB= S("data");
/* define data flow (can be asynchronous) */ // Define behavior
fetchAPI().then(data_new=> dataA(data_new)); const increment = () => count.set(count.get() + 1);
setTimeout(()=> dataB("DATA"));
/* declarative UI */ // Define data flow
return el().append( setTimeout(increment, 1000);
el("h1", { // or fetchAPI().then(increment);
textContent: "Example",
/* declarative attribute(s) */ // Declarative UI (how to render data/`count`)
classList: { declarative: dataB } // …automatically updates when changes
}), return el("div").append(
el("ul").append( // declarative element(s)
/* declarative element(s) */ el("p", S(() => "Count: " + count.get())),
S.el(dataA, data=> data.map(d=> el("li", d))) el("button", {
), onclick: increment,
el("ul").append( textContent: "Increment",
/* declarative component(s) */ // declarative attribute(s)
S.el(dataA, data=> data.map(d=> el(subcomponent, d))) disabled: S(() => count.get() >= 10)
) })
); );
} }
function subcomponent({ id }){
/* prepare changeable data */
const textContent= S("…");
/* define data flow (can be asynchronous) */
fetchAPI(id).then(text=> textContent(text));
/* declarative UI */
return el("li", { textContent, dataId: id });
}

View File

@ -1,31 +1,25 @@
/* PSEUDO-CODE!!! */ /* PSEUDO-CODE!!! */
import { el, on, scope } from "deka-dom-el"; import { el, scope } from "deka-dom-el";
function component(){ function Counter() {
const { host }= scope; const { host } = scope;
const ul= el("ul");
const ac= new AbortController(); let count = 0;
fetchAPI({ signal: ac.signal }).then(data=> { const counterText = el("p", "Count: 0");
data.forEach(d=> ul.append(el("li", d)));
}); // Manually update DOM element
host( const increment = () => {
/* element was remove before data fetched */ count++;
on.disconnected(()=> ac.abort()) counterText.textContent = "Count: " + count;
host().querySelector("button").disabled = count >= 10;
};
setTimeout(increment, 1000);
// or fetchAPI().then(increment);
return el("div").append(
counterText,
el("button", {
onclick: increment,
textContent: "Increment"
})
); );
return ul;
/**
* NEVER EVER!!
* let data;
* fetchAPI().then(d=> data= O(d));
*
* OR NEVER EVER!!
* const ul= el("ul");
* fetchAPI().then(d=> {
* const data= O("data");
* ul.append(el("li", data));
* });
*
* // THE HOST IS PROBABLY DIFFERENT THAN
* // YOU EXPECT AND OBSERVABLES MAY BE
* // UNEXPECTEDLY REMOVED!!!
* */
} }

View File

@ -0,0 +1,36 @@
/* PSEUDO-CODE!!! */
import { el, scope } from "deka-dom-el";
import { S } from "deka-dom-el/signals";
function Counter() {
const { host } = scope;
let count = S(0);
const counterText = el("p", "Count: 0");
S.on(count, c=> counterText.textContent= "Count: " + c);
// Manually update DOM element
const increment = () => {
count.set(count.get() + 1);
// NEVER EVER
// count = S(count.get() + 1);
// THE HOST IS PROBABLY DIFFERENT THAN
// YOU EXPECT AND SIGNAL MAY BE
// UNEXPECTEDLY REMOVED!!!
host().querySelector("button").disabled = count.get() >= 10;
};
setTimeout(()=> {
// ok, BUT consider extract to separate function
// see section below for more info
const ok= S(0);
S.on(ok, console.log);
setInterval(()=> ok.set(ok.get() + 1), 100);
}, 100);
return el("div").append(
counterText,
el("button", {
onclick: increment,
textContent: "Increment"
})
);
}

View File

@ -0,0 +1,45 @@
import { el, scope } from "deka-dom-el";
import { S } from "deka-dom-el/signals";
function CounterWithIsolatedTimer() {
const { host } = scope;
// Main component state
const count = S(0);
// Create a timer in an isolated scope
scope.isolate(() => {
// These subscriptions won't be tied to the component lifecycle
// They would continue to run even if the component was removed
const timer = S(0);
// Not recommended for real applications!
// Just demonstrating scope isolation
setInterval(() => {
timer.set(timer.get() + 1);
console.log(`Timer: ${timer.get()}`);
}, 1000);
});
// Normal component functionality within main scope
function increment() {
count.set(count.get() + 1);
}
return el("div").append(
el("p").append(
"Count: ",
el("#text", S(() => count.get()))
),
el("button", {
textContent: "Increment",
onclick: increment
}),
el("p", "An isolated timer runs in console")
);
}
// Usage
document.body.append(
el(CounterWithIsolatedTimer)
);

View File

@ -15,4 +15,4 @@ setTimeout(
clearInterval, clearInterval,
10*interval, 10*interval,
setInterval(oninterval, interval) setInterval(oninterval, interval)
); );

View File

@ -22,9 +22,9 @@ const onsubmit= on("submit", function(event){
S.action(todos, "push", data.get("todo")); S.action(todos, "push", data.get("todo"));
break; break;
case "E"/*dit*/: { case "E"/*dit*/: {
const last= todos().at(-1); const last= todos.get().at(-1);
if(!last) break; if(!last) break;
last(data.get("todo")); last.set(data.get("todo"));
break; break;
} }
case "R"/*emove*/: case "R"/*emove*/:

View File

@ -1,16 +1,16 @@
import { S } from "deka-dom-el/signals"; import { S } from "deka-dom-el/signals";
const signal= S(0); const signal= S(0);
// computation pattern // computation pattern
const double= S(()=> 2*signal()); const double= S(()=> 2*signal.get());
const ac= new AbortController(); const ac= new AbortController();
S.on(signal, v=> console.log("signal", v), { signal: ac.signal }); S.on(signal, v=> console.log("signal", v), { signal: ac.signal });
S.on(double, v=> console.log("double", v), { signal: ac.signal }); S.on(double, v=> console.log("double", v), { signal: ac.signal });
signal(signal()+1); signal.set(signal.get()+1);
const interval= 5 * 1000; const interval= 5 * 1000;
const id= setInterval(()=> signal(signal()+1), interval); const id= setInterval(()=> signal.set(signal.get()+1), interval);
ac.signal.addEventListener("abort", ac.signal.addEventListener("abort",
()=> setTimeout(()=> clearInterval(id), 2*interval)); ()=> setTimeout(()=> clearInterval(id), 2*interval));
setTimeout(()=> ac.abort(), 3*interval) setTimeout(()=> ac.abort(), 3*interval)

View File

@ -0,0 +1,20 @@
import { S } from "deka-dom-el/signals";
// Debugging a derived signal
const name = S('Alice');
const greeting = S(() => {
console.log('Computing greeting...');
return 'Hello, ' + name.get();
});
// Monitor the derived signal
S.on(greeting, value => console.log('Greeting changed to:', value));
// Later update the dependency
name.set('Bob'); // Should trigger computation and listener
// Console output:
// Computing greeting...
// Greeting changed to: Hello, Alice
// Computing greeting...
// Greeting changed to: Hello, Bob

View File

@ -0,0 +1,38 @@
import { el, on, scope } from "deka-dom-el";
import { S } from "deka-dom-el/signals";
// Create a component with reactive elements
function ReactiveCounter() {
const count = S(0);
scope.host(on.connected(ev=>
console.log(ev.target.__dde_reactive)
));
const counter = el('div', {
// This element will be added into the __dde_reactive property
textContent: count,
});
const incrementBtn = el('button', {
textContent: 'Increment',
onclick: () => count.set(count.get() + 1)
});
// Dynamic section will be added into __dde_signal property
const counterInfo = S.el(count, value =>
el('p', `Current count is ${value}`)
);
return el('div', { id: 'counter' }).append(
counter,
incrementBtn,
counterInfo
);
}
document.body.append(
el(ReactiveCounter),
);
// In DevTools console:
const counter = document.querySelector('#counter');
setTimeout(()=> console.log(counter.__dde_reactive), 1000); // See reactive bindings

View File

@ -0,0 +1,13 @@
import { S } from "deka-dom-el/signals";
// Create base signals
const firstName = S("John");
const lastName = S("Doe");
// Create a derived signal
const fullName = S(() => firstName.get() + " " + lastName.get());
// The fullName signal updates automatically when either dependency changes
S.on(fullName, name => console.log("Name changed to:", name));
firstName.set("Jane"); // logs: "Name changed to: Jane Doe"

View File

@ -3,8 +3,8 @@ const count= S(0);
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
document.body.append( document.body.append(
el("p", S(()=> "Currently: "+count())), el("p", S(()=> "Currently: "+count.get())),
el("p", { classList: { red: S(()=> count()%2 === 0) }, dataset: { count }, textContent: "Attributes example" }), el("p", { classList: { red: S(()=> count.get()%2 === 0) }, dataset: { count }, textContent: "Attributes example" }),
); );
document.head.append( document.head.append(
el("style", ".red { color: red; }") el("style", ".red { color: red; }")
@ -12,4 +12,4 @@ document.head.append(
const interval= 5 * 1000; const interval= 5 * 1000;
setTimeout(clearInterval, 10*interval, setTimeout(clearInterval, 10*interval,
setInterval(()=> count(count()+1), interval)); setInterval(()=> count.set(count.get()+1), interval));

View File

@ -2,7 +2,7 @@ import { S } from "deka-dom-el/signals";
const count= S(0, { const count= S(0, {
add(){ this.value= this.value + Math.round(Math.random()*10); } add(){ this.value= this.value + Math.round(Math.random()*10); }
}); });
const numbers= S([ count() ], { const numbers= S([ count.get() ], {
push(next){ this.value.push(next); } push(next){ this.value.push(next); }
}); });
@ -22,5 +22,5 @@ document.body.append(
const interval= 5*1000; const interval= 5*1000;
setTimeout(clearInterval, 10*interval, setInterval(function(){ setTimeout(clearInterval, 10*interval, setInterval(function(){
S.action(count, "add"); S.action(count, "add");
S.action(numbers, "push", count()); S.action(numbers, "push", count.get());
}, interval)); }, interval));

View File

@ -1,10 +1,10 @@
import { S } from "deka-dom-el/signals"; import { S } from "deka-dom-el/signals";
// α — `signal` represents a reactive value // PART 1 — `signal` represents a reactive value
const signal= S(0); const signal= S(0);
// β — just reacts on signal changes // PART 2 — just reacts on signal changes
S.on(signal, console.log); S.on(signal, console.log);
// γ — just updates the value // PART 3 — just updates the value
const update= ()=> signal(signal()+1); const update= ()=> signal.set(signal.get()+1);
update(); update();
const interval= 5*1000; const interval= 5*1000;

View File

@ -0,0 +1,43 @@
// Handling async data in SSR
import { JSDOM } from "jsdom";
import { S } from "deka-dom-el/signals";
import { register, queue } from "deka-dom-el/jsdom";
async function renderWithAsyncData() {
const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>");
const { el } = await register(dom);
// Create a component that fetches data
function AsyncComponent() {
const title= S("-");
const description= S("-");
// Use the queue to track the async operation
queue(fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => {
title.set(data.title);
description.set(data.description);
}));
return el("div", { className: "async-content" }).append(
el("h2", title),
el("p", description)
);
}
// Render the page
dom.window.document.body.append(
el("h1", "Page with Async Data"),
el(AsyncComponent)
);
// IMPORTANT: Wait for all queued operations to complete
await queue();
// Now the HTML includes all async content
const html = dom.serialize();
console.log(html);
}
renderWithAsyncData();

View File

@ -0,0 +1,47 @@
// Basic SSR Example
import { JSDOM } from "jsdom";
import { register, queue } from "deka-dom-el/jsdom";
import { writeFileSync } from "node:fs";
async function renderPage() {
// Create a jsdom instance
const dom = new JSDOM("<!DOCTYPE html><html><head><meta charset=\"utf-8\"></head><body></body></html>");
// Register with deka-dom-el and get the el function
const { el } = await register(dom);
// Create a simple header component
function Header({ title }) {
return el("header").append(
el("h1", title),
el("nav").append(
el("ul").append(
el("li").append(el("a", { href: "/" }, "Home")),
el("li").append(el("a", { href: "/about" }, "About")),
el("li").append(el("a", { href: "/contact" }, "Contact"))
)
)
);
}
// Create the page content
dom.window.document.body.append(
el(Header, { title: "My Static Site" }),
el("main").append(
el("h2", "Welcome!"),
el("p", "This page was rendered with deka-dom-el on the server.")
),
el("footer", "© 2025 My Company")
);
// Wait for any async operations
await queue();
// Get the HTML and write it to a file
const html = dom.serialize();
writeFileSync("index.html", html);
console.log("Page rendered successfully!");
}
renderPage().catch(console.error);

View File

@ -0,0 +1,2 @@
// use NPM or for example https://cdn.jsdelivr.net/gh/jaandrle/deka-dom-el/dist/esm-with-signals.js
import { register, unregister, queue } from "deka-dom-el/jsdom";

View File

@ -0,0 +1,35 @@
// ❌ WRONG: Static imports are hoisted and will register before JSDOM is created
import { register } from "deka-dom-el/jsdom";
import { el } from "deka-dom-el";
import { Header } from "./components/Header.js";
// ✅ CORRECT: Use dynamic imports to ensure proper initialization order
import { JSDOM } from "jsdom";
async function renderPage() {
// 1. Create JSDOM instance first
const dom = new JSDOM(`<!DOCTYPE html><html><body></body></html>`);
// 2. Dynamically import jsdom module
const { register, queue } = await import("deka-dom-el/jsdom");
// 3. Register and get el function
const { el } = await register(dom);
// 4. Dynamically import page components
const { Header } = await import("./components/Header.js");
const { Content } = await import("./components/Content.js");
// 5. Render components
const body = dom.window.document.body;
el(body).append(
el(Header, { title: "My Page" }),
el(Content, { text: "This is server-rendered content" })
);
// 6. Wait for async operations
await queue();
// 7. Get HTML and clean up
return dom.serialize();
}

View File

@ -0,0 +1,27 @@
// Basic jsdom integration example
import { JSDOM } from "jsdom";
import { register, unregister, queue } from "deka-dom-el/jsdom.js";
// Create a jsdom instance
const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>");
// Register the dom with deka-dom-el
const { el } = await register(dom);
// Use deka-dom-el normally
dom.window.document.body.append(
el("div", { className: "container" }).append(
el("h1", "Hello, SSR World!"),
el("p", "This content was rendered on the server.")
)
);
// Wait for any async operations to complete
await queue();
// Get the rendered HTML
const html = dom.serialize();
console.log(html);
// Clean up when done
unregister();

View File

@ -0,0 +1,44 @@
// Building a simple static site generator
import { JSDOM } from "jsdom";
import { register, queue } from "deka-dom-el/jsdom";
import { writeFileSync, mkdirSync } from "node:fs";
async function buildSite() {
// Define pages to build
const pages = [
{ id: "index", title: "Home", component: "./pages/home.js" },
{ id: "about", title: "About", component: "./pages/about.js" },
{ id: "docs", title: "Documentation", component: "./pages/docs.js" }
];
// Create output directory
mkdirSync("./dist", { recursive: true });
// Build each page
for (const page of pages) {
// Create a fresh jsdom instance for each page
const dom = new JSDOM("<!DOCTYPE html><html><head><meta charset=\"utf-8\"></head><body></body></html>");
// Register with deka-dom-el
const { el } = await register(dom);
// Import the page component
const { default: PageComponent } = await import(page.component);
// Render the page with its metadata
dom.window.document.body.append(
el(PageComponent, { title: page.title, pages })
);
// Wait for any async operations
await queue();
// Write the HTML to a file
const html = dom.serialize();
writeFileSync(`./dist/${page.id}.html`, html);
console.log(`Built page: ${page.id}.html`);
}
}
buildSite().catch(console.error);

View File

@ -0,0 +1,88 @@
import { el, queue } from "deka-dom-el";
import { addEventListener, registerClientFile } from "../ssr.js";
import { relative } from "node:path";
const dir= new URL("./", import.meta.url).pathname;
const dirFE= "irelands";
// Track all component instances for client-side rehydration
const componentsRegistry = new Map();
/**
* Creates a component that shows code and its runtime output
* with server-side pre-rendering and client-side rehydration
*
* @param {object} attrs
* @param {URL} attrs.src - Path to the file containing the component
* @param {string} [attrs.exportName="default"] - Name of the export to use
* @param {string} attrs.page_id - ID of the current page
* @param {object} [attrs.props={}] - Props to pass to the component
*/
export function ireland({ src, exportName = "default", props = {} }) {
// relative src against the current directory
const path= "./"+relative(dir, src.pathname);
const id = "ireland-" + generateComponentId(src);
const element = el.mark({ type: "later", name: ireland.name });
queue(import(path).then(module => {
const component = module[exportName];
element.replaceWith(el(component, props, mark(id)));
}));
if(!componentsRegistry.size)
addEventListener("oneachrender", registerClientPart);
componentsRegistry.set(id, {
src,
path: dirFE+"/"+path.split("/").pop(),
exportName,
props,
});
return element;
}
function registerClientPart(){
const todo= Array.from(componentsRegistry.entries())
.map(([ id, d ]) => {
registerClientFile(d.src, {
folder: dirFE,
// not all browsers support importmap
replacer(file){
return file
.replaceAll(/ from "deka-dom-el(\/signals)?";/g, ` from "./esm-with-signals.js";`);
}
});
return [ id, d ];
});
const store = JSON.stringify(JSON.stringify(todo));
registerClientFile(new URL("./ireland.js.js", import.meta.url));
registerClientFile(new URL("../../dist/esm-with-signals.js", import.meta.url), { folder: dirFE });
document.head.append(
// not all browsers support importmap
el("script", { type: "importmap" }).append(`
{
"imports": {
"deka-dom-el": "./${dirFE}/esm-with-signals.js",
"deka-dom-el/signals": "./${dirFE}/esm-with-signals.js"
}
}
`.trim())
);
document.body.append(
el("script", { type: "module" }).append(`
import { loadIrelands } from "./ireland.js.js";
loadIrelands(new Map(JSON.parse(${store})));
`.trim())
)
}
function mark(id) { return el=> el.dataset.ddeMark= id; }
const store_prev= new Map();
/** @param {URL} src */
function generateComponentId(src){
const candidate= parseInt(relative((new URL("..", import.meta.url)).pathname, src.pathname)
.split("")
.map(ch=> ch.charCodeAt(0))
.join(""), 10)
.toString(36)
.replace(/000+/g, "");
const count= 1 + ( store_prev.get(candidate) || 0 );
store_prev.set(candidate, count);
return count.toString()+"-"+candidate;
}

View File

@ -0,0 +1,13 @@
// not all browsers support importmaps
// import { el } from "deka-dom-el";
import { el } from "./irelands/esm-with-signals.js";
export function loadIrelands(store) {
document.body.querySelectorAll("[data-dde-mark]").forEach(ireland => {
const { ddeMark }= ireland.dataset;
if(!store.has(ddeMark)) return;
const { path, exportName, props }= store.get(ddeMark);
import("./"+path).then(module => {
ireland.replaceWith(el(module[exportName], props));
})
});
}

View File

@ -17,8 +17,14 @@ export function mnemonic(){
" — just ", el("code", "<element>.dispatchEvent(new Event(<event>[, <options>]))") " — just ", el("code", "<element>.dispatchEvent(new Event(<event>[, <options>]))")
), ),
el("li").append( el("li").append(
el("code", "dispatchEvent(<event>[, <options>])(element, detail)"), el("code", "dispatchEvent(<event>, <element>)([<detail>])"),
" — just ", el("code", "<element>.dispatchEvent(new CustomEvent(<event>, { detail, ...<options> }))") " — just ", el("code", "<element>.dispatchEvent(new Event(<event>))"), " or ",
el("code", "<element>.dispatchEvent(new CustomEvent(<event>, { detail: <detail> }))")
),
el("li").append(
el("code", "dispatchEvent(<event>[, <options>])(<element>[, <detail>])"),
" — just ", el("code", "<element>.dispatchEvent(new Event(<event>[, <options>] ))"), " or ",
el("code", "<element>.dispatchEvent(new CustomEvent(<event>, { detail: <detail> }))")
), ),
); );
} }

View File

@ -1,18 +1,67 @@
import { pages, styles } from "../ssr.js"; import { pages, styles } from "../ssr.js";
const host= "."+prevNext.name; const host= "."+prevNext.name;
styles.css` styles.css`
${host}{ /* Previous/Next navigation */
display: grid; ${host} {
grid-template-columns: 1fr 2fr 1fr; display: flex;
margin-top: 1rem; justify-content: space-between;
margin-top: 3rem;
padding-top: 1.5rem;
border-top: 1px solid var(--border); border-top: 1px solid var(--border);
gap: 1rem;
width: 100%;
} }
${host} [rel=prev]{
grid-column: 1; ${host} a {
display: flex;
align-items: center;
padding: 0.5rem 0.75rem;
border-radius: var(--border-radius);
background-color: var(--primary-dark); /* Darker background for better contrast */
color: white;
font-weight: 600; /* Bolder text for better readability */
text-decoration: none;
transition: background-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
max-width: 45%;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15); /* Subtle shadow for better visibility */
} }
${host} [rel=next]{
grid-column: 3; ${host} a:hover {
text-align: right; background-color: var(--primary);
transform: translateY(-2px);
text-decoration: none;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); /* Enhanced shadow on hover */
}
${host} [rel=prev] {
margin-right: auto;
}
${host} [rel=next] {
margin-left: auto;
}
${host} [rel=prev]::before {
content: "←";
margin-right: 0.75rem;
font-size: 1.2em;
}
${host} [rel=next]::after {
content: "→";
margin-left: 0.75rem;
font-size: 1.2em;
}
/* If there's no previous/next, ensure the spacing still works */
${host} a:only-child {
margin-left: auto;
}
@media (max-width: 640px) {
${host} a {
font-size: 0.9rem;
}
} }
`; `;
import { el } from "../../index.js"; import { el } from "../../index.js";
@ -22,21 +71,28 @@ import { el } from "../../index.js";
* @param {string} [attrs.id] * @param {string} [attrs.id]
* */ * */
export function h3({ textContent, id }){ export function h3({ textContent, id }){
if(!id) id= "h-"+textContent.toLowerCase().replaceAll(/\s/g, "-").replaceAll(/[^a-z-]/g, ""); if(!id) id= "h-"+textContent.toLowerCase().replaceAll(/\s/g, "-").replaceAll(/[^a-z-]/g, "");
return el("h3", { id }).append( return el("h3", { id }).append(
el("a", { textContent: "#", href: "#"+id, tabIndex: -1 }), el("a", {
" ", textContent className: "heading-anchor",
); href: "#"+id,
textContent: "#",
title: `Link to this section: ${textContent}`,
"aria-label": `Link to section ${textContent}`
}),
" ",
textContent,
);
} }
/** /**
* @param {import("../types.d.ts").Info} page * @param {import("../types.d.ts").Info} page
* */ * */
export function prevNext(page){ export function prevNext(page){
const page_index= pages.indexOf(page); const page_index= pages.indexOf(page);
return el("div", { className: prevNext.name }).append( return el("div", { className: prevNext.name }).append(
el(pageLink, { rel: "prev", page: pages[page_index-1] }), el(pageLink, { rel: "prev", page: pages[page_index-1] }),
el(pageLink, { rel: "next", page: pages[page_index+1] }) el(pageLink, { rel: "next", page: pages[page_index+1] })
); );
} }
/** /**
* @param {Object} attrs * @param {Object} attrs
@ -44,11 +100,22 @@ export function prevNext(page){
* @param {import("../types.d.ts").Info} [attrs.page] * @param {import("../types.d.ts").Info} [attrs.page]
* */ * */
function pageLink({ rel, page }){ function pageLink({ rel, page }){
if(!page) return el(); if(!page) return el();
let { href, title, description }= page; let { href, title, description }= page;
return el("a", { rel, href, title: description }).append(
rel==="next" ?"(next) " : "", // Find the page index to show numbering
title, const pageIndex = pages.findIndex(p => p === page);
rel==="prev" ? " (previous)" : "", const pageNumber = pageIndex + 1;
);
const linkTitle = rel === "prev"
? `Previous: ${pageNumber}. ${title}`
: `Next: ${pageNumber}. ${title}`;
return el("a", {
rel,
href,
title: description || linkTitle
}).append(
title
);
} }

View File

@ -1,124 +1,476 @@
import { styles } from "./ssr.js"; import { styles } from "./ssr.js";
styles.css` styles.css`
@import url(https://cdn.simplecss.org/simple.min.css); :root {
:root{ --primary: hsl(0, 74%, 42%);
--body-max-width: 45rem; --primary-light: hsl(5, 87%, 61%);
--marked: #fb3779; --primary-dark: hsl(0, 100%, 25%);
--code: #0d47a1; --primary-hs: 0, 74%;
--accent: #d81b60; --secondary: hsl(330, 100%, 22%);
--secondary-light: hsl(339, 80%, 38%);
--secondary-dark: hsl(328, 100%, 15%);
--secondary-hs: 330, 100%;
--font-main: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
--font-mono: 'Fira Code', 'JetBrains Mono', 'SF Mono',
SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;
--body-max-width: 40rem;
--sidebar-width: 20rem;
--header-height: 4rem;
--border-radius: 0.375rem;
--bg: hsl(0, 0%, 100%);
--bg-sidebar: hsl(0, 100%, 98%);
--text: hsl(0, 16%, 15%);
--text-light: hsl(0, 4%, 33%);
--code-bg: hsl(0, 39%, 97%);
--code-text: hsl(0, 100%, 30%);
--border: hsl(0, 32%, 80%);
--selection: hsl(var(--primary-hs), 90%);
--marked: var(--primary);
--accent: var(--secondary);
--shadow: 0 2px 6px hsla(0, 0%, 0%, 0.15);
--shadow-sm: 0 2px 4px hsla(0, 0%, 0%, 0.15);
--link-color: hsl(0, 100%, 30%);
--link-hover: hsl(0, 100%, 25%);
--button-text: hsl(0, 0%, 100%);
} }
@media (prefers-color-scheme:dark) {
@media (prefers-color-scheme: dark) {
:root { :root {
--accent: #f06292; --bg: hsl(0, 0%, 7%);
--code: #62c1f0; --bg-sidebar: hsl(0, 9%, 9%);
--text: hsl(0, 0%, 100%);
--text-light: hsl(0, 0%, 80%);
--code-bg: hsl(0, 18%, 15%);
--code-text: hsl(20, 100%, 75%);
--border: hsl(0, 14%, 27%);
--selection: hsla(9, 100%, 64%, 0.25);
--primary: hsl(0, 48%, 49%);
--primary-light: hsl(5, 100%, 75%);
--primary-dark: hsl(0, 67%, 47%);
--secondary: hsl(350, 87%, 55%);
--secondary-light: hsl(341, 100%, 69%);
--secondary-dark: hsl(340, 100%, 35%);
--accent: var(--secondary);
--link-color: hsl(0, 100%, 66%);
--link-hover: hsl(5, 100%, 75%);
--button-text: hsl(0, 0%, 100%);
--primary-hs: 0, 48%;
--secondary-hs: 350, 87%;
} }
} }
body {
grid-template-columns: 100%; /* Base styling */
grid-template-areas: "header" "sidebar" "content"; * {
box-sizing: border-box;
} }
@media (min-width:768px) {
body{ html {
grid-template-rows: auto auto; scroll-behavior: smooth;
grid-template-columns: calc(10 * var(--body-max-width) / 27) auto; }
grid-template-areas:
"header header" /* Accessibility improvements */
"sidebar content" :focus {
outline: 3px solid hsl(231, 48%, 70%);
outline-offset: 2px;
}
:focus:not(:focus-visible) {
outline: none;
}
:focus-visible {
outline: 3px solid hsl(231, 48%, 70%);
outline-offset: 2px;
}
/* Ensure reduced motion preferences are respected */
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
} }
} }
body > *{
grid-column: unset; /* Skip link for better keyboard navigation */
} .skip-link {
body > header{ position: absolute;
grid-area: header; top: 0;
padding: 0; left: 0;
} transform: translateX(-100%);
body > nav{ z-index: 9999;
grid-area: sidebar; background-color: var(--primary);
background-color: var(--accent-bg); color: white;
display: flex; padding: 0.5rem 1rem;
flex-flow: column nowrap;
}
body > nav {
font-size: 1rem;
line-height: 2;
padding: 1rem 0 0 0;
}
body > nav ol,
body > nav ul {
align-content: space-around;
align-items: center;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
list-style-type: none;
margin: 0;
padding: 0;
}
body > nav ol li,
body > nav ul li {
display:inline-block
}
body > nav a,
body > nav a:visited {
margin: 0 .5rem 1rem .5rem;
border: 1px solid currentColor;
border-radius: var(--standard-border-radius);
color: var(--text-light);
display: inline-block;
padding: .1rem 1rem;
text-decoration: none; text-decoration: none;
cursor: pointer; transition: transform 0.3s ease-in-out;
transition: all .15s;
} }
body > nav a.current,
body > nav a[aria-current=page] { .skip-link:focus {
background-color: var(--bg); transform: translateX(0);
}
/* Typography */
::selection {
background-color: var(--selection);
}
h1, h2, h3, h4, h5, h6 {
margin-bottom: 1rem;
margin-top: 2rem;
font-weight: 700;
line-height: 1.25;
color: var(--text); color: var(--text);
} }
body > nav a:hover{
h1 {
font-size: 2.25rem;
margin-top: 0;
color: var(--primary-dark);
}
h1 > a {
font-weight: unset;
color: unset;
}
h3 {
font-size: 1.25rem;
color: var(--secondary);
}
p {
margin-bottom: 1.5rem;
}
a {
color: var(--link-color, var(--primary));
transition: color 0.2s ease;
font-weight: 500;
text-underline-offset: 3px;
transition: color 0.2s ease, text-underline-offset 0.2s ease;
}
a:visited {
--link-color: var(--secondary, #700037);
}
a:hover {
--link-color: var(--link-hover, var(--primary-light));
text-underline-offset: 5px;
}
code, pre {
font-family: var(--font-mono);
font-size: 0.9em;
border-radius: var(--border-radius);
}
code {
background-color: var(--code-bg);
color: var(--code-text);
padding: 0.2em 0.4em;
word-wrap: break-word;
}
pre {
background-color: var(--code-bg);
padding: 1rem;
overflow-x: auto;
margin-bottom: 1.5rem;
border: 1px solid var(--border);
}
pre code {
background-color: transparent;
padding: 0;
}
/* Layout */
body {
font-family: var(--font-main);
background-color: var(--bg); background-color: var(--bg);
color: var(--accent); color: var(--text);
line-height: 1.6;
font-size: 1.05rem;
display: grid;
grid-template-columns: 100%;
grid-template-areas:
"header"
"sidebar"
"content";
min-height: 100vh;
margin: 0;
--_gap: .75em;
gap: var(--_gap);
padding: var(--_gap);
} }
@media only screen and (max-width:720px) { @media (min-width: 768px) {
body > nav{ body {
flex-flow: row wrap; grid-template-rows: var(--header-height) 1fr;
padding-block: .5rem; grid-template-columns: var(--sidebar-width) 1fr;
} grid-template-areas:
body > nav a { "header header"
border:none; "sidebar content";
text-decoration:underline;
margin-block: .1rem;
padding-block:.1rem;
line-height: 1rem;
font-size: .9rem;
} }
} }
main{ body > main {
grid-area: content; grid-area: content;
max-width: 100%;
overflow-x: hidden;
display: grid; display: grid;
grid-template-columns: grid-template-columns:
[full-main-start] 1fr [full-main-start] 1fr
[main-start] min(var(--body-max-width), 90%) [main-end] [main-start] min(var(--body-max-width), 90%) [main-end]
1fr [full-main-end]; 1fr [full-main-end];
} }
main > *, main slot > *{ body > main > *, body > main slot > * {
width: 100%;
max-width: 100%;
margin-inline: auto;
grid-column: main; grid-column: main;
} }
/* Page title with ID anchor for skip link */
h2 {
margin-top: 0;
border-bottom: 1px solid var(--border);
padding-bottom: 0.75rem;
margin-bottom: 1.5rem;
color: var(--primary);
}
/* Section headings with better visual hierarchy */
body > main h3, body > main h4 {
scroll-margin-top: calc(var(--header-height) + 1rem);
}
/* Make clickable heading links for better navigation */
.heading-anchor {
color: var(--text-light);
text-decoration: none;
font-weight: normal;
opacity: .4;
transition: opacity .2s;
&:hover { opacity: .8; }
}
/* Boxes */
.illustration{
grid-column: full-main;
width: calc(100% - .75em);
}
.illustration:not(:has( .comparison)){
grid-column: main;
pre {
background: none;
border-style: dashed !important;
width: fit-content;
padding: 1em 2em;
}
}
.comparison {
display: grid;
grid-template-columns: 1fr;
gap: calc(.75em / 2);
margin: 1.5rem 0;
> div {
width: 100%;
overflow: hidden;
}
}
@media (min-width: 768px) {
.comparison {
grid-template-columns: 1fr 1fr;
}
}
.good-practice, .bad-practice {
border: 1px solid var(--border);
border-radius: var(--border-radius);
border-top: 4px solid var(--practice-color);
padding: 0 1rem;
}
.good-practice {
--practice-color: hsl(145, 63%, 49%); }
.bad-practice {
--practice-color: hsl(340, 82%, 52%); }
/* Icon styling */
.icon { .icon {
vertical-align: sub;
padding-right: .25rem;
display: inline-block; display: inline-block;
width: 1em; width: 1em;
height: 1.3em; height: 1em;
margin-right: 0.2rem; vertical-align: -0.125em;
stroke-width: 0; stroke-width: 0;
stroke: currentColor; stroke: currentColor;
fill: currentColor; fill: currentColor;
} }
.note{
font-size: .9rem; /* Information blocks */
font-style: italic; .note, .tip, .warning, .callout, .troubleshooting {
padding: 1rem 1.25rem;
margin: 1.5rem 0;
border-radius: var(--border-radius);
position: relative;
font-size: 0.95rem;
line-height: 1.5;
background-color: var(--bg-sidebar);
border-radius: 0 var(--border-radius) var(--border-radius) 0;
--block-color: var(--primary);
border-left: 4px solid var(--block-color);
h4 { margin-top: 0; }
}
.tip {
--block-color: hsl(145, 63%, 49%); }
.warning {
--block-color: hsl(48, 89%, 50%); }
.callout {
--block-color: hsl(231, 48%, 70%); }
.troubleshooting {
--block-color: hsl(340, 82%, 52%); }
.note::before, .tip::before, .warning::before, .callout::before, .troubleshooting::before {
font-weight: 600;
display: block;
margin-bottom: 0.5rem;
color: var(--block-color);
}
.note::before {
content: "Note"; }
.warning::before {
content: "Warning"; }
/* Function table styling */
.function-table {
border: 1px solid var(--border);
border-radius: var(--border-radius);
padding: 1rem;
margin: 1.5rem 0;
background-color: var(--bg-sidebar);
}
.function-table h4 {
margin-top: 0;
color: var(--primary);
font-family: var(--font-mono);
border-bottom: 1px solid var(--border);
padding-bottom: 0.5rem;
margin-bottom: 1rem;
}
.function-table dl {
margin: 0;
}
.function-table dt {
font-weight: 600;
margin-top: 0.75rem;
}
.function-table dd {
margin-left: 1rem;
margin-bottom: 0.75rem;
white-space: pre-wrap;
word-wrap: break-word;
}
/* Tabs styling */
.tabs {
border: 1px solid var(--border);
border-radius: var(--border-radius);
margin: 1.5rem 0;
overflow: hidden;
}
.tab {
padding: 1rem;
border-top: 1px solid var(--border);
}
.tab:first-child {
border-top: none;
}
.tab h4 {
margin-top: 0;
margin-bottom: 0.75rem;
font-size: 1.1rem;
}
@media (min-width: 768px) {
.tabs {
display: flex;
flex-flow: row wrap;
}
.tab {
flex: 1;
min-width: 50%;
border-top: none;
display: flex;
flex-flow: column nowrap;
align-items: center;
text-align: justify;
}
.tab:first-child {
border-inline-end: 1px solid var(--border);
}
}
/* Prev/Next buttons */
.prev-next {
display: flex;
justify-content: space-between;
margin-top: 3rem;
padding-top: 1.5rem;
border-top: 1px solid var(--border);
}
.prev-next a {
display: flex;
align-items: center;
padding: 0.5rem 1rem;
border-radius: var(--border-radius);
background-color: var(--primary);
color: white;
transition: background-color 0.2s ease;
}
.prev-next a:hover {
background-color: var(--primary-dark);
text-decoration: none;
}
.prev-next a:empty {
display: none;
}
.prev-next a[rel="prev"]::before {
content: "←";
margin-right: 0.5rem;
}
.prev-next a[rel="next"]::after {
content: "→";
margin-left: 0.5rem;
} }
`; `;

View File

@ -2,7 +2,8 @@ import { t, T } from "./utils/index.js";
export const info= { export const info= {
href: "./", href: "./",
title: t`Introduction`, title: t`Introduction`,
description: t`Introducing a library.`, fullTitle: t`Vanilla for flavouring — a full-fledged feast for large projects`,
description: t`A lightweight, reactive DOM library for creating dynamic UIs with a declarative syntax`,
}; };
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
@ -26,37 +27,90 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("p", t`The library tries to provide pure JavaScript tool(s) to create reactive interfaces using …`),
el(h3, t`Event-driven programming (3 parts separation ≡ 3PS)`),
el("p").append(t`
Let's introduce the basic principle on which the library is built. We'll use the JavaScript listener as
a starting point.
`),
el(code, { src: fileURL("./components/examples/introducing/3ps.js"), page_id }),
el("p").append(...T` el("p").append(...T`
As we can see, in the code at location A we define ${el("em", t`how to react`)} when the function Welcome to Deka DOM Elements (DDE) a lightweight library for building dynamic UIs with a declarative
is called with any event as an argument. At that moment, we ${el("em", t`dont care who/why/how`)} syntax that stays close to the native DOM API. DDE gives you powerful reactive tools without the complexity
the function was called. Similarly, at point B, we reference to a function to be called on the event and overhead of larger frameworks.
${el("em", t`without caring`)} what the function will do at that time. Finally, at point C, we tell
the application that a change has occurred, in the input, and we ${el("em", t`don't care if/how someone`)}
is listening for the event.
`), `),
el("div", { className: "callout" }).append(
el("h4", t`What Makes DDE Special`),
el("ul").append(
el("li", t`No build step required — use directly in the browser`),
el("li", t`Lightweight core (~1015kB minified) with zero dependencies`),
el("li", t`Natural DOM API — work with real DOM nodes, not abstractions`),
el("li", t`Built-in reactivity with powerful signals system`),
el("li", t`Clean code organization with the 3PS pattern`)
)
),
el(example, { src: fileURL("./components/examples/introducing/helloWorld.js"), page_id }), el(example, { src: fileURL("./components/examples/introducing/helloWorld.js"), page_id }),
el(h3, { textContent: t`The 3PS Pattern: A Better Way to Build UIs`, id: "h-3ps" }),
el("p").append(...T` el("p").append(...T`
The library introduces a new type of variable/constant called ${el("em", t`signal`)} allowing us to At the heart of DDE is the 3PS (3-Part Separation) pattern. This simple yet powerful approach helps you
to use introduced 3PS pattern in our applications. As you can see it in the example above. organize your UI code into three distinct areas, making your applications more maintainable and easier
to reason about.
`), `),
el("div", { className: "illustration" }).append(
el("div", { className: "tabs" }).append(
el("div", { className: "tab" }).append(
el("h5", t`Traditional DOM Manipulation`),
el(code, { src: fileURL("./components/examples/introducing/3ps-before.js"), page_id }),
),
el("div", { className: "tab" }).append(
el("h5", t`DDE's 3PS Pattern`),
el(code, { src: fileURL("./components/examples/introducing/3ps.js"), page_id }),
)
)
),
el("p").append(...T` el("p").append(...T`
Also please notice that there is very similar 3PS pattern used for separate creation of UI and The 3PS pattern separates your code into three clear parts:
business logic.
`), `),
el("ol").append(
el("li").append(...T`
${el("strong", "Create State")}: Define your application's reactive data using signals
`),
el("li").append(...T`
${el("strong", "Bind to Elements")}: Define how UI elements react to state changes
`),
el("li").append(...T`
${el("strong", "Update State")}: Modify state in response to user events or other triggers
`)
),
el("p").append(...T` el("p").append(...T`
The 3PS is very simplified definition of the pattern. There are more deep/academic definitions more precisely By separating these concerns, your code becomes more modular, testable, and easier to maintain. This
describe usage in specific situations, see for example ${el("a", { textContent: t`MVVM`, ...references.w_mvv })} approach shares principles with more formal patterns like ${el("a", { textContent: "MVVM",
or ${el("a", { textContent: t`MVC`, ...references.w_mvc })}. ...references.w_mvv })} and ${el("a", { textContent: "MVC", ...references.w_mvc })}, but with less
overhead and complexity.
`), `),
el(h3, t`Organization of the documentation`), el("div", { className: "note" }).append(
el("p").append(...T`
The 3PS pattern becomes especially powerful when combined with components, allowing you to create
reusable pieces of UI with encapsulated state and behavior. You'll learn more about this in the
following sections.
`)
),
el(h3, t`How to Use This Documentation`),
el("p").append(...T`
This guide will take you through DDE's features step by step:
`),
el("ol").append(
el("li").append(...T`${el("strong", "Elements")} — Creating and manipulating DOM elements`),
el("li").append(...T`${el("strong", "Events")} — Handling user interactions and lifecycle events`),
el("li").append(...T`${el("strong", "Signals")} — Adding reactivity to your UI`),
el("li").append(...T`${el("strong", "Scopes")} — Managing component lifecycles`),
el("li").append(...T`${el("strong", "Custom Elements")} — Building web components`),
el("li").append(...T`${el("strong", "Debugging")} — Tools to help you build and fix your apps`),
el("li").append(...T`${el("strong", "Extensions")} — Integrating third-party functionalities`),
el("li").append(...T`${el("strong", "Ireland Components")}
Creating interactive demos with server-side pre-rendering`),
el("li").append(...T`${el("strong", "SSR")} — Server-side rendering with DDE`)
),
el("p").append(...T`
Each section builds on the previous ones, so we recommend following them in order.
Let's get started with the basics of creating elements!
`),
); );
} }

View File

@ -1,38 +1,220 @@
import { el, elNS } from "deka-dom-el"; import { el, elNS } from "deka-dom-el";
import { pages } from "../ssr.js"; import { pages, styles } from "../ssr.js";
const host= "."+header.name;
const host_nav= "."+nav.name;
styles.css`
/* Header */
${host} {
grid-area: header;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
padding: 0.75rem 1.5rem;
background-color: var(--primary);
color: white;
box-shadow: var(--shadow);
height: fit-content;
border-radius: var(--border-radius);
}
${host} .header-title {
display: flex;
align-items: center;
gap: 0.75rem;
}
${host} h1 {
font-size: 1.25rem;
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: white;
}
${host} .version-badge {
font-size: 0.75rem;
background-color: hsla(0, 0%, 59%, 0.2);
padding: 0.25rem 0.5rem;
border-radius: var(--border-radius);
}
${host} p {
display: block;
font-size: 0.875rem;
opacity: 0.9;
margin: 0;
}
${host_nav} .github-link {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.9rem;
}
/* Navigation */
${host_nav} {
grid-area: sidebar;
background-color: var(--bg-sidebar);
border: 1px solid var(--border);
border-radius: var(--border-radius);
padding: 1rem;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
${host_nav} a {
display: flex;
align-items: center;
padding: 0.625rem 0.75rem;
border-radius: var(--border-radius);
color: var(--text);
transition: background-color 0.1s ease, color 0.1s ease, transform 0.1s ease, box-shadow 0.1s ease;
line-height: 1.2;
}
${host_nav} a[aria-current=page] {
background-color: hsl(var(--primary-hs), 40%);
color: whitesmoke;
font-weight: 600;
box-shadow: var(--shadow);
text-decoration: none;
}
${host_nav} a:hover {
background-color: hsl(var(--primary-hs), 45%);
color: whitesmoke;
transform: translateY(-1px);
text-decoration: none;
}
${host_nav} a .nav-number {
color: rgb(from currentColor r g b / .75);
}
@media (min-width: 768px) {
${host_nav} {
height: fit-content;
position: sticky;
top: .5rem;
}
}
@media (max-width: 767px) {
${host_nav} {
padding: 0.75rem;
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 0.5rem;
border-bottom: 1px solid var(--border);
border-right: none;
justify-content: center;
}
${host_nav} a {
font-size: 0.875rem;
padding: 0.375rem 0.75rem;
white-space: nowrap;
}
${host_nav} a .nav-number {
width: auto;
margin-right: 0.25rem;
}
${host_nav} a:first-child {
margin-bottom: 0;
margin-right: 0.5rem;
min-width: 100%;
justify-content: center;
}
}
`;
/** /**
* @param {object} def * @param {object} def
* @param {import("../types.d.ts").Info} def.info * @param {import("../types.d.ts").Info} def.info
* @param {import("../types.d.ts").Pkg} def.pkg Package information. * @param {import("../types.d.ts").Pkg} def.pkg Package information.
* */ * */
export function header({ info: { href, title, description }, pkg }){ export function header({ info: { href, title, description }, pkg }){
title= `\`${pkg.name}\`${title}`; const pageTitle = `${pkg.name}${title}`;
// Add meta elements to the head
document.head.append( document.head.append(
head({ title, description, pkg }) head({ title: pageTitle, description, pkg })
); );
return el().append( return el().append(
el("header").append( // Header section with accessibility support
el("h1", title), el("header", { role: "banner", className: header.name }).append(
el("p", description) el("div", { className: "header-title" }).append(
), el("img", {
el("nav").append( src: "assets/logo.svg",
el("a", { href: pkg.homepage }).append( alt: "DDE Logo",
el(iconGitHub), width: "32",
"GitHub" height: "32",
style: "margin-right: 0.5rem;"
}),
el("h1").append(
el("a", { href: pages[0].href, textContent: pkg.name, title: "Go to documentation homepage" }),
),
el("span", {
className: "version-badge",
"aria-label": "Version",
textContent: pkg.version || ""
})
), ),
...pages.map((p, i)=> el("a", { el("p", description),
href: p.href==="index" ? "./" : p.href, ),
textContent: (i+1) + ". " + p.title,
title: p.description, // Navigation between pages
classList: { current: p.href===href } nav({ href, pkg })
})) );
) }
function nav({ href, pkg }){
return el("nav", {
role: "navigation",
"aria-label": "Main navigation",
className: nav.name
}).append(
el("a", {
href: pkg.homepage,
className: "github-link",
"aria-label": "View on GitHub",
target: "_blank",
rel: "noopener noreferrer",
}).append(
el(iconGitHub),
"GitHub"
),
...pages.map((p, i) => {
const isIndex = p.href === "index";
const isCurrent = p.href === href;
return el("a", {
href: isIndex ? "./" : p.href,
title: p.description || `Go to ${p.title}`,
"aria-current": isCurrent ? "page" : null,
}).append(
el("span", {
className: "nav-number",
"aria-hidden": "true",
textContent: `${i+1}. `
}),
p.title
);
}),
); );
} }
function head({ title, description, pkg }){ function head({ title, description, pkg }){
return el().append( return el().append(
el("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }), el("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
el("meta", { name: "description", content: description }), el("meta", { name: "description", content: description }),
el("meta", { name: "theme-color", content: "#b71c1c" }),
el("link", { rel: "icon", href: "assets/favicon.svg", type: "image/svg+xml" }),
el("title", title), el("title", title),
el(metaAuthor), el(metaAuthor),
el(metaTwitter, pkg), el(metaTwitter, pkg),
@ -53,7 +235,7 @@ function metaTwitter({ name, description, homepage }){
el("meta", { name: "twitter:url", content: homepage }), el("meta", { name: "twitter:url", content: homepage }),
el("meta", { name: "twitter:title", content: name }), el("meta", { name: "twitter:title", content: name }),
el("meta", { name: "twitter:description", content: description }), el("meta", { name: "twitter:description", content: description }),
//el("meta", { name: "twitter:image", content: "" }), el("meta", { name: "twitter:image", content: homepage + "/assets/logo.svg" }),
el("meta", { name: "twitter:creator", content: "@jaandrle" }), el("meta", { name: "twitter:creator", content: "@jaandrle" }),
); );
} }
@ -62,7 +244,7 @@ function metaFacebook({ name, description, homepage }){
el("meta", { name: "og:url", content: homepage }), el("meta", { name: "og:url", content: homepage }),
el("meta", { name: "og:title", content: name }), el("meta", { name: "og:title", content: name }),
el("meta", { name: "og:description", content: description }), el("meta", { name: "og:description", content: description }),
//el("meta", { name: "og:image", content: "" }), el("meta", { name: "og:image", content: homepage + "/assets/logo.svg" }),
el("meta", { name: "og:creator", content: "@jaandrle" }), el("meta", { name: "og:creator", content: "@jaandrle" }),
); );
} }

View File

@ -7,9 +7,24 @@ import { prevNext } from "../components/pageUtils.html.js";
/** @param {Pick<import("../types.d.ts").PageAttrs, "pkg" | "info">} attrs */ /** @param {Pick<import("../types.d.ts").PageAttrs, "pkg" | "info">} attrs */
export function simplePage({ pkg, info }){ export function simplePage({ pkg, info }){
return simulateSlots(el().append( return simulateSlots(el().append(
// Skip link for keyboard navigation
el("a", {
href: "#main-content",
className: "skip-link",
textContent: "Skip to main content"
}),
// Header with site information
el(header, { info, pkg }), el(header, { info, pkg }),
el("main").append(
// Main content area
el("main", { id: "main-content", role: "main" }).append(
el("h2", { textContent: info.fullTitle || info.title }),
// Main content from child elements
el("slot"), el("slot"),
// Navigation between pages
el(prevNext, info) el(prevNext, info)
) )
)); ));

View File

@ -1,7 +1,8 @@
import { T, t } from "./utils/index.js"; import { T, t } from "./utils/index.js";
export const info= { export const info= {
title: t`Elements`, title: t`Elements`,
description: t`Basic concepts of elements modifications and creations.`, fullTitle: t`Declarative DOM Element Creation`,
description: t`Building user interfaces with declarative DOM element creation.`,
}; };
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
@ -48,107 +49,154 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("h2", t`Native JavaScript DOM elements creations`), el("p").append(...T`
el("p", t` Building user interfaces in JavaScript often involves creating and manipulating DOM elements.
Lets go through all patterns we would like to use and what needs to be improved for better experience. DDE provides a simple yet powerful approach to element creation that is declarative, chainable,
and maintains a clean syntax close to HTML structure.
`), `),
el("div", { class: "callout" }).append(
el("h4", t`DDE Elements: Key Benefits`),
el("ul").append(
el("li", t`Declarative element creation with intuitive property assignment`),
el("li", t`Chainable methods for natural DOM tree construction`),
el("li", t`Simplified component patterns for code reuse`),
el("li", t`Normalized property/attribute handling across browsers`),
el("li", t`Smart element return values for cleaner code flow`)
)
),
el(code, { src: fileURL("./components/examples/elements/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/elements/intro.js"), page_id }),
el(h3, t`Creating element(s) (with custom attributes)`), el(h3, t`Creating Elements: Native vs DDE`),
el("p").append(...T` el("p").append(...T`
You can create a native DOM element by using the ${el("a", references.mdn_create).append( In standard JavaScript, you create DOM elements using the
el("code", "document.createElement()") )}. It is also possible to provide a some attribute(s) declaratively ${el("a", references.mdn_create).append(el("code", "document.createElement()"))} method
using ${el("code", "Object.assign()")}. More precisely, this way you can sets some and then set properties individually or with Object.assign():
${el("a", references.mdn_idl).append( el("abbr", { textContent: "IDL", title: "Interface Description Language" }))}
also known as a JavaScript property.
`), `),
el(example, { src: fileURL("./components/examples/elements/nativeCreateElement.js"), page_id }), el("div", { class: "illustration" }).append(
el("p").append(...T` el("div", { class: "comparison" }).append(
To make this easier, you can use the ${el("code", "el")} function. Internally in basic examples, el("div").append(
it is wrapper around ${el("code", "assign(document.createElement(…), { … })")}. el("h5", t`Native DOM API`),
`), el(code, { src: fileURL("./components/examples/elements/native-dom-create.js"), page_id })
el(example, { src: fileURL("./components/examples/elements/dekaCreateElement.js"), page_id }), ),
el("p").append(...T` el("div").append(
The ${el("code", "assign")} function provides improved behaviour of ${el("code", "Object.assign()")}. el("h5", t`DDE Approach`),
You can declaratively sets any IDL and attribute of the given element. Function prefers IDL and fallback el(code, { src: fileURL("./components/examples/elements/dde-dom-create.js"), page_id })
to the ${el("code", "element.setAttribute")} if there is no writable property in the element prototype. )
`), )
el("p").append(...T`
You can study all JavaScript elements interfaces to the corresponding HTML elements. All HTML elements
inherits from ${el("a", { textContent: "HTMLElement", ...references.mdn_el })}. To see
all available IDLs for example for paragraphs, see ${el("a", { textContent: "HTMLParagraphElement",
...references.mdn_p })}. Moreover, the ${el("code", "assign")} provides a way to sets declaratively
some convenient properties:
`),
el("ul").append(
el("li").append(...T`
It is possible to sets ${el("code", "data-*")}/${el("code", "aria-*")} attributes using object notation.
`),
el("li").append(...T`
In opposite, it is also possible to sets ${el("code", "data-*")}/${el("code", "aria-*")} attribute
using camelCase notation.
`),
el("li").append(...T`You can use string or object as a value for ${el("code", "style")} property.`),
el("li").append(...T`
${el("code", "className")} (IDL preffered)/${el("code", "class")} are ways to add CSS classes
to the element. You can use string (similarly to ${el("code", "class=\"…\"")} syntax in HTML).
`),
el("li").append(...T`
Use ${el("code", "classList")} to toggle specific classes. This will be handy later when
the reactivity via signals is beeing introduced.
`),
el("li").append(...T`
The ${el("code", "assign")} also accepts the ${el("code", "undefined")} as a value for any property
to remove it from the element declaratively. Also for some IDL the corresponding attribute is removed
as it can be confusing. ${el("em").append(...T`For example, natievly the elements ${el("code", "id")}
is removed by setting the IDL to an empty string.`)}
`),
el("li").append(...T`
You can use ${el("code", "=")} or ${el("code", ".")} to force processing given key as attribute/property
of the element.
`)
), ),
el("p").append(...T` el("p").append(...T`
For processing, the ${el("code", "assign")} internally uses ${el("code", "assignAttribute")} and The ${el("code", "el")} function provides a simple wrapper around ${el("code", "document.createElement")}
${el("code", "classListDeclarative")}. with enhanced property assignment.
`), `),
el(example, { src: fileURL("./components/examples/elements/dekaCreateElement.js"), page_id }),
el(h3, t`Advanced Property Assignment`),
el("p").append(...T`
The ${el("code", "assign")} function is the heart of DDE's element property handling. It is internally used
to assign properties using the ${el("code", "el")} function. ${el("code", "assign")} provides intelligent
assignment of both properties (IDL) and attributes:
`),
el("div", { class: "function-table" }).append(
el("dl").append(
el("dt", t`Property vs Attribute Priority`),
el("dd", t`Prefers IDL properties, falls back to setAttribute() when no writable property exists`),
el("dt", t`Data and ARIA Attributes`),
el("dd", t`Both dataset.* and data-* syntaxes supported (same for ARIA)`),
el("dt", t`Style Handling`),
el("dd", t`Accepts string or object notation for style property`),
el("dt", t`Class Management`),
el("dd", t`Works with className, class, or classList object for toggling classes`),
el("dt", t`Force Modes`),
el("dd", t`Use = prefix to force attribute mode, . prefix to force property mode`),
el("dt", t`Attribute Removal`),
el("dd", t`Pass undefined to remove a property or attribute`)
)
),
el(example, { src: fileURL("./components/examples/elements/dekaAssign.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaAssign.js"), page_id }),
el(h3, t`Native JavaScript templating`), el("div", { class: "note" }).append(
el("p", t`By default, the native JS has no good way to define HTML template using DOM API:`), el("p").append(...T`
el(example, { src: fileURL("./components/examples/elements/nativeAppend.js"), page_id }), You can explore standard HTML element properties in the MDN documentation for
${el("a", { textContent: "HTMLElement", ...references.mdn_el })} (base class)
and specific element interfaces like ${el("a", { textContent: "HTMLParagraphElement", ...references.mdn_p })}.
`)
),
el(h3, t`Building DOM Trees with Chainable Methods`),
el("p").append(...T` el("p").append(...T`
This library therefore overwrites the ${el("code", "append")} method of created elements to always return One of the most powerful features of DDE is its approach to building element trees.
parent element. Unlike the native DOM API which doesn't return the parent after appendChild(), DDE's
append() always returns the parent element:
`),
el("div", { class: "illustration" }).append(
el("div", { class: "comparison" }).append(
el("div", { class: "bad-practice" }).append(
el("h5", t`❌ Native DOM API`),
el(code, { src: fileURL("./components/examples/elements/native-dom-tree.js"), page_id })
),
el("div", { class: "good-practice" }).append(
el("h5", t`✅ DDE Approach`),
el(code, { src: fileURL("./components/examples/elements/dde-dom-tree.js"), page_id })
)
)
),
el("p").append(...T`
This chainable pattern is much cleaner and easier to follow, especially for deeply nested elements.
It also makes it simple to add multiple children to a parent element in a single fluent expression.
`), `),
el(example, { src: fileURL("./components/examples/elements/dekaAppend.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaAppend.js"), page_id }),
el(h3, t`Using Components to Build UI Fragments`),
el(h3, t`Basic (state-less) components`),
el("p").append(...T` el("p").append(...T`
You can use functions for encapsulation (repeating) logic. The ${el("code", "el")} accepts function The ${el("code", "el")} function is overloaded to support both tag names and function components.
as first argument. In that case, the function should return dom elements and the second argument for This lets you refactor complex UI trees into reusable pieces:
${el("code", "el")} is argument for given element.
`), `),
el(example, { src: fileURL("./components/examples/elements/dekaBasicComponent.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaBasicComponent.js"), page_id }),
el("p").append(...T` el("p").append(...T`
As you can see, in case of state-less/basic components there is no difference between calling component Component functions receive the properties object as their first argument, just like regular elements.
function directly or using ${el("code", "el")} function. This makes it easy to pass data down to components and create reusable UI fragments.
`),
el("p", { className: "notice" }).append(...T`
It is nice to use similar naming convention as native DOM API. This allows us to use
${el("a", { textContent: t`the destructuring assignment syntax`, ...references.mdn_destruct })} and keep
track of the native API (things are best remembered through regular use).
`), `),
el("div", { class: "tip" }).append(
el("p").append(...T`
It's helpful to use naming conventions similar to native DOM elements for your components.
This allows you to use ${el("a", { textContent: "destructuring assignment", ...references.mdn_destruct })}
and keeps your code consistent with the DOM API.
`)
),
el(h3, t`Creating non-HTML elements`), el(h3, t`Working with SVG and Other Namespaces`),
el("p").append(...T` el("p").append(...T`
Similarly to the native DOM API (${el("a", references.mdn_ns).append(el("code", "document.createElementNS"))}) For non-HTML elements like SVG, MathML, or custom namespaces, DDE provides the ${el("code", "elNS")} function
for non-HTML elements we need to tell JavaScript which kind of the element to create. We can use which corresponds to the native ${el("a", references.mdn_ns).append(el("code", "document.createElementNS"))}:
the ${el("code", "elNS")} function:
`), `),
el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }), el(example, { src: fileURL("./components/examples/elements/dekaElNS.js"), page_id }),
el("p").append(...T`
This function returns a namespace-specific element creator, allowing you to work with any element type
using the same consistent interface.
`),
el(h3, t`Best Practices for Declarative DOM Creation`),
el("ol").append(
el("li").append(...T`
${el("strong", "Use component functions for reusable UI fragments:")} Extract common UI patterns
into reusable functions that return elements.
`),
el("li").append(...T`
${el("strong", "Leverage destructuring for cleaner component code:")} Use
${el("a", { textContent: "destructuring", ...references.mdn_destruct })} to extract properties
from the props object for cleaner component code.
`),
el("li").append(...T`
${el("strong", "Leverage chainable methods for better performance:")} Use chainable methods like
${el("code", ".append()")} to build complex DOM trees for better performance and cleaner code.
`),
),
el(mnemonic) el(mnemonic)
); );

View File

@ -1,7 +1,8 @@
import { T, t } from "./utils/index.js"; import { T, t } from "./utils/index.js";
export const info= { export const info= {
title: t`Events and Addons`, title: t`Events and Addons`,
description: t`Using not only events in UI declaratively.`, fullTitle: t`Declarative Event Handling and Addons`,
description: t`Using events and addons for declarative UI interactions.`,
}; };
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
@ -15,7 +16,7 @@ const fileURL= url=> new URL(url, import.meta.url);
const references= { const references= {
/** element.addEventListener() */ /** element.addEventListener() */
mdn_listen: { mdn_listen: {
title: t`MDN documentation page for elemetn.addEventListener`, title: t`MDN documentation page for element.addEventListener`,
href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener", href: "https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener",
}, },
/** AbortSignal+element.addEventListener */ /** AbortSignal+element.addEventListener */
@ -45,109 +46,197 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("h2", t`Listenning to the native DOM events and other Addons`),
el("p").append(...T` el("p").append(...T`
We quickly introduce helper to listening to the native DOM events. And library syntax/pattern so-called Events are at the core of interactive web applications. DDE provides a clean, declarative approach to
${el("em", t`Addon`)} to incorporate not only this in UI templates declaratively. handling DOM events and extends this pattern with a powerful Addon system to incorporate additional
functionalities into your UI templates.
`), `),
el("div", { className: "callout" }).append(
el("h4", t`Why DDE's Event System and Addons Matters`),
el("ul").append(
el("li", t`Integrate event handling directly in element declarations`),
el("li", t`Leverage lifecycle events for better component design`),
el("li", t`Clean up listeners automatically with abort signals`),
el("li", t`Extend elements with custom behaviors using Addons`),
el("li", t`Maintain clean, readable code with consistent patterns`)
)
),
el(code, { src: fileURL("./components/examples/events/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/events/intro.js"), page_id }),
el(h3, t`Events and listenners`), el(h3, t`Events and Listeners: Two Approaches`),
el("p").append(...T` el("p").append(...T`
In JavaScript you can listen to the native DOM events of the given element by using In JavaScript you can listen to native DOM events using
${el("a", references.mdn_listen).append( el("code", "element.addEventListener(type, listener, options)") )}. ${el("a", references.mdn_listen).append(el("code", "element.addEventListener(type, listener, options)"))}.
The library provides an alternative (${el("code", "on")}) accepting the differen order of the arguments: DDE provides an alternative approach with arguments ordered differently to better fit its declarative style:
`),
el("div", { className: "illustration" }).append(
el("div", { className: "tabs" }).append(
el("div", { className: "tab" }).append(
el("h5", t`Native DOM API`),
el(code, { content: `element.addEventListener('click', callback, options);`, page_id })
),
el("div", { className: "tab" }).append(
el("h5", t`DDE Approach`),
el(code, { content: `on('click', callback, options)(element);`, page_id })
)
)
),
el("p").append(...T`
The main benefit of DDE's approach is that it works as an Addon, making it easy to integrate
directly into element declarations.
`), `),
el(example, { src: fileURL("./components/examples/events/compare.js"), page_id }), el(example, { src: fileURL("./components/examples/events/compare.js"), page_id }),
el("p").append(...T`
this is actually one of the two differences. The another one is that ${el("code", "on")} accepts only el(h3, t`Removing Event Listeners`),
object as the ${el("code", "options")} (but it is still optional). el("div", { className: "note" }).append(
`),
el("p", { className: "notice" }).append(...T`
The other difference is that there is ${el("strong", "no")} ${el("code", "off")} function. You can remove
listener declaratively using ${el("a", { textContent: "AbortSignal", ...references.mdn_abortListener })}:
`),
el(example, { src: fileURL("./components/examples/events/abortSignal.js"), page_id }),
el("div", { className: "notice" }).append(
el("p", t`So, there are (typically) three ways to handle events. You can use:`),
el("ul").append(
el("li").append( el("code", `el("button", { textContent: "click me", "=onclick": "console.log(event)" })`)),
el("li").append( el("code", `el("button", { textContent: "click me", onclick: console.log })`)),
el("li").append( el("code", `el("button", { textContent: "click me" }, on("click", console.log))`))
),
el("p").append(...T` el("p").append(...T`
In the first example we force to use HTML attribute (it corresponds to Unlike the native addEventListener/removeEventListener pattern, DDE uses the ${el("a", {
${el("code", `<button onclick="console.log(event)">click me</button>`)}). ${el("em", t`Side note: textContent: "AbortSignal", ...references.mdn_abortListener })} for declarative approach for removal:
this can be useful in case of SSR.`)} To study difference, you can read a nice summary here:
${el("a", { textContent: "GIST @WebReflection/web_events.md", ...references.web_events })}.
`) `)
), ),
el(example, { src: fileURL("./components/examples/events/abortSignal.js"), page_id }),
el(h3, t`Addons`), el(h3, t`Three Ways to Handle Events`),
el("div", { className: "tabs" }).append(
el("div", { className: "tab", "data-tab": "html-attr" }).append(
el("h4", t`HTML Attribute Style`),
el(code, { src: fileURL("./components/examples/events/attribute-event.js"), page_id }),
el("p").append(...T`
Forces usage as an HTML attribute. Corresponds to
${el("code", `<button onclick="console.log(event)">click me</button>`)}. This can be particularly
useful for SSR scenarios.
`)
),
el("div", { className: "tab", "data-tab": "property" }).append(
el("h4", t`Property Assignment`),
el(code, { src: fileURL("./components/examples/events/property-event.js"), page_id }),
el("p", t`Assigns the event handler directly to the element's property.`)
),
el("div", { className: "tab", "data-tab": "addon" }).append(
el("h4", t`Addon Approach`),
el(code, { src: fileURL("./components/examples/events/chain-event.js"), page_id }),
el("p", t`Uses the addon pattern, see above.`)
)
),
el("p").append(...T` el("p").append(...T`
From practical point of view, ${el("em", t`Addons`)} are just functions that accept any HTML element as For a deeper comparison of these approaches, see
their first parameter. You can see that the ${el("code", "on(…)")} fullfills this requirement. ${el("a", { textContent: "WebReflection's detailed analysis", ...references.web_events })}.
`), `),
el(h3, t`Understanding Addons`),
el("p").append(...T` el("p").append(...T`
You can use Addons as 3rd argument of ${el("code", "el")} function. This way is possible to extends your Addons are a powerful pattern in DDE that extends beyond just event handling.
templates by additional (3rd party) functionalities. But for now mainly, you can add events listeners: An Addon is any function that accepts an HTML element as its first parameter.
`),
el("div", { className: "callout" }).append(
el("h4", t`What Can Addons Do?`),
el("ul").append(
el("li", t`Add event listeners to elements`),
el("li", t`Set up lifecycle behaviors`),
el("li", t`Integrate third-party libraries`),
el("li", t`Create reusable element behaviors`),
el("li", t`Capture element references`)
)
),
el("p").append(...T`
You can use Addons as 3rd argument of the ${el("code", "el")} function, making it possible to
extend your templates with additional functionality:
`), `),
el(example, { src: fileURL("./components/examples/events/templateWithListeners.js"), page_id }), el(example, { src: fileURL("./components/examples/events/templateWithListeners.js"), page_id }),
el("p").append(...T` el("p").append(...T`
As the example shows, you can also provide types in JSDoc+TypeScript by using global type As the example shows, you can provide types in JSDoc+TypeScript using the global type
${el("code", "ddeElementAddon")}. Also notice, you can use Addons to get element reference. ${el("code", "ddeElementAddon")}. Notice how Addons can also be used to get element references.
`), `),
el(h3, t`Life-cycle events`),
el(h3, t`Lifecycle Events`),
el("p").append(...T` el("p").append(...T`
Addons are called immediately when the element is created, even it is not connected to live DOM yet. Addons are called immediately when an element is created, even before it's connected to the live DOM.
Therefore, you can understand the Addon to be oncreate event. You can think of an Addon as an "oncreate" event handler.
`), `),
el("p").append(...T` el("p").append(...T`
The library provide three additional live-cycle events corresponding to how they are named in a case of DDE provides three additional lifecycle events that correspond to custom element lifecycle callbacks:
custom elements: ${el("code", "on.connected")}, ${el("code", "on.disconnected")} and ${el("code",
"on.attributeChanged")}.
`), `),
el(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }), el("div", { className: "function-table" }).append(
el("p").append(...T` el("dl").append(
For Custom elements, we will later introduce a way to replace ${el("code", "*Callback")} syntax with el("dt", t`on.connected(callback)`),
${el("code", "dde:*")} events. The ${el("code", "on.*")} functions then listen to the appropriate el("dd", t`Fires when the element is added to the DOM`),
Custom Elements events (see ${el("a", { textContent: t`Custom element lifecycle callbacks | MDN`,
...references.mdn_customElement })}). el("dt", t`on.disconnected(callback)`),
`), el("dd", t`Fires when the element is removed from the DOM`),
el("p").append(...T`
But, in case of regular elemnets the ${el("a", references.mdn_mutation).append(el("code", el("dt", t`on.attributeChanged(callback, attributeName)`),
"MutationObserver"), " | MDN")} is internaly used to track these events. Therefore, there are some el("dd", t`Fires when the specified attribute changes`)
drawbacks: )
`),
el("ul").append(
el("li").append(...T`
To proper listener registration, you need to use ${el("code", "on.*")} not \`on("dde:*", …)\`!
`),
el("li").append(...T`
Use sparingly! Internally, library must loop of all registered events and fires event properly.
${el("strong", t`It is good practice to use the fact that if an element is removed, its children are
also removed!`)} In this spirit, we will introduce later the ${el("strong", t`host`)} syntax to
register, clean up procedures when the component is removed from the app.
`),
), ),
el("p").append(...T` el(example, { src: fileURL("./components/examples/events/live-cycle.js"), page_id }),
To provide intuitive behaviour, similar also to how the life-cycle events works in other
frameworks/libraries, deka-dom-el library ensures that ${el("code", "on.connected")} and el("div", { className: "note" }).append(
${el("code", "on.disconnected")} are called only once and only when the element, is (dis)connected to el("p").append(...T`
live DOM. The solution is inspired by ${el("a", { textContent: "Vue", ...references.vue_fix })}. For using For regular elements (non-custom elements), DDE uses
native behaviour re-(dis)connecting element, use: ${el("a", references.mdn_mutation).append(el("code", "MutationObserver"), " | MDN")}
`), internally to track lifecycle events.
el("ul").append( `)
el("li").append(...T`custom ${el("code", "MutationObserver")} or logic in (dis)${el("code",
"connectedCallback")} or`),
el("li").append(...T`re-add ${el("code", "on.connected")} or ${el("code", "on.disconnected")} listeners.`)
), ),
el(h3, t`Final notes`), el("div", { className: "warning" }).append(
el("p", t`The library also provides a method to dispatch the events.`), el("ul").append(
el("li").append(...T`
Always use ${el("code", "on.*")} functions, not ${el("code", "on('dde:*', ...)")}, for proper registration
`),
el("li").append(...T`
Use lifecycle events sparingly, as they require internal tracking
`),
el("li").append(...T`
Leverage parent-child relationships: when a parent is removed, all children are also removed
`),
el("li").append(...T`
see section later in documentation regarding hosts elements
`),
el("li").append(...T`
DDE ensures that connected/disconnected events fire only once for better predictability
`)
)
),
el(h3, t`Dispatching Custom Events`),
el("p").append(...T`
This makes it easy to implement component communication through events,
following standard web platform patterns. The curried approach allows for easy reuse
of event dispatchers throughout your application.
`),
el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }), el(example, { src: fileURL("./components/examples/events/compareDispatch.js"), page_id }),
el(h3, t`Best Practices`),
el("ol").append(
el("li").append(...T`
${el("strong", "Clean up listeners")}: Use AbortSignal to prevent memory leaks
`),
el("li").append(...T`
${el("strong", "Leverage lifecycle events")}: For component setup and teardown
`),
el("li").append(...T`
${el("strong", "Delegate when possible")}: Add listeners to container elements when handling many similar elements
`),
el("li").append(...T`
${el("strong", "Maintain consistency")}: Choose one event binding approach and stick with it
`)
),
el("div", { className: "troubleshooting" }).append(
el("h4", t`Common Event Pitfalls`),
el("dl").append(
el("dt", t`Event listeners not working`),
el("dd", t`Ensure element is in the DOM before expecting events to fire`),
el("dt", t`Memory leaks`),
el("dd", t`Use AbortController to clean up listeners when elements are removed`),
el("dt", t`Lifecycle events firing unexpectedly`),
el("dd", t`Remember that on.connected and on.disconnected events only fire once per connection state`)
)
),
el(mnemonic) el(mnemonic)
); );
} }

View File

@ -1,7 +1,8 @@
import { T, t } from "./utils/index.js"; import { T, t } from "./utils/index.js";
export const info= { export const info= {
title: t`Signals and reactivity`, title: t`Signals and Reactivity`,
description: t`Handling reactivity in UI via signals.`, fullTitle: t`Building Reactive UIs with Signals`,
description: t`Managing reactive UI state with signals.`,
}; };
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
@ -43,53 +44,124 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("h2", t`Using signals to manage reactivity`),
el("p").append(...T` el("p").append(...T`
How a program responds to variable data or user interactions is one of the fundamental problems of Signals provide a simple yet powerful way to create reactive applications with DDE. They handle the
programming. If we desire to solve the issue in a declarative manner, signals may be a viable approach. fundamental challenge of keeping your UI in sync with changing data in a declarative, efficient way.
`), `),
el("div", { class: "callout" }).append(
el("h4", t`What Makes Signals Special?`),
el("ul").append(
el("li", t`Fine-grained reactivity without complex state management`),
el("li", t`Automatic UI updates when data changes`),
el("li", t`Clean separation between data, logic, and UI`),
el("li", t`Small runtime with minimal overhead`),
el("li").append(...T`${el("strong", "In future")} no dependencies or framework lock-in`)
)
),
el(code, { src: fileURL("./components/examples/signals/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/signals/intro.js"), page_id }),
el(h3, t`Introducing signals`), el(h3, t`The 3-Part Structure of Signals`),
el("p").append(...T` el("p").append(...T`
Lets re-introduce Signals organize your code into three distinct parts, following the
${el("a", { textContent: t`3PS principle`, href: "./#h-event-driven-programming--parts-separation--ps" })}. ${el("a", { textContent: t`3PS principle`, href: "./#h-3ps" })}:
`),
el("p").append(...T`
Using signals, we split program logic into the three parts. Firstly (α), we create a variable (constant)
representing reactive value. Somewhere later, we can register (β) a logic reacting to the signal value
changes. Similarly, in a remaining part (γ), we can update the signal value.
`), `),
el("div", { class: "signal-diagram" }).append(
el("div", { class: "signal-part" }).append(
el("h4", t`PART 1: Create Signal`),
el(code, { content: "const count = S(0);", page_id }),
el("p", t`Define a reactive value that can be observed and changed`)
),
el("div", { class: "signal-part" }).append(
el("h4", t`PART 2: React to Changes`),
el(code, { content: "S.on(count, value => updateUI(value));", page_id }),
el("p", t`Subscribe to signal changes with callbacks or effects`)
),
el("div", { class: "signal-part" }).append(
el("h4", t`PART 3: Update Signal`),
el(code, { content: "count.set(count.get() + 1);", page_id }),
el("p", t`Modify the signal value, which automatically triggers updates`)
)
),
el(example, { src: fileURL("./components/examples/signals/signals.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/signals.js"), page_id }),
el("div", { class: "note" }).append(
el("p").append(...T`
Signals implement the ${el("a", { textContent: t`Publishsubscribe pattern`, ...references.wiki_pubsub })},
a form of ${el("a", { textContent: t`Event-driven programming`, ...references.wiki_event_driven })}.
This architecture allows different parts of your application to stay synchronized through a shared signal,
without direct dependencies on each other. Compare for example with ${el("a", { textContent:
t`fpubsub library`, ...references.fpubsub })}.
`)
),
el(h3, t`Signal Essentials: Core API`),
el("div", { class: "function-table" }).append(
el("dl").append(
el("dt", t`Creating a Signal`),
el("dd", t`S(initialValue) → creates a signal with the given value`),
el("dt", t`Reading a Signal`),
el("dd", t`signal.get() → returns the current value`),
el("dt", t`Writing to a Signal`),
el("dd", t`signal.set(newValue) → updates the value and notifies subscribers`),
el("dt", t`Subscribing to Changes`),
el("dd", t`S.on(signal, callback) → runs callback whenever signal changes`),
el("dt", t`Unsubscribing`),
el("dd").append(...T`S.on(signal, callback, { signal: abortController.signal }) → Similarly to the
${el("code", "on")} function to register DOM events listener.`)
)
),
el("p").append(...T` el("p").append(...T`
All this is just an example of Signals can be created with any type of value, but they work best with
${el("a", { textContent: t`Event-driven programming`, ...references.wiki_event_driven })} and ${el("a", { textContent: t`primitive types`, ...references.mdn_primitive })} like strings, numbers, and booleans.
${el("a", { textContent: t`Publishsubscribe pattern`, ...references.wiki_pubsub })} (compare for example For complex data types like objects and arrays, you'll want to use Actions (covered below).
with ${el("a", { textContent: t`fpubsub library`, ...references.fpubsub })}). All three parts can be in
some manner independent and still connected to the same reactive entity.
`), `),
el(h3, t`Derived Signals: Computed Values`),
el("p").append(...T` el("p").append(...T`
Signals are implemented in the library as functions. To see current value of signal, just call it without Computed values (also called derived signals) automatically update when their dependencies change.
any arguments ${el("code", "console.log(signal())")}. To update the signal value, pass any argument Create them by passing a function to S():
${el("code", `signal('${t`a new value`}')`)}. For listenning the signal value changes, use
${el("code", "S.on(signal, console.log)")}.
`), `),
el(example, { src: fileURL("./components/examples/signals/derived.js"), page_id }),
el("p").append(...T` el("p").append(...T`
Similarly to the ${el("code", "on")} function to register DOM events listener. You can use Derived signals are read-only - you can't call .set() on them. Their value is always computed
${el("code", "AbortController")}/${el("code", "AbortSignal")} to ${el("em", "off")}/stop listenning. In from their dependencies. They're perfect for transforming or combining data from other signals.
example, you also found the way for representing live piece of code computation pattern (derived signal):
`), `),
el(example, { src: fileURL("./components/examples/signals/computations-abort.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/computations-abort.js"), page_id }),
el(h3, t`Signals and actions`), el(h3, t`Signal Actions: For Complex State`),
el("p").append(...T` el("p").append(...T`
${el("code", `S(/* ${t`primitive`} */)`)} allows you to declare simple reactive variables, typically, around When working with objects, arrays, or other complex data structures, Signal Actions provide
${el("em", t`immutable`)} ${el("a", { textContent: t`primitive types`, ...references.mdn_primitive })}. a structured way to modify state while maintaining reactivity.
However, it may also be necessary to use reactive arrays, objects, or other complex reactive structures.
`), `),
el(example, { src: fileURL("./components/examples/signals/actions-demo.js"), page_id }), el("div", { class: "illustration" }).append(
el("p", t`…but typical user-case is object/array (maps, sets and other mutable objects):`), el("h4", t`Actions vs. Direct Mutation`),
el(example, { src: fileURL("./components/examples/signals/actions-todos.js"), page_id }), el("div", { class: "comparison" }).append(
el("div", { class: "good-practice" }).append(
el("h5", t`✅ With Actions`),
el(code, { content: `const todos = S([], {
add(text) {
this.value.push(text);
// Subscribers notified automatically
}
});
// Use the action
S.action(todos, "add", "New todo");`, page_id })
),
el("div", { class: "bad-practice" }).append(
el("h5", t`❌ Without Actions`),
el(code, { content: `
const todos = S([]);
// Directly mutating the array
const items = todos.get();
items.push("New todo");
// This WON'T trigger updates!`, page_id }))
),
),
el("p").append(...T` el("p").append(...T`
In some way, you can compare it with ${el("a", { textContent: "useReducer", ...references.mdn_use_reducer })} In some way, you can compare it with ${el("a", { textContent: "useReducer", ...references.mdn_use_reducer })}
hook from React. So, the ${el("code", "S(<data>, <actions>)")} pattern creates a store machine. We can hook from React. So, the ${el("code", "S(<data>, <actions>)")} pattern creates a store machine. We can
@ -98,31 +170,123 @@ export function page({ pkg, info }){
${el("code", "this.stopPropagation()")} in the method representing the given action. As it can be seen in ${el("code", "this.stopPropagation()")} in the method representing the given action. As it can be seen in
examples, the store value is available also in the function for given action (${el("code", "this.value")}). examples, the store value is available also in the function for given action (${el("code", "this.value")}).
`), `),
el(example, { src: fileURL("./components/examples/signals/actions-demo.js"), page_id }),
el(h3, t`Reactive DOM attributes and elements`), el("p").append(...T`
el("p", t`There are on basic level two distinc situation to mirror dynamic value into the DOM/UI`), Actions provide these benefits:
el("ol").append( `),
el("li", t`to change some attribute(s) of existing element(s)`), el("ul").append(
el("li", t`to generate elements itself dynamically this covers conditions and loops`) el("li", t`Encapsulate state change logic in named methods`),
el("li", t`Guarantee notifications when state changes`),
el("li", t`Prevent accidental direct mutations`),
el("li", t`Act similar to reducers in other state management libraries`)
), ),
el("p").append(...T`
Here's a more complete example of a todo list using signal actions:
`),
el(example, { src: fileURL("./components/examples/signals/actions-todos.js"), page_id }),
el("div", { class: "tip" }).append(
el("p").append(...T`
${el("strong", "Special Action Methods")}: Signal actions can implement special lifecycle hooks:
`),
el("ul").append(
el("li", t`[S.symbols.onclear]() - Called when the signal is cleared. Use it to clean up resources.`),
)
),
el(h3, t`Connecting Signals to the DOM`),
el("p").append(...T`
Signals really shine when connected to your UI. DDE provides several ways to bind signals to DOM elements:
`),
el("div", { class: "tabs" }).append(
el("div", { class: "tab", "data-tab": "attributes" }).append(
el("h4", t`Reactive Attributes`),
el("p", t`Bind signal values directly to element attributes, properties, or styles:`),
el(code, { content: `// Create a signal
const color = S("blue");
// Bind it to an element's style
el("div", {
style: {
color, // Updates when signal changes
fontWeight: S(() => color.get() === "red" ? "bold" : "normal")
}
}, "This text changes color");
// Later:
color.set("red"); // UI updates automatically`, page_id })
),
el("div", { class: "tab", "data-tab": "elements" }).append(
el("h4", t`Reactive Elements`),
el("p", t`Dynamically create or update elements based on signal values:`),
el(code, { content: `// Create an array signal
const items = S(["Apple", "Banana", "Cherry"]);
// Create a dynamic list that updates when items change
el("ul").append(
S.el(items, items =>
items.map(item => el("li", item))
)
);
// Later:
S.action(items, "push", "Dragonfruit"); // List updates automatically`, page_id })
)
),
el("p").append(...T`
The ${el("code", "assign")} and ${el("code", "el")} functions detect signals automatically and handle binding.
You can use special properties like ${el("code", "dataset")}, ${el("code", "ariaset")}, and
${el("code", "classList")} for fine-grained control over specific attribute types.
`),
el(example, { src: fileURL("./components/examples/signals/dom-attrs.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/dom-attrs.js"), page_id }),
el("p").append(...T` el("p").append(...T`
To derived attribute based on value of signal variable just use the signal as a value of the attribute ${el("code", "S.el()")} is especially powerful for conditional rendering and lists:
(${el("code", "assign(element, { attribute: S('value') })")}). ${el("code", "assign")}/${el("code", "el")}
provides ways to glue reactive attributes/classes more granularly into the DOM. Just use dedicated build-in
attributes ${el("code", "dataset")}, ${el("code", "ariaset")} and ${el("code", "classList")}.
`),
el("p").append(...T`
For computation, you can use the derived signal (see above) like
${el("code", "assign(element, { textContent: S(()=> 'Hello '+WorldSignal()) })")}. This is read-only signal
its value is computed based on given function and updated when any signal used in the function changes.
`),
el("p").append(...T`
To represent part of the template filled dynamically based on the signal value use
${el("code", "S.el(signal, DOMgenerator)")}. This was already used in the todo example above or see:
`), `),
el(example, { src: fileURL("./components/examples/signals/dom-el.js"), page_id }), el(example, { src: fileURL("./components/examples/signals/dom-el.js"), page_id }),
el(h3, t`Best Practices for Signals`),
el("p").append(...T`
Follow these guidelines to get the most out of signals:
`),
el("ol").append(
el("li").append(...T`
${el("strong", "Keep signals small and focused")}: Use many small signals rather than a few large ones
`),
el("li").append(...T`
${el("strong", "Use derived signals for computations")}: Don't recompute values in multiple places
`),
el("li").append(...T`
${el("strong", "Clean up signal subscriptions")}: Use AbortController or scope.host() to prevent memory leaks
`),
el("li").append(...T`
${el("strong", "Use actions for complex state")}: Don't directly mutate objects or arrays in signals
`),
el("li").append(...T`
${el("strong", "Avoid infinite loops")}: Be careful when one signal updates another in a subscription
`)
),
el("div", { class: "troubleshooting" }).append(
el("h4", t`Common Signal Pitfalls`),
el("dl").append(
el("dt", t`UI not updating when array/object changes`),
el("dd", t`Use signal actions instead of direct mutation`),
el("dt", t`Infinite update loops`),
el("dd", t`Check for circular dependencies between signals`),
el("dt", t`Memory leaks`),
el("dd", t`Use AbortController or scope.host() to clean up subscriptions`),
el("dt", t`Multiple elements updating unnecessarily`),
el("dd", t`Split large signals into smaller, more focused ones`)
)
),
el(mnemonic) el(mnemonic)
); );
} }

View File

@ -1,7 +1,8 @@
import { T, t } from "./utils/index.js"; import { T, t } from "./utils/index.js";
export const info= { export const info= {
title: t`Scopes and components`, title: t`Scopes and Components`,
description: t`Organizing UI into components`, fullTitle: t`Building Maintainable UIs with Scopes and Components`,
description: t`Organizing UI into reusable, manageable components`,
}; };
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
@ -28,59 +29,174 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("h2", t`Using functions as UI components`),
el("p").append(...T` el("p").append(...T`
For state-less components we can use functions as UI components (see Elements page). But in real life, For state-less components we can use functions as UI components (see Elements page). But in real life,
we may need to handle the component live-cycle and provide JavaScript the way to properly use we may need to handle the component's life-cycle and provide JavaScript the way to properly use
the ${el("a", { textContent: t`Garbage collection`, ...references.garbage_collection })}. the ${el("a", { textContent: t`Garbage collection`, ...references.garbage_collection })}.
`), `),
el(code, { src: fileURL("./components/examples/scopes/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/scopes/intro.js"), page_id }),
el("p").append(...T`The library therefore use ${el("em", t`scopes`)} to provide these functionalities.`), el("p").append(...T`The library therefore uses ${el("em", t`scopes`)} to provide these functionalities.`),
el(h3, t`Scopes and hosts`), el(h3, t`Understanding Host Elements and Scopes`),
el("p").append(...T` el("p").append(...T`
The ${el("strong", "host")} is the name for the element representing the component. This is typically The ${el("strong", "host")} is the name for the element representing the component. This is typically the
element returned by function. To get reference, you can use ${el("code", "scope.host()")} to applly addons element returned by a function. To get a reference, you can use ${el("code", "scope.host()")}. To apply addons,
just use ${el("code", "scope.host(...<addons>)")}. just use ${el("code", "scope.host(...<addons>)")}.
`), `),
el("p").append(...T`
Scopes are primarily needed when signals are used in DOM templates (with ${el("code", "el")}, ${el("code",
"assign")}, or ${el("code", "S.el")}). They provide a way for automatically removing signal listeners
and cleaning up unused signals when components are removed from the DOM.
`),
el("div", { className: "illustration" }).append(
el("h4", t`Component Anatomy`),
el("pre").append(el("code", `
// 1. Component scope created
el(MyComponent);
function MyComponent() {
  // 2. access the host element
  const { host } = scope;
  // 3. Add behavior to host
  host(
  on.click(handleClick)
  );
  // 4. Return the host element
  return el("div", {
  className: "my-component"
  }).append(
  el("h2", "Title"),
  el("p", "Content")
  );
}
`.trim()))
),
el("div", { className: "function-table" }).append(
el("h4", t`scope.host()`),
el("dl").append(
el("dt", t`When called with no arguments`),
el("dd", t`Returns a reference to the host element (the root element of your component)`),
el("dt", t`When called with addons/callbacks`),
el("dd", t`Applies the addons to the host element and returns the host element`)
)
),
el(example, { src: fileURL("./components/examples/scopes/scopes-and-hosts.js"), page_id }), el(example, { src: fileURL("./components/examples/scopes/scopes-and-hosts.js"), page_id }),
el("p").append(...T`
To better understanding we implement function ${el("code", "elClass")} helping to create component as el("div", { className: "tip" }).append(
class instances. el("p").append(...T`
`), ${el("strong", "Best Practice:")} Always capture the host reference at the beginning of your component
el(example, { src: fileURL("./components/examples/scopes/class-component.js"), page_id }), function using ${el("code", "const { host } = scope")} to avoid scope-related issues, especially with
el("p").append(...T` asynchronous code.
As you can see, the ${el("code", "scope.host()")} is stored temporarily and synchronously. Therefore, at `),
least in the beginning of using library, it is the good practise to store ${el("code", "host")} in the root el("p").append(...T`
of your component. As it may be changed, typically when there is asynchronous code in the component. If you are interested in the implementation details, see Class-Based Components section.
`), `)
),
el(code, { src: fileURL("./components/examples/scopes/good-practise.js"), page_id }), el(code, { src: fileURL("./components/examples/scopes/good-practise.js"), page_id }),
el(h3, t`Scopes, signals and cleaning magic`), el(h3, t`Class-Based Components`),
el("p").append(...T` el("p").append(...T`
The ${el("code", "host")} is internally used to register the cleaning procedure, when the component While functional components are the primary pattern in DDE, you can also create class-based components.
(${el("code", "host")} element) is removed from the DOM. For this, we implement function ${el("code", "elClass")} and use it to demonstrate implementation details
for better understanding of the scope logic.
`), `),
el(example, { src: fileURL("./components/examples/scopes/class-component.js"), page_id }),
el(h3, t`Automatic Cleanup with Scopes`),
el("p").append(...T`
One of the most powerful features of scopes is automatic cleanup when components are removed from the DOM.
This prevents memory leaks and ensures resources are properly released.
`),
el("div", { className: "illustration" }).append(
el("h4", t`Lifecycle Flow`),
el("pre").append(el("code", `
1. Component created scope established
2. Component added to DOM connected event
3. Component interactions happen
4. Component removed from DOM disconnected event
5. Automatic cleanup of:
  - Event listeners
  - Signal subscriptions
  - Custom cleanup code
`))
),
el(example, { src: fileURL("./components/examples/scopes/cleaning.js"), page_id }), el(example, { src: fileURL("./components/examples/scopes/cleaning.js"), page_id }),
el("div", { className: "note" }).append(
el("p").append(...T`
In this example, when you click "Remove", the component is removed from the DOM, and all its associated
resources are automatically cleaned up, including the signal subscription that updates the text content.
This happens because the library internally registers a disconnected event handler on the host element.
`)
),
el(h3, t`Declarative vs Imperative Components`),
el("p").append(...T` el("p").append(...T`
The text content of the paragraph is changing when the value of the signal ${el("code", "textContent")} The library DOM API and signals work best when used declaratively. It means you split your app's logic
is changed. Internally, there is association between ${el("code", "textContent")} and the paragraph, into three parts as introduced in ${el("a", { textContent: "Signals", ...references.signals })}.
similar to using ${el("code", `S.on(textContent, /* ${t`update the paragraph`} */)`)}.
`), `),
el("p").append(...T` el("div", { className: "note" }).append(
This listener must be removed when the component is removed from the DOM. To do it, the library assign el("p").append(...T`
internally ${el("code", `on.disconnected(/* ${t`remove the listener`} */)(host())`)} to the host element. Strictly speaking, the imperative way of using the library is not prohibited. Just be careful to avoid
`), mixing the declarative approach (using signals) with imperative manipulation of elements.
el("p", { className: "notice" }).append(...T` `)
The library DOM API and signals works ideally when used declaratively. It means, you split your app logic ),
into three parts as it was itroduced in ${el("a", { textContent: "Signals", ...references.signals })}. el("div", { className: "tabs" }).append(
`), el("div", { className: "tab", "data-tab": "declarative" }).append(
el(code, { src: fileURL("./components/examples/scopes/declarative.js"), page_id }), el("h4", t`✅ Declarative Approach`),
el("p").append(...T` el("p", t`Define what your UI should look like based on state:`),
Strictly speaking, the imperative way of using the library is not prohibited. Just be careful (rather avoid) el(code, { src: fileURL("./components/examples/scopes/declarative.js"), page_id })
mixing declarative approach (using signals) and imperative manipulation of elements. ),
`), el("div", { className: "tab", "data-tab": "imperative" }).append(
el(code, { src: fileURL("./components/examples/scopes/imperative.js"), page_id }), el("h4", t`⚠️ Imperative Approach`),
el("p", t`Manually update the DOM in response to events:`),
el(code, { src: fileURL("./components/examples/scopes/imperative.js"), page_id })
),
el("div", { className: "tab", "data-tab": "mixed" }).append(
el("h4", t`❌ Mixed Approach`),
el("p", t`This approach should be avoided:`),
el(code, { src: fileURL("./components/examples/scopes/mixed.js"), page_id })
)
),
el(h3, t`Best Practices for Scopes and Components`),
el("ol").append(
el("li").append(...T`
${el("strong", "Capture host early:")} Use ${el("code", "const { host } = scope")} at component start
`),
el("li").append(...T`
${el("strong", "Define signals as constants:")} ${el("code", "const counter = S(0);")}
`),
el("li").append(...T`
${el("strong", "Prefer declarative patterns:")} Use signals to drive UI updates rather than manual DOM manipulation
`),
el("li").append(...T`
${el("strong", "Keep components focused:")} Each component should do one thing well
`),
el("li").append(...T`
${el("strong", "Add explicit cleanup:")} For resources not managed by DDE, use ${el("code", "on.disconnected")}
`)
),
el("div", { className: "troubleshooting" }).append(
el("h4", t`Common Scope Pitfalls`),
el("dl").append(
el("dt", t`Losing host reference in async code`),
el("dd", t`Store host reference early with const { host } = scope`),
el("dt", t`Memory leaks from custom resources`),
el("dd", t`Use host(on.disconnected(cleanup)) for manual resource cleanup`),
el("dt", t`Event handlers with incorrect 'this'`),
el("dd", t`Use arrow functions or .bind() to preserve context`),
el("dt", t`Mixing declarative and imperative styles`),
el("dd", t`Choose one approach and be consistent throughout a component`)
)
),
el(mnemonic) el(mnemonic)
); );

View File

@ -1,7 +1,8 @@
import { T, t } from "./utils/index.js"; import { T, t } from "./utils/index.js";
export const info= { export const info= {
title: t`Web Components`, title: t`Web Components`,
description: t`Using custom elements in combinantion with DDE`, fullTitle: t`Using Web Components with DDE: Better Together`,
description: t`Using custom elements in combination with DDE`,
}; };
import { el } from "deka-dom-el"; import { el } from "deka-dom-el";
@ -53,90 +54,220 @@ const references= {
export function page({ pkg, info }){ export function page({ pkg, info }){
const page_id= info.id; const page_id= info.id;
return el(simplePage, { info, pkg }).append( return el(simplePage, { info, pkg }).append(
el("h2", t`Using web components in combinantion with DDE`),
el("p").append(...T` el("p").append(...T`
The DDE library allows for use within ${el("a", references.mdn_web_components).append( el("strong", DDE pairs powerfully with ${el("a", references.mdn_web_components).append(el("strong", t`Web Components`))}
t`Web Components`) )} for dom-tree generation. However, in order to be able to use signals (possibly to create reusable, encapsulated custom elements with all the benefits of DDE's declarative DOM
mapping to registered ${el("a", references.mdn_observedAttributes).append( el("code", "observedAttributes") construction and reactivity system.
)}) and additional functionality is (unfortunately) required to use helpers provided by the library.
`), `),
el("div", { className: "callout" }).append(
el("h4", t`Why Combine DDE with Web Components?`),
el("ul").append(
el("li", t`Declarative DOM creation within your components`),
el("li", t`Reactive attribute updates through signals`),
el("li", t`Simplified event handling with the same events API`),
el("li", t`Clean component lifecycle management`),
el("li", t`Improved code organization with scopes`)
)
),
el(code, { src: fileURL("./components/examples/customElement/intro.js"), page_id }), el(code, { src: fileURL("./components/examples/customElement/intro.js"), page_id }),
el(h3, t`Custom Elements Introduction`), el(h3, t`Getting Started: Web Components Basics`),
el("p").append(...T` el("p").append(...T`
Web Components, specifically Custom Elements, are a set of web platform APIs that allow you to create Web Components are a set of standard browser APIs that let you create custom HTML elements with
new HTML tags with custom functionality encapsulated within them. This allows for the creation of reusable encapsulated functionality. They consist of three main technologies:
components that can be used across web applications.
`), `),
el("ul").append(
el("li").append(...T`
${el("strong", "Custom Elements:")} Create your own HTML tags with JS-defined behavior
`),
el("li").append(...T`
${el("strong", "Shadow DOM:")} Encapsulate styles and markup within a component
`),
el("li").append(...T`
${el("strong", "HTML Templates:")} Define reusable markup structures
`)
),
el("p").append(...T` el("p").append(...T`
To start with, lets see how to use native Custom Elements. As starting point please read Let's start with a basic Custom Element example without DDE to establish the foundation:
${el("a", references.mdn_custom_elements).append( el("strong", t`Using Custom Elements`), t` on MDN` )}.
To sum up and for mnemonic see following code overview:
`), `),
el(code, { src: fileURL("./components/examples/customElement/native-basic.js"), page_id }), el(code, { src: fileURL("./components/examples/customElement/native-basic.js"), page_id }),
el("div", { className: "note" }).append(
el("p").append(...T`
For complete information on Web Components, see the
${el("a", references.mdn_custom_elements).append(el("strong", t`MDN documentation`))}.
Also, ${el("a", references.custom_elements_tips).append(el("strong", t`Handy Custom Elements Patterns`))}
provides useful techniques for connecting attributes with properties.
`)
),
el(h3, t`DDE Integration: Step 1 - Event Handling`),
el("p").append(...T` el("p").append(...T`
For more advanced use of Custom Elements, the summary ${el("a", references.custom_elements_tips) The first step in integrating DDE with Web Components is enabling DDE's event system to work with your
.append( el("strong", t`Handy Custom Elements Patterns`) )} may be useful. Especially pay attention to Custom Elements. This is done with ${el("code", "customElementWithDDE")}, which makes your Custom Element
linking HTML attributes and defining setters/getters, this is very helpful to use in combination with compatible with DDE's event handling.
the library (${el("code", `el(HTMLCustomElement.tagName, { customAttribute: "${t`new-value`}" });`)}).
`),
el("p").append(...T`
Also see the Life Cycle Events sections, very similarly we would like to use
${el("a", { textContent: t`DDE events`, href: "./p03-events.html", title: t`See events part of the library
documentation` })}. To do it, the library provides function ${el("code", "customElementWithDDE")}
`), `),
el("div", { className: "function-table" }).append(
el("h4", t`customElementWithDDE`),
el("dl").append(
el("dt", t`Purpose`),
el("dd", t`Enables DDE's event system to work with your Custom Element`),
el("dt", t`Usage`),
el("dd", t`customElementWithDDE(YourElementClass)`),
el("dt", t`Benefits`),
el("dd", t`Allows using on.connected(), on.disconnected(), etc. with your element`)
)
),
el(example, { src: fileURL("./components/examples/customElement/customElementWithDDE.js"), page_id }), el(example, { src: fileURL("./components/examples/customElement/customElementWithDDE.js"), page_id }),
el("h3", t`Custom Elements with DDE`), el("div", { className: "tip" }).append(
el("p").append(...T`
${el("strong", "Key Point:")} The ${el("code", "customElementWithDDE")} function adds event dispatching
to your Custom Element lifecycle methods, making them work seamlessly with DDE's event system.
`)
),
el(h3, t`DDE Integration: Step 2 - Rendering Components`),
el("p").append(...T` el("p").append(...T`
The ${el("code", "customElementWithDDE")} function is only (small) part of the inregration of the library. The next step is to use DDE's component rendering within your Custom Element. This is done with
More important for coexistence is render component function as a body of the Custom Element. For that, you ${el("code", "customElementRender")}, which connects your DDE component function to the Custom Element.
can use ${el("code", "customElementRender")} with arguments instance reference, target for connection,
render function and optional properties (will be passed to the render function) see later
`), `),
el("div", { className: "function-table" }).append(
el("h4", t`customElementRender`),
el("dl").append(
el("dt", t`Purpose`),
el("dd", t`Connects a DDE component function to a Custom Element`),
el("dt", t`Parameters`),
el("dd").append(
el("ol").append(
el("li", t`Target (usually this or this.shadowRoot)`),
el("li", t`Component function that returns a DOM tree`),
el("li", t`Optional: Attributes transformer function (default or S.observedAttributes)`)
)
),
el("dt", t`Returns`),
el("dd", t`The rendered DOM tree`)
)
),
el(example, { src: fileURL("./components/examples/customElement/dde.js"), page_id }), el(example, { src: fileURL("./components/examples/customElement/dde.js"), page_id }),
el("div", { className: "note" }).append(
el("p").append(...T`
In this example, we're using Shadow DOM (${el("code", "this.attachShadow()")}) for encapsulation,
but you can also render directly to the element with ${el("code", "customElementRender(this, ...)")}.
`)
),
el(h3, t`Reactive Web Components with Signals`),
el("p").append(...T` el("p").append(...T`
as you can see, you can use components created based on the documentation previously introduced. To unlock One of the most powerful features of integrating DDE with Web Components is connecting HTML attributes
full potential, use with combination ${el("code", "customElementWithDDE")} (allows to use livecycle events) to DDE's reactive signals system. This creates truly reactive custom elements.
and ${el("code", "observedAttributes")} (converts attributes to render function arguments `),
${el("em", "default")}) or ${el("code", "S.observedAttributes")} (converts attributes to signals). el("div", { className: "tip" }).append(
el("p").append(...T`
${el("strong", "Two Ways to Handle Attributes:")}
`),
el("ol").append(
el("li").append(...T`
${el("code", "observedAttributes")} - Passes attributes as regular values (static)
`),
el("li").append(...T`
${el("code", "S.observedAttributes")} - Transforms attributes into signals (reactive)
`)
)
),
el("p").append(...T`
Using ${el("code", "S.observedAttributes")} creates a reactive connection between your element's attributes
and its internal rendering. When attributes change, your component automatically updates!
`), `),
el(example, { src: fileURL("./components/examples/customElement/observedAttributes.js"), page_id }), el(example, { src: fileURL("./components/examples/customElement/observedAttributes.js"), page_id }),
el("div", { className: "callout" }).append(
el("h4", t`How S.observedAttributes Works`),
el("ol").append(
el("li", t`Takes each attribute listed in static observedAttributes`),
el("li", t`Creates a DDE signal for each one`),
el("li", t`Automatically updates these signals when attributes change`),
el("li", t`Passes the signals to your component function`),
el("li", t`Your component reacts to changes through signal subscriptions`)
)
),
el(h3, t`Shadow DOM`), el(h3, t`Working with Shadow DOM`),
el("p").append(...T` el("p").append(...T`
Shadow DOM is a web platform feature that allows for the encapsulation of a components internal DOM tree Shadow DOM provides encapsulation for your component's styles and markup. When using DDE with Shadow DOM,
from the rest of the document. This means that styles and scripts applied to the document will not affect you get the best of both worlds: encapsulation plus declarative DOM creation.
the components internal DOM, and vice versa.
`), `),
el("div", { className: "illustration" }).append(
el("h4", t`Shadow DOM Encapsulation`),
el("pre").append(el("code", `
<my-custom-element>
  
    #shadow-root
      Created with DDE:
    
      <div>
       <h2>Title</h2>
       <p>Content</p>
`))
),
el(example, { src: fileURL("./components/examples/customElement/shadowRoot.js"), page_id }), el(example, { src: fileURL("./components/examples/customElement/shadowRoot.js"), page_id }),
el("p").append(...T` el("p").append(...T`
Regarding to ${el("code", "this.attachShadow({ mode: 'open' })")} see quick overview For more information on Shadow DOM, see
${el("a", { textContent: t`Using Shadow DOM`, ...references.mdn_shadow_dom_depth })}. An another source of ${el("a", { textContent: t`Using Shadow DOM`, ...references.mdn_shadow_dom_depth })}, or the comprehensive
information can be ${el("a", { textContent: t`Shadow DOM in Depth`, ...references.shadow_dom_depth })}. ${el("a", { textContent: t`Shadow DOM in Depth`, ...references.shadow_dom_depth })}.
`), `),
el(h3, t`Working with Slots`),
el("p").append(...T` el("p").append(...T`
Besides the encapsulation, the Shadow DOM allows for using the ${el("a", references.mdn_shadow_dom_slot).append( Besides the encapsulation, the Shadow DOM allows for using the ${el("a", references.mdn_shadow_dom_slot).append(
el("strong", t`<slot>`), t` element(s)`)}. You can simulate this feature using ${el("code", "simulateSlots")}: el("strong", t`<slot>`), t` element(s)`)}. You can simulate this feature using ${el("code", "simulateSlots")}:
`), `),
el(example, { src: fileURL("./components/examples/customElement/simulateSlots.js"), page_id }), el(example, { src: fileURL("./components/examples/customElement/simulateSlots.js"), page_id }),
el("div", { className: "function-table" }).append(
el("h4", t`simulateSlots`),
el("dl").append(
el("dt", t`Purpose`),
el("dd", t`Provides slot functionality when you cannot/do not want to use shadow DOM`),
el("dt", t`Parameters`),
el("dd", t`A mapping object of slot names to DOM elements`)
)
),
el(h3, t`Best Practices for Web Components with DDE`),
el("p").append(...T` el("p").append(...T`
To sum up: When combining DDE with Web Components, follow these recommendations:
`), `),
el("ul").append( el("ol").append(
el("li").append(...T` el("li").append(...T`
The use of shadow DOM to encapsulate the internal structure of the custom element, which affects how ${el("strong", "Always use customElementWithDDE")} to enable event integration
the custom element can be styled and modified using JavaScript and CSS.
`), `),
el("li").append(...T` el("li").append(...T`
The ability to access and modify the internal structure of the custom element using JavaScript, which ${el("strong", "Prefer S.observedAttributes")} for reactive attribute connections
is affected by the use of shadow DOM and the mode of the shadow DOM.
`), `),
el("li").append(...T` el("li").append(...T`
The use of slots to allow for the insertion of content from the parent document into the custom ${el("strong", "Create reusable component functions")} that your custom elements render
element, which is affected by the use of shadow DOM and the mode of the shadow DOM.
`), `),
el("li").append(...T`
${el("strong", "Use scope.host()")} to clean up event listeners and subscriptions
`),
el("li").append(...T`
${el("strong", "Add setters and getters")} for better property access to your element
`)
),
el("div", { className: "troubleshooting" }).append(
el("h4", t`Common Issues`),
el("dl").append(
el("dt", t`Events not firing properly`),
el("dd", t`Make sure you called customElementWithDDE before defining the element`),
el("dt", t`Attributes not updating`),
el("dd", t`Check that you've properly listed them in static observedAttributes`),
el("dt", t`Component not rendering`),
el("dd", t`Verify customElementRender is called in connectedCallback, not constructor`)
)
), ),
el(mnemonic) el(mnemonic)

192
docs/p07-debugging.html.js Normal file
View File

@ -0,0 +1,192 @@
import { T, t } from "./utils/index.js";
export const info= {
title: t`Debugging`,
fullTitle: t`Debugging applications with deka-dom-el`,
description: t`Techniques for debugging applications using deka-dom-el, especially signals.`,
};
import { el } from "deka-dom-el";
import { simplePage } from "./layout/simplePage.html.js";
import { example } from "./components/example.html.js";
import { h3 } from "./components/pageUtils.html.js";
import { code } from "./components/code.html.js";
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
/** @param {import("./types.d.ts").PageAttrs} attrs */
export function page({ pkg, info }){
const page_id= info.id;
return el(simplePage, { info, pkg }).append(
el("p").append(...T`
Debugging is an essential part of application development. This guide provides techniques
and best practices for debugging applications built with deka-dom-el, with a focus on signals.
`),
el(h3, t`Debugging signals`),
el("p").append(...T`
Signals are reactive primitives that update the UI when their values change. When debugging signals,
you need to track their values, understand their dependencies, and identify why updates are or aren't happening.
`),
el("h4", t`Inspecting signal values`),
el("p").append(...T`
The simplest way to debug a signal is to log its current value by calling the get method:
`),
el(code, { content: `
const signal = S(0);
console.log('Current value:', signal.get());
// without triggering updates
console.log('Current value:', signal.valueOf());
`, page_id }),
el("p").append(...T`
You can also monitor signal changes by adding a listener:
`),
el(code, {
content:
"// Log every time the signal changes\nS.on(signal, value => console.log('Signal changed:', value));",
page_id }),
el("h4", t`Debugging derived signals`),
el("p").append(...T`
With derived signals (created with ${el("code", "S(() => computation))")}), debugging is a bit more complex
because the value depends on other signals. To understand why a derived signal isn't updating correctly:
`),
el("ol").append(
el("li", t`Check that all dependency signals are updating correctly`),
el("li", t`Add logging inside the computation function to see when it runs`),
el("li", t`Verify that the computation function actually accesses the signal values with .get()`)
),
el(example, { src: fileURL("./components/examples/debugging/consoleLog.js"), page_id }),
el(h3, t`Common signal debugging issues`),
el("h4", t`Signal updates not triggering UI changes`),
el("p").append(...T`
If signal updates aren't reflected in the UI, check:
`),
el("ul").append(
el("li", t`That you're using signal.set() to update the value, not modifying objects/arrays directly`),
el("li", t`For mutable objects, ensure you're using actions or making proper copies before updating`),
el("li", t`That the signal is actually connected to the DOM element (check your S.el or attribute binding code)`)
),
el(code, { src: fileURL("./components/examples/debugging/mutations.js"), page_id }),
el("h4", t`Memory leaks with signal listeners`),
el("p").append(...T`
Signal listeners can cause memory leaks if not properly cleaned up. Always use AbortSignal
to cancel listeners.
`),
el("h4", t`Performance issues with frequently updating signals`),
el("p").append(...T`
If you notice performance issues with signals that update very frequently:
`),
el("ul").append(
el("li", t`Consider debouncing or throttling signal updates`),
el("li", t`Make sure derived signals don't perform expensive calculations unnecessarily`),
el("li", t`Keep signal computations focused and minimal`)
),
el(code, { src: fileURL("./components/examples/debugging/debouncing.js"), page_id }),
el(h3, t`Browser DevTools tips for deka-dom-el`),
el("p").append(...T`
When debugging in the browser, deka-dom-el provides several helpful DevTools-friendly features:
`),
el("h4", t`Identifying components in the DOM`),
el("p").append(...T`
deka-dom-el marks components in the DOM with special comment nodes to help you identify component boundaries.
Components created with ${el("code", "el(ComponentFunction)")} are marked with comment nodes
${el("code", "<!--<dde:mark type=\"component\" name=\"MyComponent\" host=\"parentElement\"/>-->")} and
includes:
`),
el("ul").append(
el("li", "type - Identifies the type of marker (\"component\", \"reactive\", or \"later\")"),
el("li", "name - The name of the component function"),
el("li", "host - Indicates whether the host is \"this\" (for DocumentFragments) or \"parentElement\""),
),
el("h4", t`Finding reactive elements in the DOM`),
el("p").append(...T`
When using ${el("code", "S.el()")}, deka-dom-el creates reactive elements in the DOM
that are automatically updated when signal values change. These elements are wrapped in special
comment nodes for debugging (to be true they are also used internally, so please do not edit them by hand):
`),
el(code, { src: fileURL("./components/examples/debugging/dom-reactive-mark.js"), page_id }),
el("p").append(...T`
This is particularly useful when debugging why a reactive section isn't updating as expected.
You can inspect the elements between the comment nodes to see their current state and the
signal connections through \`__dde_reactive\` of the host element.
`),
el("h4", t`DOM inspection properties`),
el("p").append(...T`
Elements created with the deka-dom-el library have special properties to aid in debugging:
`),
el("p").append(...T`
${el("code", "<element>.__dde_reactive")} - An array property on DOM elements that tracks signal-to-element
relationships. This allows you to quickly identify which elements are reactive and what signals they're
bound to. Each entry in the array contains:
`),
el("ul").append(
el("li", "A pair of signal and listener function: [signal, listener]"),
el("li", "Additional context information about the element or attribute"),
el("li", "Automatically managed by signal.el(), signal.observedAttributes(), and processReactiveAttribute()")
),
el("p").append(...T`
These properties make it easier to understand the reactive structure of your application when inspecting elements.
`),
el(example, { src: fileURL("./components/examples/signals/debugging-dom.js"), page_id }),
el("h4", t`Examining signal connections`),
el("p").append(...T`
${el("code", "<signal>.__dde_signal")} - A Symbol property used to identify and store the internal state of
signal objects. It contains the following information:
`),
el("ul").append(
el("li", "listeners: A Set of functions called when the signal value changes"),
el("li", "actions: Custom actions that can be performed on the signal"),
el("li", "onclear: Functions to run when the signal is cleared"),
el("li", "host: Reference to the host element/scope"),
el("li", "defined: Stack trace information for debugging"),
el("li", "readonly: Boolean flag indicating if the signal is read-only")
),
el("p").append(...T`
to determine the current value of the signal, call ${el("code", "signal.valueOf()")}.
`),
el("p").append(...T`
You can inspect (host) element relationships and bindings with signals in the DevTools console using
${el("code", "$0.__dde_reactive")} (for currently selected element). In the console you will see a list of
${el("code", "[ [ signal, listener ], element, property ]")}, where:
`),
el("ul").append(
el("li", "signal — the signal triggering the changes"),
el("li", "listener — the listener function (this is an internal function for DDE)"),
el("li", "element — the DOM element that is bound to the signal"),
el("li", "property — the attribute or property name which is changing based on the signal"),
),
el("p").append(...T`
the structure of \`__dde_reactive\` utilizes the browser's behavior of packing the first field,
so you can see the element and property that changes in the console right away.
`),
el("h4", t`Debugging with breakpoints`),
el("p").append(...T`
Effective use of breakpoints can help track signal flow:
`),
el("ul").append(
el("li").append(...T`
Set breakpoints in signal update methods to track when values change
`),
el("li").append(...T`
Use conditional breakpoints to only break when specific signals change to certain values
`),
el("li").append(...T`
Set breakpoints in your signal computation functions to see when derived signals recalculate
`),
el("li").append(...T`
Use performance profiling to identify bottlenecks in signal updates
`)
),
);
}

255
docs/p08-extensions.html.js Normal file
View File

@ -0,0 +1,255 @@
import { T, t } from "./utils/index.js";
export const info= {
title: t`Extensions and 3rd Party`,
fullTitle: t`Extending deka-dom-el with Third-Party Functionalities`,
description: t`How to extend deka-dom-el with third-party libraries and custom functionalities.`,
};
import { el } from "deka-dom-el";
import { simplePage } from "./layout/simplePage.html.js";
import { h3 } from "./components/pageUtils.html.js";
import { code } from "./components/code.html.js";
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
/** @param {import("./types.js").PageAttrs} attrs */
export function page({ pkg, info }){
const page_id= info.id;
return el(simplePage, { info, pkg }).append(
el("p").append(...T`
deka-dom-el is designed with extensibility in mind. This page covers how to separate
third-party functionalities and integrate them seamlessly with the library, focusing on
proper resource cleanup and interoperability.
`),
el(h3, t`DOM Element Extensions with Addons`),
el("p").append(...T`
The primary method for extending DOM elements in deka-dom-el is through the Addon pattern.
Addons are functions that take an element and applying some functionality to it. This pattern enables a
clean, functional approach to element enhancement.
`),
el("div", { className: "callout" }).append(
el("h4", t`What are Addons?`),
el("p").append(...T`
Addons are simply functions with the signature: (element) => void. They:
`),
el("ul").append(
el("li", t`Accept a DOM element as input`),
el("li", t`Apply some behavior, property, or attribute to the element`),
)
),
el(code, { content: `
// Basic structure of an addon
function myAddon(config) {
return function(element) {
// Apply functionality to element
element.dataset.myAddon = config.option;
};
}
// Using an addon
el("div", { id: "example" }, myAddon({ option: "value" }));
`.trim(), page_id }),
el(h3, t`Resource Cleanup with Abort Signals`),
el("p").append(...T`
When extending elements with functionality that uses resources like event listeners, timers,
or external subscriptions, it's critical to clean up these resources when the element is removed
from the DOM. deka-dom-el provides utilities for this through AbortSignal integration.
`),
el("div", { className: "tip" }).append(
el("p").append(...T`
The ${el("code", "on.disconnectedAsAbort")} utility creates an AbortSignal that automatically
triggers when an element is disconnected from the DOM, making cleanup much easier to manage.
`)
),
el(code, { content: `
// Third-party library addon with proper cleanup
function externalLibraryAddon(config, signal) {
return function(element) {
// Initialize the third-party library
const instance = new ExternalLibrary(element, config);
// Set up cleanup when the element is removed
signal.addEventListener('abort', () => {
instance.destroy();
});
return element;
};
}
// dde component
function Component(){
const { host }= scope;
const signal= on.disconnectedAsAbort(host);
return el("div", null, externalLibraryAddon({ option: "value" }, signal));
}
`.trim(), page_id }),
el(h3, t`Building Library-Independent Extensions`),
el("p").append(...T`
When creating extensions, it's a good practice to make them as library-independent as possible.
This approach enables better interoperability and future-proofing.
`),
el("div", { className: "illustration" }).append(
el("h4", t`Library-Independent vs. Library-Dependent Extension`),
el("div", { className: "tabs" }).append(
el("div", { className: "tab" }).append(
el("h5", t`✅ Library-Independent`),
el(code, { content: `
function enhancementElement({ signal, ...config }) {
// do something
return function(element) {
// do something
signal.addEventListener('abort', () => {
// do cleanup
});
};
}
`.trim(), page_id })
),
el("div", { className: "tab" }).append(
el("h5", t`⚠️ Library-Dependent`),
el(code, { content: `
// Tightly coupled to deka-dom-el
function enhancementElement(config) {
return function(element) {
// do something
on.disconnected(()=> {
// do cleanup
})(element);
};
}
`.trim(), page_id })
)
)
),
el(h3, t`Signal Extensions and Future Compatibility`),
el("p").append(...T`
Unlike DOM elements, signal functionality in deka-dom-el currently lacks a standardized
way to create library-independent extensions. This is because signals are implemented
differently across libraries.
`),
el("div", { className: "note" }).append(
el("p").append(...T`
In the future, JavaScript may include built-in signals through the
${el("a", { href: "https://github.com/tc39/proposal-signals", textContent: "TC39 Signals Proposal" })}.
deka-dom-el is designed with future compatibility in mind and will hopefully support these
native signals without breaking changes when they become available.
`)
),
el("p").append(...T`
For now, when extending signals functionality, focus on clear interfaces and isolation to make
future migration easier.
`),
el(code, { content: `
// Signal extension with clear interface
function createEnhancedSignal(initialValue) {
const signal = S(initialValue);
// Extension functionality
const increment = () => signal.set(signal.get() + 1);
const decrement = () => signal.set(signal.get() - 1);
// Return the original signal with added methods
return Object.assign(signal, {
increment,
decrement
});
}
// Usage
const counter = createEnhancedSignal(0);
el("button")({ onclick: () => counter.increment() }, "Increment");
el("div", S.text\`Count: \${counter}\`);
`.trim(), page_id }),
el(h3, t`Using Signals Independently`),
el("p").append(...T`
While signals are tightly integrated with DDE's DOM elements, you can also use them independently.
This can be useful when you need reactivity in non-UI code or want to integrate with other libraries.
`),
el("p").append(...T`
There are two ways to import signals:
`),
el("ol").append(
el("li").append(...T`
${el("strong", "Standard import")}: ${el("code", "import { S } from \"deka-dom-el/signals\";")}
This automatically registers signals with DDE's DOM reactivity system
`),
el("li").append(...T`
${el("strong", "Independent import")}: ${el("code", "import { S } from \"deka-dom-el/src/signals-lib\";")}
This gives you just the signal system without DOM integration
`)
),
el(code, { content: `// Independent signals without DOM integration
import { signal as S, isSignal } from "deka-dom-el/src/signals-lib";
// Create and use signals as usual
const count = S(0);
const doubled = S(() => count.get() * 2);
// Subscribe to changes
S.on(count, value => console.log(value));
// Update signal value
count.set(5); // Logs: 5
console.log(doubled.get()); // 10`, page_id }),
el("p").append(...T`
The independent signals API includes all core functionality (${el("code", "S()")}, ${el("code", "S.on()")},
${el("code", "S.action()")}).
`),
el("div", { class: "callout" }).append(
el("h4", t`When to Use Independent Signals`),
el("ul").append(
el("li", t`For non-UI state management in your application`),
el("li", t`When integrating with other libraries or frameworks`),
el("li", t`To minimize bundle size when you don't need DOM integration`)
)
),
el(h3, t`Best Practices for Extensions`),
el("ol").append(
el("li").append(...T`
${el("strong", "Use AbortSignals for cleanup:")} Always implement proper resource cleanup with
${el("code", "on.disconnectedAsAbort")} or similar mechanisms
`),
el("li").append(...T`
${el("strong", "Separate core logic from library adaptation:")} Make your core functionality work
with standard DOM APIs when possible
`),
el("li").append(...T`
${el("strong", "Document clearly:")} Provide clear documentation on how your extension works
and what resources it uses
`),
el("li").append(...T`
${el("strong", "Follow the Addon pattern:")} Keep to the (element) => element signature for
DOM element extensions
`),
el("li").append(...T`
${el("strong", "Avoid modifying global state:")} Extensions should be self-contained and not
affect other parts of the application
`)
),
el("div", { className: "troubleshooting" }).append(
el("h4", t`Common Extension Pitfalls`),
el("dl").append(
el("dt", t`Leaking event listeners or resources`),
el("dd", t`Always use AbortSignal-based cleanup to automatically remove listeners when elements
are disconnected`),
el("dt", t`Tight coupling with library internals`),
el("dd", t`Focus on standard DOM APIs and clean interfaces rather than depending on deka-dom-el
implementation details`),
el("dt", t`Mutating element prototypes`),
el("dd", t`Prefer compositional approaches with addons over modifying element prototypes`),
el("dt", t`Complex initialization in addons`),
el("dd", t`Split complex logic into a separate initialization function that the addon can call`)
)
)
);
}

138
docs/p09-ssr.html.js Normal file
View File

@ -0,0 +1,138 @@
import { T, t } from "./utils/index.js";
export const info= {
title: t`Server-Side Rendering (SSR)`,
fullTitle: t`Server-Side Rendering with deka-dom-el`,
description: t`Using deka-dom-el for server-side rendering with jsdom to generate static HTML.`,
};
import { el } from "deka-dom-el";
import { simplePage } from "./layout/simplePage.html.js";
import { h3 } from "./components/pageUtils.html.js";
import { code } from "./components/code.html.js";
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
/** @param {import("./types.js").PageAttrs} attrs */
export function page({ pkg, info }){
const page_id= info.id;
return el(simplePage, { info, pkg }).append(
el("div", { className: "warning" }).append(
el("p").append(...T`
This part of the documentation is primarily intended for technical enthusiasts and authors of
3rd-party libraries. It describes an advanced feature, not a core part of the library. Most users will
not need to implement this functionality directly in their applications. This capability will hopefully
be covered by third-party libraries or frameworks that provide simpler SSR integration using
deka-dom-el.
`)
),
el("p").append(...T`
deka-dom-el isn't limited to browser environments. Thanks to its flexible architecture,
it can be used for server-side rendering (SSR) to generate static HTML files.
This is achieved through integration with for example ${el("a", { href: "https://github.com/tmpvar/jsdom",
textContent: "jsdom" })}, a JavaScript implementation of web standards for Node.js.
`),
el(code, { src: fileURL("./components/examples/ssr/intro.js"), page_id }),
el(h3, t`Why Server-Side Rendering?`),
el("p").append(...T`
SSR offers several benefits:
`),
el("ul").append(
el("li", t`Improved SEO — Search engines can easily index fully rendered content`),
el("li", t`Faster initial page load — Users see content immediately without waiting for JavaScript to load`),
el("li", t`Better performance on low-powered devices — Less JavaScript processing on the client`),
el("li", t`Content available without JavaScript — Useful for users who have disabled JavaScript`),
el("li", t`Static site generation — Build files once, serve them many times`)
),
el(h3, t`How jsdom Integration Works`),
el("p").append(...T`
The jsdom export in deka-dom-el provides the necessary tools to use the library in Node.js
by integrating with jsdom. Here's what it does:
`),
el("ol").append(
el("li", t`Creates a virtual DOM environment in Node.js using jsdom`),
el("li", t`Registers DOM globals like HTMLElement, document, etc. for deka-dom-el to use`),
el("li", t`Sets an SSR flag in the environment to enable SSR-specific behaviors`),
el("li", t`Provides a promise queue system for managing async operations during rendering`),
el("li", t`Handles DOM property/attribute mapping differences between browsers and jsdom`)
),
el(code, { src: fileURL("./components/examples/ssr/start.js"), page_id }),
el(h3, t`Basic SSR Example`),
el("p").append(...T`
Here's a simple example of how to use deka-dom-el for server-side rendering in a Node.js script:
`),
el(code, { src: fileURL("./components/examples/ssr/basic-example.js"), page_id }),
el(h3, t`Building a Static Site Generator`),
el("p").append(...T`
You can build a complete static site generator with deka-dom-el. In fact, this documentation site
is built using deka-dom-el for server-side rendering! Here's how the documentation build process works:
`),
el(code, { src: fileURL("./components/examples/ssr/static-site-generator.js"), page_id }),
el(h3, t`Working with Async Content in SSR`),
el("p").append(...T`
The jsdom export includes a queue system to handle asynchronous operations during rendering.
This is crucial for components that fetch data or perform other async tasks.
`),
el(code, { src: fileURL("./components/examples/ssr/async-data.js"), page_id }),
el(h3, t`Working with Dynamic Imports for SSR`),
el("p").append(...T`
When structuring server-side rendering code, a crucial pattern to follow is using dynamic imports
for both the deka-dom-el/jsdom module and your page components.
`),
el("p").append(...T`
Why is this important?
`),
el("ul").append(
el("li").append(...T`
${el("strong", "Static imports are hoisted:")} JavaScript hoists import statements to the top of the file,
executing them before any other code
`),
el("li").append(...T`
${el("strong", "Environment registration timing:")} The jsdom module auto-registers the DOM environment
when imported, which must happen ${el("em", "after")} you've created your JSDOM instance and
${el("em", "before")} you import your components using ${el("code", "import { el } from \"deka-dom-el\";")}.
`),
el("li").append(...T`
${el("strong", "Correct initialization order:")} You need to control the exact sequence of:
create JSDOM register environment import components
`)
),
el("p").append(...T`
Follow this pattern when creating server-side rendered pages:
`),
el(code, { src: fileURL("./components/examples/ssr/pages.js"), page_id }),
el(h3, t`SSR Considerations and Limitations`),
el("p").append(...T`
When using deka-dom-el for SSR, keep these considerations in mind:
`),
el("ul").append(
el("li", t`Browser-specific APIs like window.localStorage are not available in jsdom by default`),
el("li", t`Event listeners added during SSR won't be functional in the final HTML unless hydrated on the client`),
el("li", t`Some DOM features may behave differently in jsdom compared to real browsers`),
el("li", t`For large sites, you may need to optimize memory usage by creating a new jsdom instance for each page`)
),
el("p").append(...T`
For advanced SSR applications, consider implementing hydration on the client-side to restore
interactivity after the initial render.
`),
el(h3, t`Real Example: How This Documentation is Built`),
el("p").append(...T`
This documentation site itself is built using deka-dom-el's SSR capabilities.
The build process collects all page components, renders them with jsdom, and outputs static HTML files.
`),
el(code, { src: fileURL("./components/examples/ssr/static-site-generator.js"), page_id }),
el("p").append(...T`
The resulting static files can be deployed to any static hosting service,
providing fast loading times and excellent SEO without the need for client-side JavaScript
to render the initial content.
`),
);
}

363
docs/p10-ireland.html.js Normal file
View File

@ -0,0 +1,363 @@
import { T, t } from "./utils/index.js";
export const info= {
title: t`Ireland Components`,
fullTitle: t`Interactive Demo Components with Server-Side Pre-Rendering`,
description: t`Creating live, interactive component examples in documentation with server-side
rendering and client-side hydration.`,
};
import { el } from "deka-dom-el";
import { simplePage } from "./layout/simplePage.html.js";
import { h3 } from "./components/pageUtils.html.js";
import { code } from "./components/code.html.js";
import { ireland } from "./components/ireland.html.js";
/** @param {string} url */
const fileURL= url=> new URL(url, import.meta.url);
/** @param {import("./types.js").PageAttrs} attrs */
export function page({ pkg, info }){
const page_id= info.id;
return el(simplePage, { info, pkg }).append(
el("div", { className: "warning" }).append(
el("p").append(...T`
This part of the documentation is primarily intended for technical enthusiasts and authors of
3rd-party libraries. It describes an advanced feature, not a core part of the library. Most users will
not need to implement this functionality directly in their applications. This capability will hopefully
be covered by third-party libraries or frameworks that provide simpler SSR integration using
deka-dom-el.
`)
),
el(h3, t`What Are Ireland Components?`),
el("p").append(...T`
Ireland components are a special type of documentation component that:
`),
el("ul").append(
el("li", t`Display source code with syntax highlighting`),
el("li", t`Pre-render components on the server during documentation build`),
el("li", t`Copy component source files to the documentation output`),
el("li", t`Provide client-side rehydration for interactive demos`),
el("li", t`Allow users to run and experiment with components in real-time`)
),
el(h3, t`How Ireland Components Work`),
el("p").append(...T`
The Ireland component system consists of several parts working together:
`),
el("ol").append(
el("li").append(...T`
${el("strong", "Server-side rendering:")} Components are pre-rendered during the documentation build process
`),
el("li").append(...T`
${el("strong", "Component registration:")} Source files are copied to the documentation output directory
`),
el("li").append(...T`
${el("strong", "Client-side scripting:")} JavaScript code is generated to load and render components
`),
el("li").append(...T`
${el("strong", "User interaction:")} The "Run Component" button dynamically loads and renders the component
`)
),
el(h3, t`Implementation Architecture`),
el("p").append(...T`
The core of the Ireland system is implemented in ${el("code", "docs/components/ireland.html.js")}.
It integrates with the SSR build process using the ${el("code", "registerClientFile")} function
from ${el("code", "docs/ssr.js")}.
`),
el(code, { content: `
// Basic usage of an ireland component
el(ireland, {
src: fileURL("./components/examples/path/to/component.js"),
exportName: "NamedExport", // optional, defaults to "default",
})`, page_id }),
el("p").append(...T`
During the build process (${el("code", "bs/docs.js")}), the following happens:
`),
el("ol").append(
el("li", t`Component source code is loaded and displayed with syntax highlighting`),
el("li", t`Source files are registered to be copied to the output directory`),
el("li", t`Client-side scripts are generated for each page with ireland components`),
el("li", t`The component is wrapped in a UI container with controls`)
),
el(h3, t`Core Implementation Details`),
el("p").append(...T`
Let's look at the key parts of the ireland component implementation:
`),
el("h4", t`Building SSR`),
el(code, { content: `
// From bs/docs.js - Server-side rendering engine
import { createHTMl } from "./docs/jsdom.js";
import { register, queue } from "../jsdom.js";
import { path_target, dispatchEvent } from "../docs/ssr.js";
// For each page, render it on the server
for(const { id, info } of pages) {
// Create a virtual DOM environment for server-side rendering
const serverDOM = createHTMl("");
serverDOM.registerGlobally("HTMLScriptElement");
// Register deka-dom-el with the virtual DOM
const { el } = await register(serverDOM.dom);
// Import and render the page component
const { page } = await import(\`../docs/\${id}.html.js\`);
serverDOM.document.body.append(
el(page, { pkg, info }),
);
// Process the queue of asynchronous operations
await queue();
// Trigger render event handlers
dispatchEvent("oneachrender", document);
// Write the HTML to the output file
s.echo(serverDOM.serialize()).to(path_target.root+id+".html");
}
// Final build step - trigger SSR end event
dispatchEvent("onssrend");
`, page_id }),
el("h4", t`File Registration`),
el(code, { content: `
// From docs/ssr.js - File registration system
export function registerClientFile(url, { head, folder = "", replacer } = {}) {
// Ensure folder path ends with a slash
if(folder && !folder.endsWith("/")) folder += "/";
// Extract filename from URL
const file_name = url.pathname.split("/").pop();
// Create target directory if needed
s.mkdir("-p", path_target.root+folder);
// Get file content and apply optional replacer function
let content = s.cat(url);
if(replacer) content = s.echo(replacer(content.toString()));
// Write content to the output directory
content.to(path_target.root+folder+file_name);
// If a head element was provided, add it to the document
if(!head) return;
head[head instanceof HTMLScriptElement ? "src" : "href"] = file_name;
document.head.append(head);
}
`, page_id }),
el("h4", t`Server-Side Rendering`),
el(code, { content: `
// From docs/components/ireland.html.js - Server-side component implementation
export function ireland({ src, exportName = "default", props = {} }) {
// Calculate relative path for imports
const path = "./"+relative(dir, src.pathname);
// Generate unique ID for this component instance
const id = "ireland-" + generateComponentId(src);
// Create placeholder element
const element = el.mark({ type: "later", name: ireland.name });
// Import and render the component during SSR
queue(import(path).then(module => {
const component = module[exportName];
element.replaceWith(el(component, props, mark(id)));
}));
// Register client-side hydration on first component
if(!componentsRegistry.size)
addEventListener("oneachrender", registerClientPart);
// Store component info for client-side hydration
componentsRegistry.set(id, {
src,
path: dirFE+"/"+path.split("/").pop(),
exportName,
props,
});
return element;
}
// Register client-side resources
function registerClientPart() {
// Process all component registrations
const todo = Array.from(componentsRegistry.entries())
.map(([ id, d ]) => {
// Copy the component source file to output directory
registerClientFile(d.src, {
folder: dirFE,
// Replace bare imports for browser compatibility
replacer(file) {
return file.replaceAll(
/ from "deka-dom-el(\/signals)?";/g,
\` from "./esm-with-signals.js";\`
);
}
});
return [ id, d ];
});
// Serialize the component registry for client-side use
const store = JSON.stringify(JSON.stringify(todo));
// Copy client-side scripts to output
registerClientFile(new URL("./ireland.js.js", import.meta.url));
registerClientFile(new URL("../../dist/esm-with-signals.js", import.meta.url), { folder: dirFE });
// Add import map for package resolution
document.head.append(
el("script", { type: "importmap" }).append(\`
{
"imports": {
"deka-dom-el": "./\${dirFE}/esm-with-signals.js",
"deka-dom-el/signals": "./\${dirFE}/esm-with-signals.js"
}
}
\`.trim())
);
// Add bootstrap script to load components
document.body.append(
el("script", { type: "module" }).append(\`
import { loadIrelands } from "./ireland.js.js";
loadIrelands(new Map(JSON.parse(\${store})));
\`.trim())
);
}
`, page_id }),
el("h4", t`Client-Side Hydration`),
el(code, { content: `
// From docs/components/ireland.js.js - Client-side hydration
import { el } from "./irelands/esm-with-signals.js";
export function loadIrelands(store) {
// Find all marked components in the DOM
document.body.querySelectorAll("[data-dde-mark]").forEach(ireland => {
const { ddeMark } = ireland.dataset;
// Skip if this component isn't in our registry
if(!store.has(ddeMark)) return;
// Get component information
const { path, exportName, props } = store.get(ddeMark);
// Dynamically import the component module
import("./" + path).then(module => {
// Replace the server-rendered element with the client-side version
ireland.replaceWith(el(module[exportName], props));
});
});
}
`, page_id }),
el(h3, t`Live Example`),
el("p").append(...T`
Here's a live example of an Ireland component showing a standard counter.
The component is defined in ${el("code", "docs/components/examples/ireland-test/counter.js")} and
rendered with the Ireland component system:
`),
el(code, {
src: fileURL("./components/examples/ireland-test/counter.js"),
page_id
}),
el(ireland, {
src: fileURL("./components/examples/ireland-test/counter.js"),
exportName: "CounterStandard",
page_id
}),
el("p").append(...T`
When the "Run Component" button is clicked, the component is loaded and rendered dynamically.
The counter state is maintained using signals, allowing for reactive updates as you click
the buttons to increment and decrement the value.
`),
el(h3, t`Creating Your Own Components`),
el("p").append(...T`
To create components for use with the Ireland system, follow these guidelines:
`),
el("ol").append(
el("li").append(...T`
${el("strong", "Export a function:")} Components should be exported as named or default functions
`),
el("li").append(...T`
`),
el("li").append(...T`
${el("strong", "Accept props:")} Components should accept a props object, even if not using it
`),
el("li").append(...T`
${el("strong", "Manage reactivity:")} Use signals for state management where appropriate
`),
el("li").append(...T`
${el("strong", "Handle cleanup:")} Include any necessary cleanup for event listeners or signals
`)
),
el(h3, t`Practical Considerations and Limitations`),
el("p").append(...T`
When implementing Ireland components in real documentation, there are several important
considerations to keep in mind:
`),
el("div", { className: "warning" }).append(
el("h4", t`Module Resolution and Bundling`),
el("p").append(...T`
The examples shown here use bare module specifiers like ${el("code", "import { el } from \"deka-dom-el\"")}
which aren't supported in all browsers without importmaps. In a production implementation, you would need to:
`),
el("ol").append(
el("li", t`Replace bare import paths with actual paths during the build process`),
el("li", t`Bundle component dependencies to avoid multiple requests`),
el("li", t`Ensure all module dependencies are properly resolved and copied to the output directory`)
),
el("p").append(...T`
In this documentation, we replace the paths with ${el("code", "./esm-with-signals.js")} and provide
a bundled version of the library, but more complex components might require a dedicated bundling step.
`)
),
el("div", { className: "note" }).append(
el("h4", t`Component Dependencies`),
el("p").append(...T`
Real-world components typically depend on multiple modules and assets. The Ireland system would need
to be extended to:
`),
el("ul").append(
el("li", t`Detect and analyze all dependencies of a component`),
el("li", t`Bundle these dependencies together or ensure they're properly copied to the output directory`),
el("li", t`Handle non-JavaScript assets like CSS, images, or data files`)
)
),
el(h3, t`Advanced Usage`),
el("p").append(...T`
The Ireland system can be extended in several ways to address these limitations:
`),
el("ul").append(
el("li", t`Integrate with a bundler like esbuild, Rollup, or Webpack`),
el("li", t`Add props support for configuring components at runtime`),
el("li", t`Implement module caching to reduce network requests`),
el("li", t`Add code editing capabilities for interactive experimentation`),
el("li", t`Support TypeScript and other languages through transpilation`),
el("li", t`Implement state persistence between runs`)
),
el("p").append(...T`
This documentation site itself is built using the techniques described here,
showcasing how deka-dom-el can be used to create both the documentation and
the interactive examples within it. The implementation here is simplified for clarity,
while a production-ready system would need to address the considerations above.
`)
);
}

View File

@ -1,7 +1,8 @@
export { t } from "./utils/index.js"; export { t } from "./utils/index.js";
export const path_target= { export const path_target= {
root: "dist/docs/", root: "dist/docs/",
css: "dist/docs/" css: "dist/docs/",
assets: "dist/docs/assets/"
}; };
/** /**
* This variable will be filled with the list of pages during the build process (see `bs/docs.js`). * This variable will be filled with the list of pages during the build process (see `bs/docs.js`).
@ -12,16 +13,23 @@ export let pages= [];
* @typedef registerClientFile * @typedef registerClientFile
* @type {function} * @type {function}
* @param {URL} url * @param {URL} url
* @param {HTMLScriptElement|HTMLLinkElement} [element_head] * @param {Object} [options]
* @param {HTMLScriptElement|HTMLLinkElement} [options.head]
* @param {string} [options.folder]
* @param {function} [options.replacer]
* */ * */
export function registerClientFile(url, element_head){ export function registerClientFile(url, { head, folder= "", replacer }= {}){
if(folder && !folder.endsWith("/")) folder+= "/";
const file_name= url.pathname.split("/").pop(); const file_name= url.pathname.split("/").pop();
s.cat(url).to(path_target.root+file_name); s.mkdir("-p", path_target.root+folder);
let content= s.cat(url)
if(replacer) content= s.echo(replacer(content.toString()));
content.to(path_target.root+folder+file_name);
if(!element_head) return; if(!head) return;
element_head[element_head instanceof HTMLScriptElement ? "src" : "href"]= file_name; head[head instanceof HTMLScriptElement ? "src" : "href"]= file_name;
document.head.append( document.head.append(
element_head head
); );
} }

1
docs/types.d.ts vendored
View File

@ -4,6 +4,7 @@ export type Info= {
id: string, id: string,
href: string, href: string,
title: string, title: string,
fullTitle: string,
description: string, description: string,
} }
export type Pages=Info[]; export type Pages=Info[];

View File

@ -15,7 +15,7 @@ export function thirdParty(){
}, { }, {
set(key, value){ set(key, value){
const p= this.value[key] || S(); const p= this.value[key] || S();
p(value); p.set(value);
this.value[key]= p; this.value[key]= p;
} }
}); });
@ -32,7 +32,7 @@ export function thirdParty(){
})(); })();
return el("input", { return el("input", {
className, className,
value: store().value(), value: store.get().value.get(),
type: "text", type: "text",
onchange: ev=> S.action(store, "set", "value", ev.target.value) onchange: ev=> S.action(store, "set", "value", ev.target.value)
}); });

View File

@ -9,24 +9,24 @@ export function fullNameComponent(){
const labels= [ "Name", "Surname" ]; const labels= [ "Name", "Surname" ];
const name= labels.map(_=> S("")); const name= labels.map(_=> S(""));
const full_name= S(()=> const full_name= S(()=>
name.map(l=> l()).filter(Boolean).join(" ") || "-"); name.map(l=> l.get()).filter(Boolean).join(" ") || "-");
scope.host( scope.host(
on.connected(()=> console.log(fullNameComponent)), on.connected(()=> console.log(fullNameComponent)),
on.disconnected(()=> console.log(fullNameComponent)) on.disconnected(()=> console.log(fullNameComponent))
); );
const count= S(0); const count= S(0);
setInterval(()=> count(count()+1), 5000); setInterval(()=> count.set(count.get()+1), 5000);
const style= { height: "80px", display: "block", fill: "currentColor" }; const style= { height: "80px", display: "block", fill: "currentColor" };
const elSVG= elNS("http://www.w3.org/2000/svg"); const elSVG= elNS("http://www.w3.org/2000/svg");
return el("div", { className }).append( return el("div", { className }).append(
el("h2", "Simple form:"), el("h2", "Simple form:"),
el("p", { textContent: S(()=> "Count: "+count()), el("p", { textContent: S(()=> "Count: "+count.get()),
dataset: { count }, classList: { count: S(() => count()%2 === 0) } }), dataset: { count }, classList: { count: S(() => count.get()%2 === 0) } }),
el("form", { onsubmit: ev=> ev.preventDefault() }).append( el("form", { onsubmit: ev=> ev.preventDefault() }).append(
...name.map((v, i)=> ...name.map((v, i)=>
el("label", labels[i]).append( el("label", labels[i]).append(
el("input", { type: "text", name: labels[i], value: v() }, on("change", ev=> v(ev.target.value))) el("input", { type: "text", name: labels[i], value: v.get() }, on("change", ev=> v.set(ev.target.value)))
)) ))
), ),
el("p").append( el("p").append(

View File

@ -45,7 +45,7 @@ export function todosComponent({ todos= [ "Task A" ] }= {}){
: el("ul").append( : el("ul").append(
...Array.from(ts).map(([ value, textContent ])=> ...Array.from(ts).map(([ value, textContent ])=>
memo(value, ()=> el(todoComponent, { textContent, value, className }, onremove))) memo(value, ()=> el(todoComponent, { textContent, value, className }, onremove)))
) ),
), ),
el("p", "Click to the text to edit it.") el("p", "Click to the text to edit it.")
), ),
@ -54,11 +54,11 @@ export function todosComponent({ todos= [ "Task A" ] }= {}){
el("label", "New todo: ").append( el("label", "New todo: ").append(
el("input", { name, type: "text", required: true }), el("input", { name, type: "text", required: true }),
), ),
el("button", "+") el("button", "+"),
), ),
el("div").append( el("div").append(
el("h3", "Output (JSON):"), el("h3", "Output (JSON):"),
el("output", S(()=> JSON.stringify(Array.from(todosO()), null, "\t"))) el("output", S(()=> JSON.stringify(Array.from(todosO.get()), null, "\t")))
) )
) )
} }
@ -80,13 +80,13 @@ function todoComponent({ textContent, value }){
const is_editable= S(false); const is_editable= S(false);
const onedited= on("change", ev=> { const onedited= on("change", ev=> {
const el= /** @type {HTMLInputElement} */ (ev.target); const el= /** @type {HTMLInputElement} */ (ev.target);
textContent(el.value); textContent.set(el.value);
is_editable(false); is_editable.set(false);
}); });
return el("li").append( return el("li").append(
S.el(is_editable, is=> is S.el(is_editable, is=> is
? el("input", { value: textContent(), type: "text" }, onedited) ? el("input", { value: textContent.get(), type: "text" }, onedited)
: el("span", { textContent, onclick: is_editable.bind(null, true) }) : el("span", { textContent, onclick: ()=> is_editable.set(true) })
), ),
el("button", { type: "button", value, textContent: "-" }, onclick) el("button", { type: "button", value, textContent: "-" }, onclick)
); );

View File

@ -34,7 +34,7 @@ export class CustomHTMLTestElement extends HTMLElement{
text(test), text(test),
text(name), text(name),
text(preName), text(preName),
el("button", { type: "button", textContent: "pre-name", onclick: ()=> preName("Ahoj") }), el("button", { type: "button", textContent: "pre-name", onclick: ()=> preName.set("Ahoj") }),
" | ", " | ",
el("slot", { className: "test", name: "test" }), el("slot", { className: "test", name: "test" }),
); );

View File

@ -20,7 +20,7 @@ document.body.append(
el("span", { textContent: "test", slot: "test" }), el("span", { textContent: "test", slot: "test" }),
), ),
el(thirdParty), el(thirdParty),
el(CustomSlottingHTMLElement.tagName, { onclick: ()=> toggle(!toggle()) }).append( el(CustomSlottingHTMLElement.tagName, { onclick: ()=> toggle.set(!toggle.get()) }).append(
el("strong", { slot: "name", textContent: "Honzo" }), el("strong", { slot: "name", textContent: "Honzo" }),
S.el(toggle, is=> is S.el(toggle, is=> is
? el("span", "…default slot") ? el("span", "…default slot")

94
index.d.ts vendored
View File

@ -1,5 +1,4 @@
declare global{ /* ddeSignal */ } import type { Signal as ddeSignal } from "./signals";
type CustomElementTagNameMap= { '#text': Text, '#comment': Comment } type CustomElementTagNameMap= { '#text': Text, '#comment': Comment }
type SupportedElement= type SupportedElement=
HTMLElementTagNameMap[keyof HTMLElementTagNameMap] HTMLElementTagNameMap[keyof HTMLElementTagNameMap]
@ -9,8 +8,8 @@ type SupportedElement=
declare global { declare global {
type ddeComponentAttributes= Record<any, any> | undefined; type ddeComponentAttributes= Record<any, any> | undefined;
type ddeElementAddon<El extends SupportedElement | DocumentFragment | Node>= (element: El)=> any; type ddeElementAddon<El extends SupportedElement | DocumentFragment | Node>= (element: El)=> any;
type ddeString= string | ddeSignal<string> type ddeString= string | ddeSignal<string, {}>
type ddeStringable= ddeString | number | ddeSignal<number> type ddeStringable= ddeString | number | ddeSignal<number, {}>
} }
type PascalCase= `${Capitalize<string>}${string}`; type PascalCase= `${Capitalize<string>}${string}`;
type AttrsModified= { type AttrsModified= {
@ -18,13 +17,13 @@ type AttrsModified= {
* Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API). * Use string like in HTML (internally uses `*.setAttribute("style", *)`), or object representation (like DOM API).
*/ */
style: Partial<CSSStyleDeclaration> | ddeString style: Partial<CSSStyleDeclaration> | ddeString
| Partial<{ [K in keyof CSSStyleDeclaration]: ddeSignal<CSSStyleDeclaration[K]> }> | Partial<{ [K in keyof CSSStyleDeclaration]: ddeSignal<CSSStyleDeclaration[K], {}> }>
/** /**
* Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1. * Provide option to add/remove/toggle CSS clasess (index of object) using 1/0/-1.
* In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))` * In fact `el.classList.toggle(class_name)` for `-1` and `el.classList.toggle(class_name, Boolean(...))`
* for others. * for others.
*/ */
classList: Record<string,-1|0|1|boolean|ddeSignal<-1|0|1|boolean>>, classList: Record<string,-1|0|1|boolean|ddeSignal<-1|0|1|boolean, {}>>,
/** /**
* Used by the dataset HTML attribute to represent data for custom attributes added to elements. * Used by the dataset HTML attribute to represent data for custom attributes added to elements.
* Values are converted to string (see {@link DOMStringMap}). * Values are converted to string (see {@link DOMStringMap}).
@ -52,9 +51,13 @@ type IsReadonly<T, K extends keyof T> =
* @private * @private
*/ */
type ElementAttributes<T extends SupportedElement>= Partial<{ type ElementAttributes<T extends SupportedElement>= Partial<{
[K in keyof _fromElsInterfaces<T>]: IsReadonly<_fromElsInterfaces<T>, K> extends false [K in keyof _fromElsInterfaces<T>]:
? _fromElsInterfaces<T>[K] | ddeSignal<_fromElsInterfaces<T>[K]> _fromElsInterfaces<T>[K] extends ((...p: any[])=> any)
: ddeStringable ? _fromElsInterfaces<T>[K] | ((...p: Parameters<_fromElsInterfaces<T>[K]>)=>
ddeSignal<ReturnType<_fromElsInterfaces<T>[K]>, {}>)
: (IsReadonly<_fromElsInterfaces<T>, K> extends false
? _fromElsInterfaces<T>[K] | ddeSignal<_fromElsInterfaces<T>[K], {}>
: ddeStringable)
} & AttrsModified> & Record<string, any>; } & AttrsModified> & Record<string, any>;
export function classListDeclarative<El extends SupportedElement>( export function classListDeclarative<El extends SupportedElement>(
element: El, element: El,
@ -68,6 +71,40 @@ export function assignAttribute<El extends SupportedElement, ATT extends keyof E
): ElementAttributes<El>[ATT] ): ElementAttributes<El>[ATT]
type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap; type ExtendedHTMLElementTagNameMap= HTMLElementTagNameMap & CustomElementTagNameMap;
export namespace el {
/**
* Creates a marker comment for elements
*
* @param attrs - Marker attributes
* @param [is_open=false] - Whether the marker is open-ended
* @returns Comment node marker
*/
export function mark(
attrs: { type: "component"|"reactive"|"later", name?: string, host?: "this"|"parentElement" },
is_open?: boolean
): Comment;
}
export function el<
A extends ddeComponentAttributes,
EL extends SupportedElement | ddeDocumentFragment
>(
component: (attr: A, ...rest: any[])=> EL,
attrs?: NoInfer<A>,
...addons: ddeElementAddon<EL>[]
): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap]
? EL
: ( EL extends ddeDocumentFragment ? EL : ddeHTMLElement )
export function el<
A extends { textContent: ddeStringable },
EL extends SupportedElement | ddeDocumentFragment
>(
component: (attr: A, ...rest: any[])=> EL,
attrs?: NoInfer<A>["textContent"],
...addons: ddeElementAddon<EL>[]
): EL extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap]
? EL
: ( EL extends ddeDocumentFragment ? EL : ddeHTMLElement )
export function el< export function el<
TAG extends keyof ExtendedHTMLElementTagNameMap, TAG extends keyof ExtendedHTMLElementTagNameMap,
>( >(
@ -85,16 +122,6 @@ export function el(
attrs?: ElementAttributes<HTMLElement> | ddeStringable, attrs?: ElementAttributes<HTMLElement> | ddeStringable,
...addons: ddeElementAddon<HTMLElement>[] ...addons: ddeElementAddon<HTMLElement>[]
): ddeHTMLElement ): ddeHTMLElement
export function el<
C extends (attr: ddeComponentAttributes)=> SupportedElement | ddeDocumentFragment
>(
component: C,
attrs?: Parameters<C>[0] | ddeStringable,
...addons: ddeElementAddon<ReturnType<C>>[]
): ReturnType<C> extends ddeHTMLElementTagNameMap[keyof ddeHTMLElementTagNameMap]
? ReturnType<C>
: ( ReturnType<C> extends ddeDocumentFragment ? ReturnType<C> : ddeHTMLElement )
export { el as createElement } export { el as createElement }
export function elNS( export function elNS(
@ -115,7 +142,7 @@ export function elNS(
>( >(
tag_name: TAG, tag_name: TAG,
attrs?: ddeStringable | Partial<{ attrs?: ddeStringable | Partial<{
[key in keyof EL]: EL[key] | ddeSignal<EL[key]> | string | number | boolean [key in keyof EL]: EL[key] | ddeSignal<EL[key], {}> | string | number | boolean
}>, }>,
...addons: ddeElementAddon<NoInfer<EL>>[] ...addons: ddeElementAddon<NoInfer<EL>>[]
)=> ddeMathMLElement )=> ddeMathMLElement
@ -143,6 +170,8 @@ export function simulateSlots<EL extends SupportedElement | DocumentFragment>(
body: EL, body: EL,
): EL ): EL
export function dispatchEvent(name: keyof DocumentEventMap | string, element: SupportedElement):
(data?: any)=> void;
export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit): export function dispatchEvent(name: keyof DocumentEventMap | string, options?: EventInit):
(element: SupportedElement, data?: any)=> void; (element: SupportedElement, data?: any)=> void;
export function dispatchEvent( export function dispatchEvent(
@ -216,7 +245,7 @@ export const scope: {
state: Scope[], state: Scope[],
/** Adds new child scope. All attributes are inherited by default. */ /** Adds new child scope. All attributes are inherited by default. */
push(scope: Partial<Scope>): ReturnType<Array<Scope>["push"]>, push(scope?: Partial<Scope>): ReturnType<Array<Scope>["push"]>,
/** Adds root scope as a child of the current scope. */ /** Adds root scope as a child of the current scope. */
pushRoot(): ReturnType<Array<Scope>["push"]>, pushRoot(): ReturnType<Array<Scope>["push"]>,
/** Removes last/current child scope. */ /** Removes last/current child scope. */
@ -225,7 +254,7 @@ export const scope: {
export function customElementRender< export function customElementRender<
EL extends HTMLElement, EL extends HTMLElement,
P extends any = Record<string, string | ddeSignal<string>> P extends any = Record<string, string | ddeSignal<string, {}>>
>( >(
target: ShadowRoot | EL, target: ShadowRoot | EL,
render: (props: P)=> SupportedElement | DocumentFragment, render: (props: P)=> SupportedElement | DocumentFragment,
@ -235,6 +264,27 @@ export function customElementWithDDE<EL extends (new ()=> HTMLElement)>(custom_e
export function lifecyclesToEvents<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL export function lifecyclesToEvents<EL extends (new ()=> HTMLElement)>(custom_element: EL): EL
export function observedAttributes(custom_element: HTMLElement): Record<string, string> export function observedAttributes(custom_element: HTMLElement): Record<string, string>
/**
* This is used primarly for server side rendering. To be sure that all async operations
* are finished before the page is sent to the client.
* ```
* // on component
* function component(){
*
* queue(fetch(...).then(...));
* }
*
* // building the page
* async function build(){
* const { component }= await import("./component.js");
* document.body.append(el(component));
* await queue();
* retutn document.body.innerHTML;
* }
* ```
* */
export function queue(promise?: Promise<unknown>): Promise<unknown>;
/* TypeScript MEH */ /* TypeScript MEH */
declare global{ declare global{
type ddeAppend<el>= (...nodes: (Node | string)[])=> el; type ddeAppend<el>= (...nodes: (Node | string)[])=> el;

View File

@ -17,7 +17,7 @@ env.setDeleteAttr= function(obj, prop, value){
if(value) return obj.setAttribute(prop, ""); if(value) return obj.setAttribute(prop, "");
obj.removeAttribute(prop); obj.removeAttribute(prop);
}; };
const keys= { H: "HTMLElement", S: "SVGElement", F: "DocumentFragment", M: "MutationObserver", D: "document" }; const keys= { H: "HTMLElement", S: "SVGElement", F: "DocumentFragment", D: "document" };
let env_bk= {}; let env_bk= {};
let dom_last; let dom_last;

1551
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "deka-dom-el", "name": "deka-dom-el",
"version": "0.8.0", "version": "0.9.0",
"description": "A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks.", "description": "A low-code library that simplifies the creation of native DOM elements/components using small wrappers and tweaks.",
"author": "Jan Andrle <andrle.jan@centrum.cz>", "author": "Jan Andrle <andrle.jan@centrum.cz>",
"license": "MIT", "license": "MIT",
@ -29,8 +29,8 @@
"types": "./jsdom.d.ts" "types": "./jsdom.d.ts"
}, },
"./src/signals-lib": { "./src/signals-lib": {
"import": "./src/signals-lib.js", "import": "./src/signals-lib/signals-lib.js",
"types": "./src/signals-lib.d.ts" "types": "./src/signals-lib/signals-lib.d.ts"
} }
}, },
"files": [ "files": [
@ -53,7 +53,8 @@
"globals": { "globals": {
"requestIdleCallback": false, "requestIdleCallback": false,
"AbortController": false, "AbortController": false,
"AbortSignal": false "AbortSignal": false,
"FinalizationRegistry": false
} }
}, },
"size-limit": [ "size-limit": [
@ -65,7 +66,7 @@
}, },
{ {
"path": "./signals.js", "path": "./signals.js",
"limit": "12 kB", "limit": "12.5 kB",
"gzip": false, "gzip": false,
"brotli": false "brotli": false
}, },
@ -77,7 +78,7 @@
}, },
{ {
"path": "./index-with-signals.js", "path": "./index-with-signals.js",
"limit": "5.25 kB" "limit": "5.5 kB"
} }
], ],
"modifyEsbuildConfig": { "modifyEsbuildConfig": {
@ -91,11 +92,11 @@
"typescript" "typescript"
], ],
"devDependencies": { "devDependencies": {
"@size-limit/preset-small-lib": "~11.0", "@size-limit/preset-small-lib": "~11.2",
"dts-bundler": "~0.1", "dts-bundle-generator": "~9.5",
"editorconfig-checker": "~6.0", "editorconfig-checker": "~6.0",
"esbuild": "~0.24", "esbuild": "~0.25",
"jsdom": "~25.0", "jsdom": "~26.0",
"jshint": "~2.13", "jshint": "~2.13",
"nodejsscript": "^1.0.2", "nodejsscript": "^1.0.2",
"size-limit-node-esbuild": "~0.3" "size-limit-node-esbuild": "~0.3"

12
signals.d.ts vendored
View File

@ -1,4 +1,12 @@
export type Signal<V, A>= (set?: V)=> V & A; export interface Signal<V, A> {
/** The current value of the signal */
get(): V;
/** Set new value of the signal */
set(value: V): V;
toJSON(): V;
valueOf(): V;
}
type Action<V>= (this: { value: V, stopPropagation(): void }, ...a: any[])=> typeof signal._ | void; type Action<V>= (this: { value: V, stopPropagation(): void }, ...a: any[])=> typeof signal._ | void;
//type SymbolSignal= Symbol; //type SymbolSignal= Symbol;
type SymbolOnclear= symbol; type SymbolOnclear= symbol;
@ -27,7 +35,7 @@ interface signal{
* ```js * ```js
* const name= S("Jan"); * const name= S("Jan");
* const surname= S("Andrle"); * const surname= S("Andrle");
* const fullname= S(()=> name()+" "+surname()); * const fullname= S(()=> name.get()+" "+surname.get());
* ``` * ```
* @param value Initial signal value. Or function computing value from other signals. * @param value Initial signal value. Or function computing value from other signals.
* @param actions Use to define actions on the signal. Such as add item to the array. * @param actions Use to define actions on the signal. Such as add item to the array.

View File

@ -1,4 +1,4 @@
export { signal, S, isSignal } from "./src/signals-lib.js"; export { signal, S, isSignal } from "./src/signals-lib/signals-lib.js";
import { signals_config } from "./src/signals-lib.js"; import { signals_config } from "./src/signals-lib/signals-lib.js";
import { registerReactivity } from "./src/signals-common.js"; import { registerReactivity } from "./src/signals-lib/common.js";
registerReactivity(signals_config); registerReactivity(signals_config);

View File

@ -1,6 +1,15 @@
import { keyLTE, evc, evd, eva } from "./dom-common.js"; import { keyLTE, evc, evd, eva } from "./dom-common.js";
import { scope } from "./dom.js"; import { scope } from "./dom.js";
import { c_ch_o } from "./events-observer.js"; import { c_ch_o } from "./events-observer.js";
/**
* Renders content into a custom element or shadow root
*
* @param {Element|ShadowRoot} target - The custom element or shadow root to render into
* @param {Function} render - The render function that returns content
* @param {Function|Object} [props=observedAttributes] - Props to pass to the render function
* @returns {Node} The rendered content
*/
export function customElementRender(target, render, props= observedAttributes){ export function customElementRender(target, render, props= observedAttributes){
const custom_element= target.host || target; const custom_element= target.host || target;
scope.push({ scope.push({
@ -17,6 +26,13 @@ export function customElementRender(target, render, props= observedAttributes){
scope.pop(); scope.pop();
return target.append(out); return target.append(out);
} }
/**
* Transforms custom element lifecycle callbacks into events
*
* @param {Function|Object} class_declaration - Custom element class or instance
* @returns {Function|Object} The modified class or instance
*/
export function lifecyclesToEvents(class_declaration){ export function lifecyclesToEvents(class_declaration){
wrapMethod(class_declaration.prototype, "connectedCallback", function(target, thisArg, detail){ wrapMethod(class_declaration.prototype, "connectedCallback", function(target, thisArg, detail){
target.apply(thisArg, detail); target.apply(thisArg, detail);
@ -38,12 +54,30 @@ export function lifecyclesToEvents(class_declaration){
class_declaration.prototype[keyLTE]= true; class_declaration.prototype[keyLTE]= true;
return class_declaration; return class_declaration;
} }
/** Public API */
export { lifecyclesToEvents as customElementWithDDE }; export { lifecyclesToEvents as customElementWithDDE };
/**
* Wraps a method with a proxy to intercept calls
*
* @param {Object} obj - Object containing the method
* @param {string} method - Method name to wrap
* @param {Function} apply - Function to execute when method is called
* @private
*/
function wrapMethod(obj, method, apply){ function wrapMethod(obj, method, apply){
obj[method]= new Proxy(obj[method] || (()=> {}), { apply }); obj[method]= new Proxy(obj[method] || (()=> {}), { apply });
} }
import { observedAttributes as oA } from "./helpers.js"; import { observedAttributes as oA } from "./helpers.js";
/**
* Gets observed attributes for a custom element
*
* @param {Element} instance - Custom element instance
* @returns {Object} Object mapping camelCase attribute names to their values
*/
export function observedAttributes(instance){ export function observedAttributes(instance){
return oA(instance, (i, n)=> i.getAttribute(n)); return oA(instance, (i, n)=> i.getAttribute(n));
} }

View File

@ -1,3 +1,15 @@
/**
* Environment configuration and globals for the library
* @typedef {Object} Environment
* @property {typeof setDeleteAttr} setDeleteAttr - Function to safely set or delete attributes
* @property {string} ssr - Server-side rendering flag
* @property {Document} D - Document global
* @property {typeof DocumentFragment} F - DocumentFragment constructor
* @property {typeof HTMLElement} H - HTMLElement constructor
* @property {typeof SVGElement} S - SVGElement constructor
* @property {typeof MutationObserver} M - MutationObserver constructor
* @property {Function} q - Promise wrapper for Promse queue feature
*/
export const enviroment= { export const enviroment= {
setDeleteAttr, setDeleteAttr,
ssr: "", ssr: "",
@ -8,26 +20,43 @@ export const enviroment= {
M: globalThis.MutationObserver, M: globalThis.MutationObserver,
q: p=> p || Promise.resolve(), q: p=> p || Promise.resolve(),
}; };
import { isUndef } from './helpers.js'; import { isInstance, isUndef } from './helpers.js';
/**
* Handles attribute setting with special undefined handling
*
* @param {Object} obj - The object to set the property on
* @param {string} prop - The property name
* @param {any} val - The value to set
* @returns {void}
*
* Issue:
* For some native attrs you can unset only to set empty string.
* This can be confusing as it is seen in inspector `<… id=""`.
* Options:
* 1. Leave it, as it is native behaviour
* 2. Sets as empty string and removes the corresponding attribute when also has empty string
* 3. (*) Sets as undefined and removes the corresponding attribute when "undefined" string discovered
* 4. Point 2. with checks for coincidence (e.g. use special string)
*/
function setDeleteAttr(obj, prop, val){ function setDeleteAttr(obj, prop, val){
/* Issue
For some native attrs you can unset only to set empty string.
This can be confusing as it is seen in inspector `<… id=""`.
Options:
1. Leave it, as it is native behaviour
2. Sets as empty string and removes the corresponding attribute when also has empty string
3. (*) Sets as undefined and removes the corresponding attribute when "undefined" string discovered
4. Point 2. with checks for coincidence (e.g. use special string)
*/
Reflect.set(obj, prop, val); Reflect.set(obj, prop, val);
if(!isUndef(val)) return; if(!isUndef(val)) return;
Reflect.deleteProperty(obj, prop); Reflect.deleteProperty(obj, prop);
if(obj instanceof enviroment.H && obj.getAttribute(prop)==="undefined") if(isInstance(obj, enviroment.H) && obj.getAttribute(prop)==="undefined")
return obj.removeAttribute(prop); return obj.removeAttribute(prop);
if(Reflect.get(obj, prop)==="undefined") if(Reflect.get(obj, prop)==="undefined")
return Reflect.set(obj, prop, ""); return Reflect.set(obj, prop, "");
} }
/** Property key for tracking lifecycle events */
export const keyLTE= "__dde_lifecyclesToEvents"; //boolean export const keyLTE= "__dde_lifecyclesToEvents"; //boolean
/** Event name for connected lifecycle event */
export const evc= "dde:connected"; export const evc= "dde:connected";
/** Event name for disconnected lifecycle event */
export const evd= "dde:disconnected"; export const evd= "dde:disconnected";
/** Event name for attribute changed lifecycle event */
export const eva= "dde:attributeChanged"; export const eva= "dde:attributeChanged";

View File

@ -1,38 +1,104 @@
import { signals } from "./signals-common.js"; import { signals } from "./signals-lib/common.js";
import { enviroment as env } from './dom-common.js'; import { enviroment as env } from './dom-common.js';
import { isInstance, isUndef, oAssign } from "./helpers.js";
//TODO: add type, docs ≡ make it public /**
* Queues a promise, this is helpful for crossplatform components (on server side we can wait for all registered
* promises to be resolved before rendering).
* @param {Promise} promise - Promise to process
* @returns {Promise} Processed promise
*/
export function queue(promise){ return env.q(promise); } export function queue(promise){ return env.q(promise); }
/** @type {{ scope: object, prevent: boolean, host: function }[]} */
/**
* Array of scope contexts for tracking component hierarchies
* @type {{ scope: object, prevent: boolean, host: function }[]}
*/
const scopes= [ { const scopes= [ {
get scope(){ return env.D.body; }, get scope(){ return env.D.body; },
host: c=> c ? c(env.D.body) : env.D.body, host: c=> c ? c(env.D.body) : env.D.body,
prevent: true, prevent: true,
} ]; } ];
/**
* Scope management utility for tracking component hierarchies
*/
export const scope= { export const scope= {
/**
* Gets the current scope
* @returns {Object} Current scope context
*/
get current(){ return scopes[scopes.length-1]; }, get current(){ return scopes[scopes.length-1]; },
/**
* Gets the host element of the current scope
* @returns {Function} Host accessor function
*/
get host(){ return this.current.host; }, get host(){ return this.current.host; },
/**
* Prevents default behavior in the current scope
* @returns {Object} Current scope context
*/
preventDefault(){ preventDefault(){
const { current }= this; const { current }= this;
current.prevent= true; current.prevent= true;
return current; return current;
}, },
/**
* Gets a copy of the current scope stack
* @returns {Array} Copy of scope stack
*/
get state(){ return [ ...scopes ]; }, get state(){ return [ ...scopes ]; },
push(s= {}){ return scopes.push(Object.assign({}, this.current, { prevent: false }, s)); },
/**
* Pushes a new scope to the stack
* @param {Object} [s={}] - Scope object to push
* @returns {number} New length of the scope stack
*/
push(s= {}){ return scopes.push(oAssign({}, this.current, { prevent: false }, s)); },
/**
* Pushes the root scope to the stack
* @returns {number} New length of the scope stack
*/
pushRoot(){ return scopes.push(scopes[0]); }, pushRoot(){ return scopes.push(scopes[0]); },
/**
* Pops the current scope from the stack
* @returns {Object|undefined} Popped scope or undefined if only one scope remains
*/
pop(){ pop(){
if(scopes.length===1) return; if(scopes.length===1) return;
return scopes.pop(); return scopes.pop();
}, },
}; };
//NOTE: following chainableAppend implementation is OK as the ElementPrototype.append description already is { writable: true, enumerable: true, configurable: true } // editorconfig-checker-disable-line /**
* Chainable append function for elements
* @private
*/
function append(...els){ this.appendOriginal(...els); return this; } function append(...els){ this.appendOriginal(...els); return this; }
/**
* Makes an element's append method chainable. NOTE: following chainableAppend implementation is OK as the
* ElementPrototype.append description already is { writable: true, enumerable: true, configurable: true }
* @param {Element} el - Element to modify
* @returns {Element} Modified element
*/
export function chainableAppend(el){ export function chainableAppend(el){
if(el.append===append) return el; el.appendOriginal= el.append; el.append= append; return el; if(el.append===append) return el; el.appendOriginal= el.append; el.append= append; return el;
} }
/** Current namespace for element creation */
let namespace; let namespace;
/**
* Creates a DOM element with specified tag, attributes and addons
*
* @param {string|Function} tag - Element tag name or component function
* @param {Object|string|number} [attributes] - Element attributes
* @param {...Function} addons - Functions to call with the created element
* @returns {Element|DocumentFragment} Created element
*/
export function createElement(tag, attributes, ...addons){ export function createElement(tag, attributes, ...addons){
/* jshint maxcomplexity: 15 */ /* jshint maxcomplexity: 15 */
const s= signals(this); const s= signals(this);
@ -47,7 +113,7 @@ export function createElement(tag, attributes, ...addons){
(scoped===1 ? addons.unshift(...c) : c.forEach(c=> c(el_host)), undefined); (scoped===1 ? addons.unshift(...c) : c.forEach(c=> c(el_host)), undefined);
scope.push({ scope: tag, host }); scope.push({ scope: tag, host });
el= tag(attributes || undefined); el= tag(attributes || undefined);
const is_fragment= el instanceof env.F; const is_fragment= isInstance(el, env.F);
if(el.nodeName==="#comment") break; if(el.nodeName==="#comment") break;
const el_mark= createElement.mark({ const el_mark= createElement.mark({
type: "component", type: "component",
@ -70,10 +136,15 @@ export function createElement(tag, attributes, ...addons){
scoped= 2; scoped= 2;
return el; return el;
} }
/** /**
* @param { { type: "component", name: string, host: "this" | "parentElement" } | { type: "reactive" | "later" } } attrs * Creates a marker comment for elements
* @param {boolean} [is_open=false] *
* */ * @param {{ type: "component"|"reactive"|"later", name?: string, host?: "this"|"parentElement" }} attrs - Marker
* attributes
* @param {boolean} [is_open=false] - Whether the marker is open-ended
* @returns {Comment} Comment node marker
*/
createElement.mark= function(attrs, is_open= false){ createElement.mark= function(attrs, is_open= false){
attrs= Object.entries(attrs).map(([ n, v ])=> n+`="${v}"`).join(" "); attrs= Object.entries(attrs).map(([ n, v ])=> n+`="${v}"`).join(" ");
const end= is_open ? "" : "/"; const end= is_open ? "" : "/";
@ -81,8 +152,16 @@ createElement.mark= function(attrs, is_open= false){
if(is_open) out.end= env.D.createComment("</dde:mark>"); if(is_open) out.end= env.D.createComment("</dde:mark>");
return out; return out;
}; };
/** Alias for createElement */
export { createElement as el }; export { createElement as el };
//TODO?: const namespaceHelper= ns=> ns==="svg" ? "http://www.w3.org/2000/svg" : ns; //TODO?: const namespaceHelper= ns=> ns==="svg" ? "http://www.w3.org/2000/svg" : ns;
/**
* Creates a namespaced element creation function
*
* @param {string} ns - Namespace URI
* @returns {Function} Element creation function for the namespace
*/
export function createElementNS(ns){ export function createElementNS(ns){
const _this= this; const _this= this;
return function createElementNSCurried(...rest){ return function createElementNSCurried(...rest){
@ -92,9 +171,17 @@ export function createElementNS(ns){
return el; return el;
}; };
} }
/** Alias for createElementNS */
export { createElementNS as elNS }; export { createElementNS as elNS };
/** @param {HTMLElement} element @param {HTMLElement} [root] */ /**
* Simulates slot functionality for elements
*
* @param {HTMLElement} element - Parent element
* @param {HTMLElement} [root=element] - Root element containing slots
* @returns {HTMLElement} The root element
*/
export function simulateSlots(element, root= element){ export function simulateSlots(element, root= element){
const mark_e= "¹⁰", mark_s= "✓"; //NOTE: Markers to identify slots processed by this function. Also “prevents” native behavior as it is unlikely to use these in names. // editorconfig-checker-disable-line const mark_e= "¹⁰", mark_s= "✓"; //NOTE: Markers to identify slots processed by this function. Also “prevents” native behavior as it is unlikely to use these in names. // editorconfig-checker-disable-line
const slots= Object.fromEntries( const slots= Object.fromEntries(
@ -128,17 +215,34 @@ export function simulateSlots(element, root= element){
return root; return root;
} }
/** Store for element assignment contexts */
const assign_context= new WeakMap(); const assign_context= new WeakMap();
const { setDeleteAttr }= env; const { setDeleteAttr }= env;
/**
* Assigns attributes to an element
*
* @param {Element} element - Element to assign attributes to
* @param {...Object} attributes - Attribute objects to assign
* @returns {Element} The element with attributes assigned
*/
export function assign(element, ...attributes){ export function assign(element, ...attributes){
if(!attributes.length) return element; if(!attributes.length) return element;
assign_context.set(element, assignContext(element, this)); assign_context.set(element, assignContext(element, this));
for(const [ key, value ] of Object.entries(Object.assign({}, ...attributes))) for(const [ key, value ] of Object.entries(oAssign({}, ...attributes)))
assignAttribute.call(this, element, key, value); assignAttribute.call(this, element, key, value);
assign_context.delete(element); assign_context.delete(element);
return element; return element;
} }
/**
* Assigns a single attribute to an element
*
* @param {Element} element - Element to assign attribute to
* @param {string} key - Attribute name
* @param {any} value - Attribute value
* @returns {any} Result of the attribute assignment
*/
export function assignAttribute(element, key, value){ export function assignAttribute(element, key, value){
const { setRemoveAttr, s }= assignContext(element, this); const { setRemoveAttr, s }= assignContext(element, this);
const _this= this; const _this= this;
@ -170,13 +274,28 @@ export function assignAttribute(element, key, value){
} }
return isPropSetter(element, key) ? setDeleteAttr(element, key, value) : setRemoveAttr(key, value); return isPropSetter(element, key) ? setDeleteAttr(element, key, value) : setRemoveAttr(key, value);
} }
/**
* Gets or creates assignment context for an element
*
* @param {Element} element - Element to get context for
* @param {Object} _this - Context object
* @returns {Object} Assignment context
* @private
*/
function assignContext(element, _this){ function assignContext(element, _this){
if(assign_context.has(element)) return assign_context.get(element); if(assign_context.has(element)) return assign_context.get(element);
const is_svg= element instanceof env.S; const is_svg= isInstance(element, env.S);
const setRemoveAttr= (is_svg ? setRemoveNS : setRemove).bind(null, element, "Attribute"); const setRemoveAttr= (is_svg ? setRemoveNS : setRemove).bind(null, element, "Attribute");
const s= signals(_this); const s= signals(_this);
return { setRemoveAttr, s }; return { setRemoveAttr, s };
} }
/**
* Applies a declarative classList object to an element
*
* @param {Element} element - Element to apply classes to
* @param {Object} toggle - Object with class names as keys and boolean values
* @returns {Element} The element with classes applied
*/
export function classListDeclarative(element, toggle){ export function classListDeclarative(element, toggle){
const s= signals(this); const s= signals(this);
forEachEntries(s, "classList", element, toggle, forEachEntries(s, "classList", element, toggle,
@ -184,18 +303,45 @@ export function classListDeclarative(element, toggle){
element.classList.toggle(class_name, val===-1 ? undefined : Boolean(val)) ); element.classList.toggle(class_name, val===-1 ? undefined : Boolean(val)) );
return element; return element;
} }
/**
* Generic element attribute manipulation
*
* @param {Element} element - Element to manipulate
* @param {string} op - Operation ("set" or "remove")
* @param {string} key - Attribute name
* @param {any} [value] - Attribute value
* @returns {void}
*/
export function elementAttribute(element, op, key, value){ export function elementAttribute(element, op, key, value){
if(element instanceof env.H) if(isInstance(element, env.H))
return element[op+"Attribute"](key, value); return element[op+"Attribute"](key, value);
return element[op+"AttributeNS"](null, key, value); return element[op+"AttributeNS"](null, key, value);
} }
import { isUndef } from "./helpers.js";
//TODO: add cache? `(Map/Set)<el.tagName+key,isUndef>` //TODO: add cache? `(Map/Set)<el.tagName+key,isUndef>`
/**
* Checks if a property can be set on an element
*
* @param {Element} el - Element to check
* @param {string} key - Property name
* @returns {boolean} Whether the property can be set
* @private
*/
function isPropSetter(el, key){ function isPropSetter(el, key){
if(!(key in el)) return false; if(!(key in el)) return false;
const des= getPropDescriptor(el, key); const des= getPropDescriptor(el, key);
return !isUndef(des.set); return !isUndef(des.set);
} }
/**
* Gets a property descriptor from a prototype chain
*
* @param {Object} p - Prototype object
* @param {string} key - Property name
* @returns {PropertyDescriptor} Property descriptor
* @private
*/
function getPropDescriptor(p, key){ function getPropDescriptor(p, key){
p= Object.getPrototypeOf(p); p= Object.getPrototypeOf(p);
if(!p) return {}; if(!p) return {};
@ -224,9 +370,44 @@ function forEachEntries(s, target, element, obj, cb){
}); });
} }
/**
* Sets or removes an attribute based on value
*
* @param {Element} obj - Element to modify
* @param {string} prop - Property suffix ("Attribute")
* @param {string} key - Attribute name
* @param {any} val - Attribute value
* @returns {void}
* @private
*/
function setRemove(obj, prop, key, val){ function setRemove(obj, prop, key, val){
return obj[ (isUndef(val) ? "remove" : "set") + prop ](key, val); } return obj[ (isUndef(val) ? "remove" : "set") + prop ](key, val);
}
/**
* Sets or removes a namespaced attribute based on value
*
* @param {Element} obj - Element to modify
* @param {string} prop - Property suffix ("Attribute")
* @param {string} key - Attribute name
* @param {any} val - Attribute value
* @param {string|null} [ns=null] - Namespace URI
* @returns {void}
* @private
*/
function setRemoveNS(obj, prop, key, val, ns= null){ function setRemoveNS(obj, prop, key, val, ns= null){
return obj[ (isUndef(val) ? "remove" : "set") + prop + "NS" ](ns, key, val); } return obj[ (isUndef(val) ? "remove" : "set") + prop + "NS" ](ns, key, val);
}
/**
* Sets or deletes a property based on value
*
* @param {Object} obj - Object to modify
* @param {string} key - Property name
* @param {any} val - Property value
* @returns {void}
* @private
*/
function setDelete(obj, key, val){ function setDelete(obj, key, val){
Reflect.set(obj, key, val); if(!isUndef(val)) return; return Reflect.deleteProperty(obj, key); } Reflect.set(obj, key, val); if(!isUndef(val)) return; return Reflect.deleteProperty(obj, key);
}

Some files were not shown because too many files have changed in this diff Show More