@endge/native-dom 0.1.1
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.
- package/dist/domain/types/native-dom-sfc-render.type.d.ts +20 -0
- package/dist/main.d.ts +4 -0
- package/dist/model/render/sfc/native-dom-render-tools.d.ts +11 -0
- package/dist/model/render/sfc/native-dom-sfc-adapter.d.ts +4 -0
- package/dist/model/render/sfc/native-dom-visual-renderers.d.ts +3 -0
- package/dist/native-dom.js +128 -0
- package/dist/test/native-dom-sfc-adapter.test.d.ts +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EndgeSFCRenderAdapterKey, UIRenderAdapter } from '@endge/core';
|
|
2
|
+
/** Вход renderer-а одного уже вычисленного SFC primitive. */
|
|
3
|
+
export interface SFCNativeDOMRenderElementInput {
|
|
4
|
+
document: Document;
|
|
5
|
+
children: readonly SFCNativeDOMChild[];
|
|
6
|
+
props: Record<string, unknown>;
|
|
7
|
+
attrs: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export type SFCNativeDOMChild = Node | string | number | boolean | null | undefined;
|
|
10
|
+
/** Renderer одной visual primitive в Native DOM engine. */
|
|
11
|
+
export type SFCNativeDOMRenderAdapterFunction = (input: SFCNativeDOMRenderElementInput) => HTMLElement;
|
|
12
|
+
/** Полный набор visual primitive renderers Native DOM adapter-а. */
|
|
13
|
+
export type SFCNativeDOMRenderAdapterRendererMap = Record<EndgeSFCRenderAdapterKey, SFCNativeDOMRenderAdapterFunction>;
|
|
14
|
+
/** Типизированный SFC adapter для Native DOM render engine. */
|
|
15
|
+
export interface SFCNativeDOMRenderAdapter extends UIRenderAdapter<SFCNativeDOMRenderAdapterFunction> {
|
|
16
|
+
protocol: 'endge-sfc';
|
|
17
|
+
protocolVersion: 1;
|
|
18
|
+
renderer: 'native-dom';
|
|
19
|
+
renderers: SFCNativeDOMRenderAdapterRendererMap;
|
|
20
|
+
}
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SFCNativeDOMChild, SFCNativeDOMRenderElementInput } from '../../../domain/types/native-dom-sfc-render.type';
|
|
2
|
+
/** Создаёт DOM element и применяет общие attrs, children и placement. */
|
|
3
|
+
export declare function createNativeDOMElement(input: SFCNativeDOMRenderElementInput, tag: keyof HTMLElementTagNameMap, className: string): HTMLElement;
|
|
4
|
+
/** Добавляет children без HTML-string interpolation. */
|
|
5
|
+
export declare function appendNativeDOMChildren(element: HTMLElement, children: readonly SFCNativeDOMChild[]): void;
|
|
6
|
+
/** Применяет безопасный набор already-normalized DOM attrs. */
|
|
7
|
+
export declare function applyNativeDOMAttrs(element: HTMLElement, attrs: Record<string, unknown>): void;
|
|
8
|
+
/** Применяет renderer-neutral placement props к любому Grid child. */
|
|
9
|
+
export declare function applyNativeDOMGridPlacement(element: HTMLElement, props: Record<string, unknown>): void;
|
|
10
|
+
export declare function normalizeNativeDOMLength(value: unknown, numericUnit?: number): string;
|
|
11
|
+
export declare function normalizeNativeDOMTracks(value: unknown, fallback?: number): string;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { SFCNativeDOMRenderAdapter } from '../../../domain/types/native-dom-sfc-render.type';
|
|
2
|
+
export declare const NATIVE_DOM_SFC_ADAPTER_ID = "native-dom";
|
|
3
|
+
/** Стандартный SFC adapter без зависимости от Vue или другого UI framework. */
|
|
4
|
+
export declare const NativeDOMSFCAdapter: SFCNativeDOMRenderAdapter;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { ENDGE_SFC_RENDER_ADAPTER_PROTOCOL_VERSION as g, ENDGE_SFC_RENDER_ADAPTER_PROTOCOL as m } from "@endge/core";
|
|
2
|
+
function s(e, r, t) {
|
|
3
|
+
const o = e.document.createElement(r);
|
|
4
|
+
return u(o, e.attrs), o.classList.add(t), y(o, e.props), d(o, e.children), o;
|
|
5
|
+
}
|
|
6
|
+
function d(e, r) {
|
|
7
|
+
for (const t of r) {
|
|
8
|
+
if (t == null || t === !1) continue;
|
|
9
|
+
const o = typeof t == "object" && "nodeType" in t;
|
|
10
|
+
e.append(o ? t : String(t));
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function u(e, r) {
|
|
14
|
+
for (const [t, o] of Object.entries(r))
|
|
15
|
+
if (!(o == null || o === !1 || t === "key")) {
|
|
16
|
+
if (t === "class") {
|
|
17
|
+
f(o).forEach((l) => e.classList.add(l));
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (t === "style" && o && typeof o == "object") {
|
|
21
|
+
Object.assign(e.style, o);
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
t.startsWith("on") || e.setAttribute(t, o === !0 ? "" : String(o));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function y(e, r) {
|
|
28
|
+
const t = c(r.colStart, r.colSpan), o = c(r.rowStart, r.rowSpan);
|
|
29
|
+
t && (e.style.gridColumn = t), o && (e.style.gridRow = o);
|
|
30
|
+
}
|
|
31
|
+
function n(e, r = 1) {
|
|
32
|
+
if (e == null || e === !1) return "";
|
|
33
|
+
if (typeof e == "number") return `${e * r}px`;
|
|
34
|
+
const t = String(e).trim();
|
|
35
|
+
return /^-?\d+(\.\d+)?$/.test(t) ? `${Number(t) * r}px` : t;
|
|
36
|
+
}
|
|
37
|
+
function i(e, r) {
|
|
38
|
+
if (e == null || e === !1 || String(e).trim() === "")
|
|
39
|
+
return r ? `repeat(${r}, minmax(0, 1fr))` : "";
|
|
40
|
+
const t = String(e).trim();
|
|
41
|
+
return /^\d+$/.test(t) && Number(t) > 0 ? `repeat(${Number(t)}, minmax(0, 1fr))` : t;
|
|
42
|
+
}
|
|
43
|
+
function c(e, r) {
|
|
44
|
+
const t = p(e), o = p(r);
|
|
45
|
+
return t != null && o != null ? `${t} / span ${o}` : t != null ? String(t) : o != null ? `span ${o}` : "";
|
|
46
|
+
}
|
|
47
|
+
function p(e) {
|
|
48
|
+
if (e == null || e === !1 || e === "") return null;
|
|
49
|
+
const r = Number(e);
|
|
50
|
+
return Number.isInteger(r) && r > 0 ? r : null;
|
|
51
|
+
}
|
|
52
|
+
function f(e) {
|
|
53
|
+
return Array.isArray(e) ? e.flatMap(f) : e && typeof e == "object" ? Object.entries(e).filter(([, r]) => !!r).map(([r]) => r) : String(e ?? "").trim().split(/\s+/).filter(Boolean);
|
|
54
|
+
}
|
|
55
|
+
const b = {
|
|
56
|
+
Text: (e) => s(e, "span", "endge-sfc-text"),
|
|
57
|
+
DateTime: (e) => {
|
|
58
|
+
const r = s(e, "time", "endge-sfc-datetime");
|
|
59
|
+
return e.props.value != null && e.children.length === 0 && (r.textContent = String(e.props.value)), r;
|
|
60
|
+
},
|
|
61
|
+
Number: (e) => {
|
|
62
|
+
const r = s(e, "span", "endge-sfc-number");
|
|
63
|
+
return e.props.value != null && e.children.length === 0 && (r.textContent = String(e.props.value)), r;
|
|
64
|
+
},
|
|
65
|
+
Icon: (e) => {
|
|
66
|
+
const r = s(e, "span", "endge-sfc-icon");
|
|
67
|
+
return r.setAttribute("aria-hidden", e.props.label == null ? "true" : "false"), e.props.label != null && r.setAttribute("aria-label", String(e.props.label)), e.props.name != null && e.children.length === 0 && (r.textContent = String(e.props.name)), r;
|
|
68
|
+
},
|
|
69
|
+
Badge: (e) => s(e, "span", "endge-sfc-badge"),
|
|
70
|
+
Dot: (e) => {
|
|
71
|
+
const r = s(e, "span", "endge-sfc-dot"), t = n(e.props.size, 1) || "8px";
|
|
72
|
+
return r.style.display = "inline-block", r.style.width = t, r.style.height = t, r.style.borderRadius = "9999px", r;
|
|
73
|
+
},
|
|
74
|
+
Box: (e) => s(e, "div", "endge-sfc-box"),
|
|
75
|
+
Flex: (e) => {
|
|
76
|
+
const r = s(e, "div", "endge-sfc-flex"), t = e.props.col === !0 || e.props.direction === "column";
|
|
77
|
+
return r.style.display = "flex", r.style.flexDirection = t ? "column" : "row", r.style.gap = n(e.props.gap, 4), e.props.align != null && (r.style.alignItems = String(e.props.align)), e.props.justify != null && (r.style.justifyContent = String(e.props.justify)), (e.props.wrap === !0 || e.props.wrap === "wrap") && (r.style.flexWrap = "wrap"), r;
|
|
78
|
+
},
|
|
79
|
+
Grid: (e) => {
|
|
80
|
+
const r = s(e, "div", "endge-sfc-grid");
|
|
81
|
+
return r.style.display = "grid", r.style.gridTemplateColumns = i(e.props.columns, 12), r.style.gridTemplateRows = i(e.props.rows), r.style.gridAutoRows = n(e.props.autoRows), e.props.autoFlow != null && (r.style.gridAutoFlow = String(e.props.autoFlow)), r.style.gap = n(e.props.gap, 4), r.style.columnGap = n(e.props.columnGap, 4), r.style.rowGap = n(e.props.rowGap, 4), e.props.align != null && (r.style.alignItems = String(e.props.align)), e.props.justify != null && (r.style.justifyItems = String(e.props.justify)), r;
|
|
82
|
+
},
|
|
83
|
+
Divider: (e) => s(e, "hr", "endge-sfc-divider"),
|
|
84
|
+
Input: (e) => {
|
|
85
|
+
const r = s({ ...e, children: [] }, "input", "endge-sfc-input");
|
|
86
|
+
return e.props.type != null && (r.type = String(e.props.type).toLowerCase()), e.props.value != null && (r.value = String(e.props.value)), e.props.placeholder != null && (r.placeholder = String(e.props.placeholder)), e.props.disabled === !0 && (r.disabled = !0), r;
|
|
87
|
+
},
|
|
88
|
+
Textarea: (e) => {
|
|
89
|
+
const r = s({ ...e, children: [] }, "textarea", "endge-sfc-textarea");
|
|
90
|
+
return e.props.value != null && (r.value = String(e.props.value)), e.props.placeholder != null && (r.placeholder = String(e.props.placeholder)), e.props.rows != null && (r.rows = Math.max(1, Number(e.props.rows) || 1)), e.props.disabled === !0 && (r.disabled = !0), r;
|
|
91
|
+
},
|
|
92
|
+
Checkbox: (e) => {
|
|
93
|
+
const r = s({ ...e, children: [] }, "label", "endge-sfc-checkbox"), t = e.document.createElement("input");
|
|
94
|
+
return t.type = "checkbox", t.checked = e.props.checked === !0, t.disabled = e.props.disabled === !0, r.append(t), e.props.label != null && r.append(String(e.props.label)), d(r, e.children), r;
|
|
95
|
+
},
|
|
96
|
+
Select: (e) => {
|
|
97
|
+
const r = s({ ...e, children: [] }, "select", "endge-sfc-select");
|
|
98
|
+
r.multiple = e.props.multiple === !0, r.disabled = e.props.disabled === !0;
|
|
99
|
+
const t = Array.isArray(e.props.options) ? e.props.options : [];
|
|
100
|
+
for (const o of t) {
|
|
101
|
+
const l = e.document.createElement("option");
|
|
102
|
+
if (o && typeof o == "object") {
|
|
103
|
+
const a = o;
|
|
104
|
+
l.value = String(a.value ?? ""), l.textContent = String(a.label ?? a.value ?? "");
|
|
105
|
+
} else
|
|
106
|
+
l.value = String(o ?? ""), l.textContent = String(o ?? "");
|
|
107
|
+
r.append(l);
|
|
108
|
+
}
|
|
109
|
+
return r;
|
|
110
|
+
}
|
|
111
|
+
}, S = "native-dom", x = {
|
|
112
|
+
id: S,
|
|
113
|
+
protocol: m,
|
|
114
|
+
protocolVersion: g,
|
|
115
|
+
renderer: "native-dom",
|
|
116
|
+
renderers: b
|
|
117
|
+
};
|
|
118
|
+
export {
|
|
119
|
+
S as NATIVE_DOM_SFC_ADAPTER_ID,
|
|
120
|
+
x as NativeDOMSFCAdapter,
|
|
121
|
+
b as NativeDOMVisualRenderers,
|
|
122
|
+
d as appendNativeDOMChildren,
|
|
123
|
+
u as applyNativeDOMAttrs,
|
|
124
|
+
y as applyNativeDOMGridPlacement,
|
|
125
|
+
s as createNativeDOMElement,
|
|
126
|
+
n as normalizeNativeDOMLength,
|
|
127
|
+
i as normalizeNativeDOMTracks
|
|
128
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@endge/native-dom",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/native-dom.js",
|
|
8
|
+
"module": "./dist/native-dom.js",
|
|
9
|
+
"types": "./dist/main.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/main.d.ts",
|
|
13
|
+
"import": "./dist/native-dom.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"@endge/core": "^1.2.7"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@endge/core": "link:../@endge-core",
|
|
24
|
+
"jsdom": "^26.1.0",
|
|
25
|
+
"rimraf": "^6.0.1",
|
|
26
|
+
"typescript": "^5.5.4",
|
|
27
|
+
"vite": "^6.1.0",
|
|
28
|
+
"vite-plugin-dts": "^4.5.0",
|
|
29
|
+
"vitest": "^2.1.9"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"clean": "rimraf dist tsconfig.tsbuildinfo",
|
|
33
|
+
"build": "vite build",
|
|
34
|
+
"test": "vitest",
|
|
35
|
+
"typecheck": "tsc --noEmit"
|
|
36
|
+
}
|
|
37
|
+
}
|