elegance-js 2.1.23 → 2.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/client/effect.d.ts +27 -0
  2. package/dist/client/effect.js +37 -0
  3. package/dist/client/eventListener.d.ts +39 -0
  4. package/dist/client/eventListener.js +52 -0
  5. package/dist/client/loadHook.d.ts +34 -0
  6. package/dist/client/loadHook.js +52 -0
  7. package/dist/client/observer.d.ts +36 -0
  8. package/dist/client/observer.js +66 -0
  9. package/dist/client/runtime.d.ts +105 -0
  10. package/dist/client/runtime.js +620 -0
  11. package/dist/client/state.d.ts +40 -0
  12. package/dist/client/state.js +110 -0
  13. package/dist/compilation/compiler.d.ts +155 -0
  14. package/dist/compilation/compiler.js +1153 -0
  15. package/dist/components/ClientComponent.d.ts +22 -0
  16. package/dist/components/ClientComponent.js +55 -0
  17. package/dist/components/Link.d.ts +16 -1
  18. package/dist/components/Link.js +22 -0
  19. package/dist/components/Portal.d.ts +2 -0
  20. package/dist/components/Portal.js +2 -0
  21. package/dist/elements/element.d.ts +87 -0
  22. package/dist/elements/element.js +33 -0
  23. package/dist/elements/element_list.d.ts +7 -0
  24. package/dist/elements/element_list.js +65 -0
  25. package/dist/elements/raw.d.ts +14 -0
  26. package/dist/elements/raw.js +78 -0
  27. package/dist/elements/specific_props.d.ts +750 -0
  28. package/dist/global.d.ts +221 -327
  29. package/dist/index.d.ts +15 -3
  30. package/dist/index.js +11 -0
  31. package/dist/server/layout.d.ts +34 -3
  32. package/dist/server/layout.js +6 -0
  33. package/dist/server/log.d.ts +12 -0
  34. package/dist/server/log.js +64 -0
  35. package/dist/server/page.d.ts +32 -0
  36. package/dist/server/page.js +6 -0
  37. package/dist/server/runtime.d.ts +6 -0
  38. package/dist/server/runtime.js +72 -0
  39. package/dist/server/server.d.ts +103 -11
  40. package/dist/server/server.js +709 -0
  41. package/package.json +13 -13
  42. package/scripts/bootstrap.js +37 -273
  43. package/scripts/bootstrap_files/elegance.txt +40 -0
  44. package/scripts/bootstrap_files/index.txt +3 -0
  45. package/scripts/bootstrap_files/layout.txt +46 -0
  46. package/scripts/bootstrap_files/middleware.txt +18 -0
  47. package/scripts/bootstrap_files/page.txt +123 -0
  48. package/scripts/bootstrap_files/route.txt +6 -0
  49. package/scripts/elegance_dev.ts +40 -0
  50. package/scripts/elegance_prod.ts +40 -0
  51. package/scripts/elegance_static.ts +24 -0
  52. package/scripts/prod.js +9 -26
  53. package/scripts/run.js +13 -0
  54. package/scripts/static.js +13 -0
  55. package/dist/build.d.ts +0 -2
  56. package/dist/build.mjs +0 -202
  57. package/dist/client/client.d.ts +0 -1
  58. package/dist/client/client.mjs +0 -574
  59. package/dist/client/processPageElements.d.ts +0 -1
  60. package/dist/client/processPageElements.mjs +0 -117
  61. package/dist/client/render.d.ts +0 -1
  62. package/dist/client/render.mjs +0 -40
  63. package/dist/client/watcher.d.ts +0 -1
  64. package/dist/client/watcher.mjs +0 -26
  65. package/dist/compilation/compilation.d.ts +0 -139
  66. package/dist/compilation/compilation.mjs +0 -751
  67. package/dist/compilation/compiler_process.d.ts +0 -3
  68. package/dist/compilation/compiler_process.mjs +0 -102
  69. package/dist/compilation/dynamic_compiler.d.ts +0 -10
  70. package/dist/compilation/dynamic_compiler.mjs +0 -93
  71. package/dist/compile_docs.mjs +0 -34
  72. package/dist/components/Link.mjs +0 -65
  73. package/dist/global.mjs +0 -0
  74. package/dist/helpers/ObjectAttributeType.d.ts +0 -7
  75. package/dist/helpers/ObjectAttributeType.mjs +0 -11
  76. package/dist/helpers/camelToKebab.d.ts +0 -1
  77. package/dist/helpers/camelToKebab.mjs +0 -6
  78. package/dist/index.mjs +0 -3
  79. package/dist/internal/deprecate.d.ts +0 -1
  80. package/dist/internal/deprecate.mjs +0 -7
  81. package/dist/log.d.ts +0 -10
  82. package/dist/log.mjs +0 -38
  83. package/dist/server/generateHTMLTemplate.d.ts +0 -12
  84. package/dist/server/generateHTMLTemplate.mjs +0 -41
  85. package/dist/server/layout.mjs +0 -19
  86. package/dist/server/loadHook.d.ts +0 -30
  87. package/dist/server/loadHook.mjs +0 -50
  88. package/dist/server/observe.d.ts +0 -19
  89. package/dist/server/observe.mjs +0 -16
  90. package/dist/server/render.d.ts +0 -5
  91. package/dist/server/render.mjs +0 -61
  92. package/dist/server/server.mjs +0 -429
  93. package/dist/server/state.d.ts +0 -61
  94. package/dist/server/state.mjs +0 -146
  95. package/dist/shared/bindServerElements.mjs +0 -3
  96. package/dist/shared/serverElements.d.ts +0 -11
  97. package/dist/shared/serverElements.mjs +0 -164
  98. package/scripts/dev.js +0 -33
  99. package/scripts/export.js +0 -20
  100. package/scripts/ts-arc-dev.js +0 -9
  101. package/scripts/ts-arc-prod.js +0 -9
  102. /package/dist/{compile_docs.d.ts → elements/specific_props.js} +0 -0
  103. /package/dist/{shared/bindServerElements.d.ts → global.js} +0 -0
