@getforma/core 1.0.3 → 1.0.5
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/README.md +20 -10
- package/dist/formajs.global.js +76 -51
- package/dist/formajs.global.js.map +1 -1
- package/dist/index.cjs +30 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +29 -6
- package/dist/index.js.map +1 -1
- package/package.json +22 -3
package/README.md
CHANGED
|
@@ -812,18 +812,28 @@ See the [`examples/`](./examples) directory:
|
|
|
812
812
|
|
|
813
813
|
---
|
|
814
814
|
|
|
815
|
-
##
|
|
815
|
+
## Part of the Forma Stack
|
|
816
816
|
|
|
817
|
-
|
|
817
|
+
### Frontend (TypeScript)
|
|
818
818
|
|
|
819
|
-
| Package |
|
|
820
|
-
|
|
821
|
-
| [@getforma/core](https://www.npmjs.com/package/@getforma/core) |
|
|
822
|
-
| [@getforma/compiler](https://
|
|
823
|
-
| [@getforma/build](https://
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
819
|
+
| Package | Description |
|
|
820
|
+
|---|---|
|
|
821
|
+
| [@getforma/core](https://www.npmjs.com/package/@getforma/core) | **This library** — reactive DOM, signals, islands, SSR hydration |
|
|
822
|
+
| [@getforma/compiler](https://www.npmjs.com/package/@getforma/compiler) | Vite plugin — h() optimization, server function transforms, FMIR emission |
|
|
823
|
+
| [@getforma/build](https://www.npmjs.com/package/@getforma/build) | Production pipeline — esbuild bundling, content hashing, compression, manifest |
|
|
824
|
+
|
|
825
|
+
### Backend (Rust)
|
|
826
|
+
|
|
827
|
+
| Package | Description |
|
|
828
|
+
|---|---|
|
|
829
|
+
| [forma-ir](https://crates.io/crates/forma-ir) | FMIR binary format — parser, walker, WASM exports |
|
|
830
|
+
| [forma-server](https://crates.io/crates/forma-server) | Axum middleware — SSR page rendering, asset serving, CSP headers |
|
|
831
|
+
|
|
832
|
+
### Full Framework
|
|
833
|
+
|
|
834
|
+
| Package | Description |
|
|
835
|
+
|---|---|
|
|
836
|
+
| [@getforma/create-app](https://github.com/getforma-dev/create-forma-app) | `npx @getforma/create-app` — scaffolds a Rust server + TypeScript frontend project |
|
|
827
837
|
|
|
828
838
|
---
|
|
829
839
|
|
package/dist/formajs.global.js
CHANGED
|
@@ -85,6 +85,8 @@ var FormaJS = (() => {
|
|
|
85
85
|
setStyle: () => setStyle,
|
|
86
86
|
setText: () => setText,
|
|
87
87
|
siblings: () => siblings,
|
|
88
|
+
template: () => template,
|
|
89
|
+
templateMany: () => templateMany,
|
|
88
90
|
toggleClass: () => toggleClass,
|
|
89
91
|
trackDisposer: () => trackDisposer,
|
|
90
92
|
trigger: () => trigger,
|
|
@@ -1253,7 +1255,7 @@ var FormaJS = (() => {
|
|
|
1253
1255
|
const fragment2 = document.createDocumentFragment();
|
|
1254
1256
|
fragment2.appendChild(startMarker);
|
|
1255
1257
|
fragment2.appendChild(endMarker);
|
|
1256
|
-
let
|
|
1258
|
+
let cache2 = /* @__PURE__ */ new Map();
|
|
1257
1259
|
let currentNodes = [];
|
|
1258
1260
|
let currentItems = [];
|
|
1259
1261
|
const updateOnItemChange = options?.updateOnItemChange ?? "none";
|
|
@@ -1270,7 +1272,7 @@ var FormaJS = (() => {
|
|
|
1270
1272
|
for (const node of currentNodes) {
|
|
1271
1273
|
if (node.parentNode === parent2) parent2.removeChild(node);
|
|
1272
1274
|
}
|
|
1273
|
-
|
|
1275
|
+
cache2 = /* @__PURE__ */ new Map();
|
|
1274
1276
|
currentNodes = [];
|
|
1275
1277
|
currentItems = [];
|
|
1276
1278
|
return;
|
|
@@ -1294,7 +1296,7 @@ var FormaJS = (() => {
|
|
|
1294
1296
|
}
|
|
1295
1297
|
const updateRow = updateOnItemChange === "rerender" ? (node, item) => {
|
|
1296
1298
|
const key = keyFn(item);
|
|
1297
|
-
const cached =
|
|
1299
|
+
const cached = cache2.get(key);
|
|
1298
1300
|
if (!cached) return;
|
|
1299
1301
|
if (cached.item === item) return;
|
|
1300
1302
|
cached.item = item;
|
|
@@ -1309,7 +1311,7 @@ var FormaJS = (() => {
|
|
|
1309
1311
|
}
|
|
1310
1312
|
} : (_node, item) => {
|
|
1311
1313
|
const key = keyFn(item);
|
|
1312
|
-
const cached =
|
|
1314
|
+
const cached = cache2.get(key);
|
|
1313
1315
|
if (cached) cached.item = item;
|
|
1314
1316
|
};
|
|
1315
1317
|
const result = reconcileList(
|
|
@@ -1323,7 +1325,7 @@ var FormaJS = (() => {
|
|
|
1323
1325
|
const key = keyFn(item);
|
|
1324
1326
|
const [getIndex, setIndex] = createSignal(0);
|
|
1325
1327
|
const element = untrack(() => renderFn(item, getIndex));
|
|
1326
|
-
|
|
1328
|
+
cache2.set(key, { element, item, getIndex, setIndex });
|
|
1327
1329
|
return element;
|
|
1328
1330
|
},
|
|
1329
1331
|
updateRow,
|
|
@@ -1333,13 +1335,13 @@ var FormaJS = (() => {
|
|
|
1333
1335
|
const newCache = /* @__PURE__ */ new Map();
|
|
1334
1336
|
for (let i = 0; i < cleanItems.length; i++) {
|
|
1335
1337
|
const key = keyFn(cleanItems[i]);
|
|
1336
|
-
const cached =
|
|
1338
|
+
const cached = cache2.get(key);
|
|
1337
1339
|
if (cached) {
|
|
1338
1340
|
cached.setIndex(i);
|
|
1339
1341
|
newCache.set(key, cached);
|
|
1340
1342
|
}
|
|
1341
1343
|
}
|
|
1342
|
-
|
|
1344
|
+
cache2 = newCache;
|
|
1343
1345
|
currentNodes = result.nodes;
|
|
1344
1346
|
currentItems = result.items;
|
|
1345
1347
|
});
|
|
@@ -1746,12 +1748,12 @@ var FormaJS = (() => {
|
|
|
1746
1748
|
for (const adoptedNode of adoptedNodes) {
|
|
1747
1749
|
parent2.insertBefore(adoptedNode, end);
|
|
1748
1750
|
}
|
|
1749
|
-
let
|
|
1751
|
+
let cache2 = /* @__PURE__ */ new Map();
|
|
1750
1752
|
for (let i = 0; i < adoptedItems.length; i++) {
|
|
1751
1753
|
const item = adoptedItems[i];
|
|
1752
1754
|
const key = listKeyFn(item);
|
|
1753
1755
|
const [getIndex, setIndex] = createSignal(i);
|
|
1754
|
-
|
|
1756
|
+
cache2.set(key, {
|
|
1755
1757
|
element: adoptedNodes[i],
|
|
1756
1758
|
item,
|
|
1757
1759
|
getIndex,
|
|
@@ -1777,7 +1779,7 @@ var FormaJS = (() => {
|
|
|
1777
1779
|
const key = listKeyFn(item);
|
|
1778
1780
|
const [getIndex, setIndex] = createSignal(0);
|
|
1779
1781
|
const element = untrack(() => listRenderFn(item, getIndex));
|
|
1780
|
-
|
|
1782
|
+
cache2.set(key, { element, item, getIndex, setIndex });
|
|
1781
1783
|
return element;
|
|
1782
1784
|
} finally {
|
|
1783
1785
|
hydrating = prevHydrating;
|
|
@@ -1785,7 +1787,7 @@ var FormaJS = (() => {
|
|
|
1785
1787
|
},
|
|
1786
1788
|
(_node, item) => {
|
|
1787
1789
|
const key = listKeyFn(item);
|
|
1788
|
-
const cached =
|
|
1790
|
+
const cached = cache2.get(key);
|
|
1789
1791
|
if (cached) cached.item = item;
|
|
1790
1792
|
},
|
|
1791
1793
|
end
|
|
@@ -1793,13 +1795,13 @@ var FormaJS = (() => {
|
|
|
1793
1795
|
const newCache = /* @__PURE__ */ new Map();
|
|
1794
1796
|
for (let i = 0; i < newItems.length; i++) {
|
|
1795
1797
|
const key = listKeyFn(newItems[i]);
|
|
1796
|
-
const cached =
|
|
1798
|
+
const cached = cache2.get(key);
|
|
1797
1799
|
if (cached) {
|
|
1798
1800
|
cached.setIndex(i);
|
|
1799
1801
|
newCache.set(key, cached);
|
|
1800
1802
|
}
|
|
1801
1803
|
}
|
|
1802
|
-
|
|
1804
|
+
cache2 = newCache;
|
|
1803
1805
|
reconcileNodes = result.nodes;
|
|
1804
1806
|
reconcileItems = result.items;
|
|
1805
1807
|
});
|
|
@@ -2073,9 +2075,9 @@ var FormaJS = (() => {
|
|
|
2073
2075
|
if (typeof value2 === "function") {
|
|
2074
2076
|
internalEffect(() => {
|
|
2075
2077
|
const v = value2();
|
|
2076
|
-
const
|
|
2077
|
-
if (
|
|
2078
|
-
|
|
2078
|
+
const cache2 = getCache(el);
|
|
2079
|
+
if (cache2["class"] === v) return;
|
|
2080
|
+
cache2["class"] = v;
|
|
2079
2081
|
if (el instanceof HTMLElement) {
|
|
2080
2082
|
el.className = v;
|
|
2081
2083
|
} else {
|
|
@@ -2083,9 +2085,9 @@ var FormaJS = (() => {
|
|
|
2083
2085
|
}
|
|
2084
2086
|
});
|
|
2085
2087
|
} else {
|
|
2086
|
-
const
|
|
2087
|
-
if (
|
|
2088
|
-
|
|
2088
|
+
const cache2 = getCache(el);
|
|
2089
|
+
if (cache2["class"] === value2) return;
|
|
2090
|
+
cache2["class"] = value2;
|
|
2089
2091
|
if (el instanceof HTMLElement) {
|
|
2090
2092
|
el.className = value2;
|
|
2091
2093
|
} else {
|
|
@@ -2099,9 +2101,9 @@ var FormaJS = (() => {
|
|
|
2099
2101
|
internalEffect(() => {
|
|
2100
2102
|
const v = value2();
|
|
2101
2103
|
if (typeof v === "string") {
|
|
2102
|
-
const
|
|
2103
|
-
if (
|
|
2104
|
-
|
|
2104
|
+
const cache2 = getCache(el);
|
|
2105
|
+
if (cache2["style"] === v) return;
|
|
2106
|
+
cache2["style"] = v;
|
|
2105
2107
|
prevKeys = [];
|
|
2106
2108
|
el.style.cssText = v;
|
|
2107
2109
|
} else if (v && typeof v === "object") {
|
|
@@ -2117,9 +2119,9 @@ var FormaJS = (() => {
|
|
|
2117
2119
|
}
|
|
2118
2120
|
});
|
|
2119
2121
|
} else if (typeof value2 === "string") {
|
|
2120
|
-
const
|
|
2121
|
-
if (
|
|
2122
|
-
|
|
2122
|
+
const cache2 = getCache(el);
|
|
2123
|
+
if (cache2["style"] === value2) return;
|
|
2124
|
+
cache2["style"] = value2;
|
|
2123
2125
|
el.style.cssText = value2;
|
|
2124
2126
|
} else if (value2 && typeof value2 === "object") {
|
|
2125
2127
|
Object.assign(el.style, value2);
|
|
@@ -2152,9 +2154,9 @@ var FormaJS = (() => {
|
|
|
2152
2154
|
"dangerouslySetInnerHTML: __html must be a string, got " + typeof html
|
|
2153
2155
|
);
|
|
2154
2156
|
}
|
|
2155
|
-
const
|
|
2156
|
-
if (
|
|
2157
|
-
|
|
2157
|
+
const cache2 = getCache(el);
|
|
2158
|
+
if (cache2["innerHTML"] === html) return;
|
|
2159
|
+
cache2["innerHTML"] = html;
|
|
2158
2160
|
el.innerHTML = html;
|
|
2159
2161
|
});
|
|
2160
2162
|
} else {
|
|
@@ -2199,9 +2201,9 @@ var FormaJS = (() => {
|
|
|
2199
2201
|
if (typeof value2 === "function") {
|
|
2200
2202
|
internalEffect(() => {
|
|
2201
2203
|
const v = value2();
|
|
2202
|
-
const
|
|
2203
|
-
if (
|
|
2204
|
-
|
|
2204
|
+
const cache2 = getCache(el);
|
|
2205
|
+
if (cache2[key] === v) return;
|
|
2206
|
+
cache2[key] = v;
|
|
2205
2207
|
if (v) {
|
|
2206
2208
|
el.setAttribute(key, "");
|
|
2207
2209
|
} else {
|
|
@@ -2209,9 +2211,9 @@ var FormaJS = (() => {
|
|
|
2209
2211
|
}
|
|
2210
2212
|
});
|
|
2211
2213
|
} else {
|
|
2212
|
-
const
|
|
2213
|
-
if (
|
|
2214
|
-
|
|
2214
|
+
const cache2 = getCache(el);
|
|
2215
|
+
if (cache2[key] === value2) return;
|
|
2216
|
+
cache2[key] = value2;
|
|
2215
2217
|
if (value2) {
|
|
2216
2218
|
el.setAttribute(key, "");
|
|
2217
2219
|
} else {
|
|
@@ -2224,29 +2226,29 @@ var FormaJS = (() => {
|
|
|
2224
2226
|
internalEffect(() => {
|
|
2225
2227
|
const v = value2();
|
|
2226
2228
|
if (v == null || v === false) {
|
|
2227
|
-
const
|
|
2228
|
-
if (
|
|
2229
|
-
|
|
2229
|
+
const cache2 = getCache(el);
|
|
2230
|
+
if (cache2[key] === null) return;
|
|
2231
|
+
cache2[key] = null;
|
|
2230
2232
|
el.removeAttribute(key);
|
|
2231
2233
|
} else {
|
|
2232
2234
|
const strVal = String(v);
|
|
2233
|
-
const
|
|
2234
|
-
if (
|
|
2235
|
-
|
|
2235
|
+
const cache2 = getCache(el);
|
|
2236
|
+
if (cache2[key] === strVal) return;
|
|
2237
|
+
cache2[key] = strVal;
|
|
2236
2238
|
el.setAttribute(key, strVal);
|
|
2237
2239
|
}
|
|
2238
2240
|
});
|
|
2239
2241
|
} else {
|
|
2240
2242
|
if (value2 == null || value2 === false) {
|
|
2241
|
-
const
|
|
2242
|
-
if (
|
|
2243
|
-
|
|
2243
|
+
const cache2 = getCache(el);
|
|
2244
|
+
if (cache2[key] === null) return;
|
|
2245
|
+
cache2[key] = null;
|
|
2244
2246
|
el.removeAttribute(key);
|
|
2245
2247
|
} else {
|
|
2246
2248
|
const strVal = String(value2);
|
|
2247
|
-
const
|
|
2248
|
-
if (
|
|
2249
|
-
|
|
2249
|
+
const cache2 = getCache(el);
|
|
2250
|
+
if (cache2[key] === strVal) return;
|
|
2251
|
+
cache2[key] = strVal;
|
|
2250
2252
|
el.setAttribute(key, strVal);
|
|
2251
2253
|
}
|
|
2252
2254
|
}
|
|
@@ -2497,7 +2499,7 @@ var FormaJS = (() => {
|
|
|
2497
2499
|
const fragment2 = document.createDocumentFragment();
|
|
2498
2500
|
fragment2.appendChild(startMarker);
|
|
2499
2501
|
fragment2.appendChild(endMarker);
|
|
2500
|
-
const
|
|
2502
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
2501
2503
|
let currentNode = null;
|
|
2502
2504
|
let currentMatch = UNSET;
|
|
2503
2505
|
const switchDispose = internalEffect(() => {
|
|
@@ -2532,7 +2534,7 @@ var FormaJS = (() => {
|
|
|
2532
2534
|
}
|
|
2533
2535
|
const matchedCase = cases.find((c) => c.match === val);
|
|
2534
2536
|
if (matchedCase) {
|
|
2535
|
-
let entry =
|
|
2537
|
+
let entry = cache2.get(val);
|
|
2536
2538
|
if (!entry) {
|
|
2537
2539
|
let branchDispose;
|
|
2538
2540
|
const node = createRoot((dispose) => {
|
|
@@ -2540,7 +2542,7 @@ var FormaJS = (() => {
|
|
|
2540
2542
|
return untrack(() => matchedCase.render());
|
|
2541
2543
|
});
|
|
2542
2544
|
entry = { node, dispose: branchDispose };
|
|
2543
|
-
|
|
2545
|
+
cache2.set(val, entry);
|
|
2544
2546
|
if (DEBUG) console.log("[forma:switch] rendered new branch for", String(val), "\u2192", node.nodeName, "type", node.nodeType);
|
|
2545
2547
|
} else {
|
|
2546
2548
|
if (DEBUG) console.log("[forma:switch] reusing cached branch for", String(val), "\u2192", entry.node.nodeName, "type", entry.node.nodeType, "childNodes", entry.node.childNodes?.length);
|
|
@@ -2557,10 +2559,10 @@ var FormaJS = (() => {
|
|
|
2557
2559
|
});
|
|
2558
2560
|
fragment2.__switchDispose = () => {
|
|
2559
2561
|
switchDispose();
|
|
2560
|
-
for (const entry of
|
|
2562
|
+
for (const entry of cache2.values()) {
|
|
2561
2563
|
entry.dispose();
|
|
2562
2564
|
}
|
|
2563
|
-
|
|
2565
|
+
cache2.clear();
|
|
2564
2566
|
};
|
|
2565
2567
|
return fragment2;
|
|
2566
2568
|
}
|
|
@@ -2664,6 +2666,29 @@ var FormaJS = (() => {
|
|
|
2664
2666
|
return fragment2;
|
|
2665
2667
|
}
|
|
2666
2668
|
|
|
2669
|
+
// src/dom/template.ts
|
|
2670
|
+
var cache = /* @__PURE__ */ new Map();
|
|
2671
|
+
function template(html) {
|
|
2672
|
+
let node = cache.get(html);
|
|
2673
|
+
if (!node) {
|
|
2674
|
+
const tpl = document.createElement("template");
|
|
2675
|
+
tpl.innerHTML = html;
|
|
2676
|
+
node = tpl.content.firstChild;
|
|
2677
|
+
cache.set(html, node);
|
|
2678
|
+
}
|
|
2679
|
+
return node;
|
|
2680
|
+
}
|
|
2681
|
+
function templateMany(html) {
|
|
2682
|
+
let node = cache.get(html);
|
|
2683
|
+
if (!node) {
|
|
2684
|
+
const tpl = document.createElement("template");
|
|
2685
|
+
tpl.innerHTML = html;
|
|
2686
|
+
node = tpl.content;
|
|
2687
|
+
cache.set(html, node);
|
|
2688
|
+
}
|
|
2689
|
+
return node.cloneNode(true);
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2667
2692
|
// src/dom/activate.ts
|
|
2668
2693
|
var FORBIDDEN_PROP_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
2669
2694
|
function sanitizeProps(obj) {
|