@@ -0,0 +1,22 @@
1
+ import { ClientSubject } from "../client/runtime";
2
+ import { ServerSubject } from "../client/state";
3
+ import { EleganceElement } from "../elements/element";
4
+ type ClientComponentCallback<D extends readonly ServerSubject<unknown>[]> = (...dependencies: {
5
+ [K in keyof D]: ClientSubject<D[K]["value"]>;
6
+ }) => EleganceElement<any, any>;
7
+ /**
8
+ * Create a component that will be client-side rendered.
9
+ *
10
+ * You should really only use this for specific things, not as a top-level component.
11
+ * Server-side rendering is not only faster and more efficient, but also gives your components access to more things.
12
+ *
13
+ * This component exists for specific scenarios, such as if you have client-side data fetching that you need to show react-style "suspense" components for.
14
+ *
15
+ * **IMPORTANT** `callback` is sent literally as-is to the browser, and thus has no context of server-side variables, and is untrusted.
16
+ *
17
+ * @param callback The component to send to the browser.
18
+ * @param dependencies Any subjects that the component needs access to.
19
+ * @returns An HTML element to track the position of the Client Component.
20
+ */
21
+ declare function ClientComponent<const T extends readonly ServerSubject<unknown>[]>(callback: ClientComponentCallback<T>, dependencies: [...T]): EleganceElement<any, true>;
22
+ export { ClientComponent };
@@ -0,0 +1,55 @@
1
+ import { loadHook } from "../client/loadHook.js";
2
+ import { state } from "../client/state.js";
3
+ import { compilerStore } from "../compilation/compiler.js";
4
+ /**
5
+ * Create a component that will be client-side rendered.
6
+ *
7
+ * You should really only use this for specific things, not as a top-level component.
8
+ * Server-side rendering is not only faster and more efficient, but also gives your components access to more things.
9
+ *
10
+ * This component exists for specific scenarios, such as if you have client-side data fetching that you need to show react-style "suspense" components for.
11
+ *
12
+ * **IMPORTANT** `callback` is sent literally as-is to the browser, and thus has no context of server-side variables, and is untrusted.
13
+ *
14
+ * @param callback The component to send to the browser.
15
+ * @param dependencies Any subjects that the component needs access to.
16
+ * @returns An HTML element to track the position of the Client Component.
17
+ */
18
+ function ClientComponent(callback, dependencies) {
19
+ const callbackState = state(callback);
20
+ const store = compilerStore.getStore();
21
+ if (!store) {
22
+ throw new Error("ClientComponent() can only be invoked during the compilation of a page or layout.");
23
+ }
24
+ const componentId = state(store.generateId());
25
+ loadHook((componentId, callback, ...dependencies) => {
26
+ let node;
27
+ function update() {
28
+ node?.remove();
29
+ const element = callback.value(...dependencies);
30
+ const HTMLElement = eleganceClient.createHTMLElementFromElement(element);
31
+ node = HTMLElement.root;
32
+ const trackedElement = document.querySelector(`template[component-id="${componentId.value}"]`);
33
+ if (!trackedElement)
34
+ return;
35
+ trackedElement.parentElement.insertBefore(HTMLElement.root, trackedElement);
36
+ }
37
+ const observers = [];
38
+ for (const dep of dependencies) {
39
+ const id = `${Math.random() * 1000 + Date.now()}`;
40
+ dep.observe(id, update);
41
+ observers.push({ subject: dep, id, });
42
+ }
43
+ update();
44
+ return () => {
45
+ node?.remove();
46
+ for (const observer of observers) {
47
+ observer.subject.unobserve(observer.id);
48
+ }
49
+ };
50
+ }, [componentId, callbackState, ...dependencies]);
51
+ return template({
52
+ "component-id": componentId.value,
53
+ });
54
+ }
55
+ export { ClientComponent };
@@ -1 +1,16 @@
1
- export declare const Link: (options: Record<string, any>, ...children: Child[]) => BuiltElement<"a">;
1
+ import { AnyElement, ElementOptionsOrChild, SpecialElementOption } from "../elements/element";
2
+ /**
3
+ * Create a custom anchor element that let's you hook into client-side navigation.
4
+ * If provided a URL that is non-local, it will default to normal navigation.
5
+ * @param options Standard element optins, must include href for the link to work properly.
6
+ * @param children Standard element children.
7
+ * @returns A custom anchor element.
8
+ */
9
+ type ExtraOptions = {
10
+ /** Mandatory, where this Link should take the user to. */
11
+ href: string | SpecialElementOption;
12
+ /** Set window.scrollTop to 0 whenever this link navigates. */
13
+ resetScrollOnNav?: boolean;
14
+ };
15
+ declare function Link(options: ElementOptionsOrChild<"a", ExtraOptions>, ...children: AnyElement[]): import("..").EleganceElement<"a", true>;
16
+ export { Link, };
@@ -0,0 +1,22 @@
1
+ import { eventListener } from "../client/eventListener.js";
2
+ import { isAnElement } from "../elements/element.js";
3
+ function Link(options, ...children) {
4
+ const handler = eventListener((event) => {
5
+ const targetUrl = new URL(event.currentTarget.href, window.location.href);
6
+ const currentUrl = new URL(window.location.href);
7
+ const isSameHost = targetUrl.hostname === currentUrl.hostname &&
8
+ targetUrl.port === currentUrl.port;
9
+ if (!isSameHost) {
10
+ return;
11
+ }
12
+ event.preventDefault();
13
+ eleganceClient.navigateLocally(targetUrl.pathname + targetUrl.search + targetUrl.hash, true);
14
+ }, []);
15
+ const extraOptions = options && typeof options === "object" ? options : {};
16
+ const firstChild = isAnElement(options) ? options : undefined;
17
+ return a({
18
+ onClick: handler,
19
+ ...extraOptions,
20
+ }, ...(firstChild ? [firstChild, ...children] : children));
21
+ }
22
+ export { Link, };
@@ -0,0 +1,2 @@
1
+ import { AnyElement } from "../elements/element";
2
+ export declare function Portal(element: AnyElement): void;
@@ -0,0 +1,2 @@
1
+ export function Portal(element) {
2
+ }
@@ -0,0 +1,87 @@
1
+ import type { EventListenerOption } from "../client/eventListener";
2
+ import type { ServerSubject } from "../client/state";
3
+ import type { SpecificPropsMap } from "./specific_props";
4
+ /** Any valid element that has not been constructed via the use of an element constructor such as h1() */
5
+ type ElementLiteral = boolean | number | string | Array<any> | null | undefined | void;
6
+ type AnyElement = EleganceElement<any, any> | ElementLiteral | ServerSubject<any>;
7
+ type ElementChildren = AnyElement[];
8
+ /** Helper to make SpecialElementOption usable on any prop value while preserving original type enforcement */
9
+ export type MaybeSpecial<T> = T | SpecialElementOption;
10
+ /**
11
+ * An option that should be treated differently by the compiler.
12
+ */
13
+ declare abstract class SpecialElementOption {
14
+ /**
15
+ * Mutate this option in the element to it's serializeable state.
16
+ */
17
+ abstract mutate(element: EleganceElement<any, any>, optionName: string): void;
18
+ /**
19
+ * Convert this special element option into a string.
20
+ */
21
+ abstract serialize(optionName: string, elementKey: string): string;
22
+ }
23
+ type CommonElementProps = {
24
+ "map-id"?: string;
25
+ "component-id"?: string;
26
+ "key"?: string;
27
+ className?: MaybeSpecial<string>;
28
+ style?: MaybeSpecial<Record<string, string | number>>;
29
+ innerHTML?: MaybeSpecial<string>;
30
+ innerText?: MaybeSpecial<string>;
31
+ id?: MaybeSpecial<string>;
32
+ title?: MaybeSpecial<string>;
33
+ lang?: MaybeSpecial<string>;
34
+ dir?: MaybeSpecial<"ltr" | "rtl" | "auto">;
35
+ tabIndex?: MaybeSpecial<number>;
36
+ role?: MaybeSpecial<string>;
37
+ draggable?: MaybeSpecial<boolean>;
38
+ hidden?: MaybeSpecial<boolean>;
39
+ onClick?: MaybeSpecial<EventListenerOption>;
40
+ onDoubleClick?: MaybeSpecial<EventListenerOption>;
41
+ onContextMenu?: MaybeSpecial<EventListenerOption>;
42
+ onMouseDown?: MaybeSpecial<EventListenerOption>;
43
+ onMouseUp?: MaybeSpecial<EventListenerOption>;
44
+ onMouseEnter?: MaybeSpecial<EventListenerOption>;
45
+ onMouseLeave?: MaybeSpecial<EventListenerOption>;
46
+ onMouseMove?: MaybeSpecial<EventListenerOption>;
47
+ onMouseOver?: MaybeSpecial<EventListenerOption>;
48
+ onMouseOut?: MaybeSpecial<EventListenerOption>;
49
+ onWheel?: MaybeSpecial<EventListenerOption>;
50
+ onKeyDown?: MaybeSpecial<EventListenerOption>;
51
+ onKeyUp?: MaybeSpecial<EventListenerOption>;
52
+ onKeyPress?: MaybeSpecial<EventListenerOption>;
53
+ onFocus?: MaybeSpecial<EventListenerOption>;
54
+ onBlur?: MaybeSpecial<EventListenerOption>;
55
+ onFocusIn?: MaybeSpecial<EventListenerOption>;
56
+ onFocusOut?: MaybeSpecial<EventListenerOption>;
57
+ onChange?: MaybeSpecial<EventListenerOption>;
58
+ onInput?: MaybeSpecial<EventListenerOption>;
59
+ onSubmit?: MaybeSpecial<EventListenerOption>;
60
+ onInvalid?: MaybeSpecial<EventListenerOption>;
61
+ onReset?: MaybeSpecial<EventListenerOption>;
62
+ onScroll?: MaybeSpecial<EventListenerOption>;
63
+ [key: `aria-${string}`]: MaybeSpecial<string | number | boolean | null | undefined>;
64
+ [key: `data-${string}`]: MaybeSpecial<string | number | boolean | null | undefined>;
65
+ };
66
+ type SpecificProps<Tag extends AllElementTags> = Tag extends keyof SpecificPropsMap ? SpecificPropsMap[Tag] : {};
67
+ type ElementOptions<Tag extends AllElementTags, ExtraOptions extends object = {}> = CommonElementProps & SpecificProps<Tag> & ExtraOptions;
68
+ type ElementOptionsOrChild<Tag extends AllElementTags, ExtraOptions extends object = {}> = ElementOptions<Tag, ExtraOptions> | AnyElement;
69
+ type HtmlChildrenlessElementTags = "area" | "base" | "br" | "col" | "embed" | "hr" | "img" | "input" | "link" | "meta" | "param" | "source" | "track" | "wbr";
70
+ type HtmlElementTags = "a" | "abbr" | "address" | "article" | "aside" | "audio" | "b" | "bdi" | "bdo" | "blockquote" | "body" | "button" | "canvas" | "caption" | "cite" | "code" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "dialog" | "div" | "dl" | "dt" | "em" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "html" | "i" | "iframe" | "ins" | "kbd" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menu" | "meter" | "nav" | "noscript" | "object" | "ol" | "optgroup" | "option" | "output" | "p" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "search" | "section" | "select" | "slot" | "small" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "template" | "textarea" | "tfoot" | "th" | "thead" | "time" | "title" | "tr" | "u" | "ul" | "varElement" | "video";
71
+ type SvgChildrenlessElementTags = "path" | "circle" | "ellipse" | "line" | "polygon" | "polyline" | "stop";
72
+ type SvgElementTags = "svg" | "g" | "text" | "tspan" | "textPath" | "defs" | "symbol" | "use" | "image" | "clipPath" | "mask" | "pattern" | "linearGradient" | "radialGradient" | "filter" | "marker" | "view" | "feBlend" | "feColorMatrix" | "feComponentTransfer" | "feComposite" | "feConvolveMatrix" | "feDiffuseLighting" | "feDisplacementMap" | "feDistantLight" | "feFlood" | "feFuncA" | "feFuncB" | "feFuncG" | "feFuncR" | "feGaussianBlur" | "feImage" | "feMerge" | "feMergeNode" | "feMorphology" | "feOffset" | "fePointLight" | "feSpecularLighting" | "feSpotLight" | "feTile" | "feTurbulence";
73
+ type MathMLChildrenlessElementTags = "mi" | "mn" | "mo";
74
+ type MathMLElementTags = "math" | "ms" | "mtext" | "mrow" | "mfenced" | "msup" | "msub" | "msubsup" | "mfrac" | "msqrt" | "mroot" | "mtable" | "mtr" | "mtd" | "mstyle" | "menclose" | "mmultiscripts";
75
+ type AllElementTags = HtmlChildrenlessElementTags | HtmlElementTags | SvgChildrenlessElementTags | SvgElementTags | MathMLChildrenlessElementTags | MathMLElementTags;
76
+ type EleganceElementBuilder<Tag extends AllElementTags> = Tag extends HtmlChildrenlessElementTags | SvgChildrenlessElementTags | MathMLChildrenlessElementTags ? (options?: ElementOptions<Tag>) => EleganceElement<Tag, false> : (options?: ElementOptionsOrChild<Tag>, ...children: ElementChildren) => EleganceElement<Tag, true>;
77
+ declare function isAnElement(value: any): value is AnyElement;
78
+ declare class EleganceElement<Tag extends AllElementTags, CanHaveChildren extends boolean> {
79
+ readonly tag: Tag;
80
+ readonly options: ElementOptions<Tag>;
81
+ key?: string;
82
+ children: CanHaveChildren extends true ? ElementChildren : null;
83
+ constructor(tag: Tag, options?: ElementOptionsOrChild<Tag>, children?: ElementChildren | null);
84
+ canHaveChildren(): this is EleganceElement<Tag, true>;
85
+ }
86
+ export { EleganceElement, SpecialElementOption, isAnElement, };
87
+ export type { EleganceElementBuilder, AnyElement, ElementChildren, AllElementTags, HtmlElementTags, HtmlChildrenlessElementTags, SvgElementTags, SvgChildrenlessElementTags, MathMLElementTags, MathMLChildrenlessElementTags, ElementOptions, ElementOptionsOrChild, };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * An option that should be treated differently by the compiler.
3
+ */
4
+ class SpecialElementOption {
5
+ }
6
+ function isAnElement(value) {
7
+ if (value !== null &&
8
+ value !== undefined &&
9
+ (typeof value !== "object" || Array.isArray(value) || value instanceof EleganceElement))
10
+ return true;
11
+ return false;
12
+ }
13
+ class EleganceElement {
14
+ constructor(tag, options = {}, children = null) {
15
+ this.tag = tag;
16
+ if (isAnElement(options)) {
17
+ if (this.canHaveChildren() === false) {
18
+ console.error("The element:", this, "is an invalid element. Reason:");
19
+ throw "The options of an element may not be an element, if the element cannot have children.";
20
+ }
21
+ this.children = [options, ...(children ?? [])];
22
+ this.options = {};
23
+ }
24
+ else {
25
+ this.options = options;
26
+ this.children = children;
27
+ }
28
+ }
29
+ canHaveChildren() {
30
+ return this.children !== null;
31
+ }
32
+ }
33
+ export { EleganceElement, SpecialElementOption, isAnElement, };
@@ -0,0 +1,7 @@
1
+ import { EleganceElement, EleganceElementBuilder, ElementChildren } from "./element";
2
+ declare const elements: Record<string, EleganceElementBuilder<any>>;
3
+ declare const childrenlessElements: Record<string, EleganceElementBuilder<any>>;
4
+ declare const allElements: {
5
+ [x: string]: ((options?: any) => EleganceElement<any, false>) | ((options?: any, ...children: ElementChildren) => EleganceElement<any, true>);
6
+ };
7
+ export { elements, childrenlessElements, allElements, };
@@ -0,0 +1,65 @@
1
+ import { EleganceElement, } from "./element.js";
2
+ const htmlChildrenlessElementTags = [
3
+ "area", "base", "br", "col", "embed", "hr", "img", "input",
4
+ "link", "meta", "param", "source", "track", "wbr",
5
+ ];
6
+ const htmlElementTags = [
7
+ "a", "abbr", "address", "article", "aside", "audio", "b", "bdi", "bdo",
8
+ "blockquote", "body", "button", "canvas", "caption", "cite", "code",
9
+ "colgroup", "data", "datalist", "dd", "del", "details", "dfn", "dialog",
10
+ "div", "dl", "dt", "em", "fieldset", "figcaption", "figure", "footer",
11
+ "form", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup",
12
+ "html", "i", "iframe", "ins", "kbd", "label", "legend", "li", "main",
13
+ "map", "mark", "menu", "meter", "nav", "noscript", "object", "ol",
14
+ "optgroup", "option", "output", "p", "picture", "pre", "progress",
15
+ "q", "rp", "rt", "ruby", "s", "samp", "script", "search", "section",
16
+ "select", "slot", "small", "span", "strong", "style", "sub", "summary",
17
+ "sup", "table", "tbody", "td", "template", "textarea", "tfoot", "th",
18
+ "thead", "time", "title", "tr", "u", "ul", "varElement", "video",
19
+ ];
20
+ const svgChildrenlessElementTags = [
21
+ "path", "circle", "ellipse", "line", "polygon", "polyline", "stop",
22
+ ];
23
+ const svgElementTags = [
24
+ "svg", "g", "text", "tspan", "textPath", "defs", "symbol", "use",
25
+ "image", "clipPath", "mask", "pattern", "linearGradient", "radialGradient",
26
+ "filter", "marker", "view",
27
+ "feBlend", "feColorMatrix", "feComponentTransfer", "feComposite",
28
+ "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight",
29
+ "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur",
30
+ "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset",
31
+ "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence",
32
+ ];
33
+ const mathmlChildrenlessElementTags = [
34
+ "mi", "mn", "mo",
35
+ ];
36
+ const mathmlElementTags = [
37
+ "math", "ms", "mtext", "mrow", "mfenced", "msup", "msub", "msubsup",
38
+ "mfrac", "msqrt", "mroot", "mtable", "mtr", "mtd", "mstyle",
39
+ "menclose", "mmultiscripts",
40
+ ];
41
+ const elements = {};
42
+ const childrenlessElements = {};
43
+ function createElementBuilder(tag) {
44
+ return ((options, ...children) => new EleganceElement(tag, options, children));
45
+ }
46
+ function createChildrenlessElementBuilder(tag) {
47
+ return ((options) => new EleganceElement(tag, options, null));
48
+ }
49
+ for (const tag of htmlElementTags)
50
+ elements[tag] = createElementBuilder(tag);
51
+ for (const tag of svgElementTags)
52
+ elements[tag] = createElementBuilder(tag);
53
+ for (const tag of mathmlElementTags)
54
+ elements[tag] = createElementBuilder(tag);
55
+ for (const tag of htmlChildrenlessElementTags)
56
+ childrenlessElements[tag] = createChildrenlessElementBuilder(tag);
57
+ for (const tag of svgChildrenlessElementTags)
58
+ childrenlessElements[tag] = createChildrenlessElementBuilder(tag);
59
+ for (const tag of mathmlChildrenlessElementTags)
60
+ childrenlessElements[tag] = createChildrenlessElementBuilder(tag);
61
+ const allElements = {
62
+ ...elements,
63
+ ...childrenlessElements,
64
+ };
65
+ export { elements, childrenlessElements, allElements, };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Make an HTML string not be escaped by the Elegance compiler.
3
+ *
4
+ * A wrapped string from process A cannot be unwrapped in process B.
5
+ *
6
+ * **IMPORTANT:** Do not use this in client components. This functions exists for the *server* to prevent HTML injection.
7
+ * For most needs element({ innerHTML: "<p>Hello, World!</p>", }); should be enough.
8
+ * NOTE: Does not return suitable HTML, must be sent to the compiler for processing.
9
+ * @param html Any HTML string.
10
+ * @returns HTML string that will not be escaped by the compiler.
11
+ */
12
+ declare function raw(html: string): string;
13
+ declare function unwrapAllRaw(input: string): string;
14
+ export { raw, unwrapAllRaw, };
@@ -0,0 +1,78 @@
1
+ import crypto from "crypto";
2
+ /**
3
+ * Use cryptographically secure random bytes to generate un-escaped HTML that cannot be replicated by any component in-order to unescape itself.
4
+ */
5
+ const RAW_SECRET = crypto.randomBytes(32);
6
+ const PREFIX = "\uE000RAW:";
7
+ const SEP = "\uE001";
8
+ const SUFFIX = "\uE002";
9
+ /**
10
+ * Make an HTML string not be escaped by the Elegance compiler.
11
+ *
12
+ * A wrapped string from process A cannot be unwrapped in process B.
13
+ *
14
+ * **IMPORTANT:** Do not use this in client components. This functions exists for the *server* to prevent HTML injection.
15
+ * For most needs element({ innerHTML: "<p>Hello, World!</p>", }); should be enough.
16
+ * NOTE: Does not return suitable HTML, must be sent to the compiler for processing.
17
+ * @param html Any HTML string.
18
+ * @returns HTML string that will not be escaped by the compiler.
19
+ */
20
+ function raw(html) {
21
+ const mac = crypto.createHmac("sha256", RAW_SECRET)
22
+ .update(html)
23
+ .digest("base64url");
24
+ return PREFIX + mac + SEP + html + SUFFIX;
25
+ }
26
+ function maybeContainsRaw(s) {
27
+ return s.includes(PREFIX);
28
+ }
29
+ function escapeHtml(s) {
30
+ return s
31
+ .replace(/&/g, "&amp;")
32
+ .replace(/</g, "&lt;")
33
+ .replace(/>/g, "&gt;")
34
+ .replace(/"/g, "&quot;")
35
+ .replace(/'/g, "&#39;");
36
+ }
37
+ function unwrapAllRaw(input) {
38
+ if (!maybeContainsRaw(input))
39
+ return escapeHtml(input);
40
+ let out = "";
41
+ let i = 0;
42
+ while (i < input.length) {
43
+ const start = input.indexOf(PREFIX, i);
44
+ if (start === -1) {
45
+ out += escapeHtml(input.slice(i));
46
+ break;
47
+ }
48
+ out += escapeHtml(input.slice(i, start));
49
+ const macStart = start + PREFIX.length;
50
+ const sepIndex = input.indexOf(SEP, macStart);
51
+ if (sepIndex === -1) {
52
+ out += escapeHtml(input.slice(start));
53
+ break;
54
+ }
55
+ const suffixIndex = input.indexOf(SUFFIX, sepIndex + 1);
56
+ if (suffixIndex === -1) {
57
+ out += escapeHtml(input.slice(start));
58
+ break;
59
+ }
60
+ const mac = input.slice(macStart, sepIndex);
61
+ const html = input.slice(sepIndex + 1, suffixIndex);
62
+ const expected = crypto.createHmac("sha256", RAW_SECRET)
63
+ .update(html)
64
+ .digest("base64url");
65
+ const macBuf = Buffer.from(mac);
66
+ const expBuf = Buffer.from(expected);
67
+ if (macBuf.length === expBuf.length &&
68
+ crypto.timingSafeEqual(macBuf, expBuf)) {
69
+ out += html;
70
+ }
71
+ else {
72
+ out += escapeHtml(input.slice(start, suffixIndex + 1));
73
+ }
74
+ i = suffixIndex + SUFFIX.length;
75
+ }
76
+ return out;
77
+ }
78
+ export { raw, unwrapAllRaw, };