so it begins
This commit is contained in:
parent
784ef673c8
commit
2ac046a297
11
README.md
11
README.md
@ -1,11 +0,0 @@
|
|||||||
|
|
||||||
Run in an empty directory to setup basic files:
|
|
||||||
```
|
|
||||||
deno run -Ar https://gitea.hptrow.me/SethTrowbridge/gale/raw/branch/master/scripts/scaffold.ts
|
|
||||||
```
|
|
||||||
|
|
||||||
- `deno task work` starts the dev server
|
|
||||||
- `deno task scan` scans the deno.json for type declaration files (be sure to then restart the Deno language server)
|
|
||||||
- `deno task html` creates an index.html for use when static file hosting (the dev serve will create its own index.html if none exists in the file system)
|
|
||||||
|
|
||||||
`entry` in the import map points to the starting file
|
|
45
app.js
45
app.js
@ -1,45 +0,0 @@
|
|||||||
const {DOM, Tag, Div} = Gale({
|
|
||||||
Button: {
|
|
||||||
padding: "20px",
|
|
||||||
background: "orange",
|
|
||||||
".Inner": {
|
|
||||||
fontSize: "10rem"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Outline: {
|
|
||||||
border: "2px solid orange"
|
|
||||||
},
|
|
||||||
Window:{
|
|
||||||
height: "100vh",
|
|
||||||
border: "2px solid black",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "row",
|
|
||||||
alignItems: "end",
|
|
||||||
justifyContent: "center",
|
|
||||||
gap: "10px"
|
|
||||||
},
|
|
||||||
Ability:{
|
|
||||||
width: "50px",
|
|
||||||
height: "50px",
|
|
||||||
background: "red",
|
|
||||||
transition: "all 0.4s",
|
|
||||||
":hover":{
|
|
||||||
transform:"scale(1.1)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Orange:{
|
|
||||||
background:"orange"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const UI =()=>
|
|
||||||
{
|
|
||||||
return Div.Window(
|
|
||||||
Div.Ability({class:Tag("Ability", "Orange")}),
|
|
||||||
Div.Ability(),
|
|
||||||
Div.Ability(),
|
|
||||||
Div.Ability.Orange(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
van.add(document.body, UI());
|
|
9
app.tsx
Normal file
9
app.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import * as React from ">/npm:react";
|
||||||
|
|
||||||
|
export function App(){
|
||||||
|
return <>
|
||||||
|
<div>lol hey!</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default "lol"
|
22
deno.json
22
deno.json
@ -1,19 +1,13 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions":
|
"tasks": {
|
||||||
{
|
"dev": "deno -A --unstable-bundle --watch server.ts"
|
||||||
"checkJs": true,
|
|
||||||
"lib": ["deno.window", "DOM"],
|
|
||||||
"types": ["GALE@HOST/types.d.ts"]
|
|
||||||
},
|
},
|
||||||
"tasks":
|
"compilerOptions": {
|
||||||
{
|
"jsx": "react-jsx",
|
||||||
"work": "deno run -Ar GALE@HOST/scripts/dev_server.ts",
|
"jsxImportSource": "react"
|
||||||
"scan": "deno run -Ar GALE@HOST/scripts/refresh_types.ts",
|
|
||||||
"html": "deno run -Ar GALE@HOST/scripts/scaffold.ts --html"
|
|
||||||
},
|
},
|
||||||
"imports":
|
"imports": {
|
||||||
{
|
"@std/assert": "jsr:@std/assert@1",
|
||||||
"GALE@HOST/":"./",
|
"react":"npm:react"
|
||||||
"GALE@ENTRY":"./app.js"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
113
deno.lock
113
deno.lock
@ -1,111 +1,26 @@
|
|||||||
{
|
{
|
||||||
"version": "5",
|
"version": "5",
|
||||||
"specifiers": {
|
"specifiers": {
|
||||||
"jsr:@std/media-types@*": "1.1.0",
|
"npm:react@*": "19.2.0"
|
||||||
"npm:vanjs-core@*": "1.5.5",
|
|
||||||
"npm:vanjs-core@^1.5.5": "1.5.5",
|
|
||||||
"npm:vanjs-ext@~0.6.3": "0.6.3"
|
|
||||||
},
|
|
||||||
"jsr": {
|
|
||||||
"@std/media-types@1.1.0": {
|
|
||||||
"integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"npm": {
|
"npm": {
|
||||||
"vanjs-core@1.5.5": {
|
"react@19.2.0": {
|
||||||
"integrity": "sha512-BC9MjbXYIRqnwncXfacT6upJpVmIKyrV2MjZi8NuCK+yc9RP0hfdghTpmEuYswXOfkLarDPPcYK4X6q68T9e+g=="
|
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="
|
||||||
},
|
|
||||||
"vanjs-ext@0.6.3": {
|
|
||||||
"integrity": "sha512-Jmaeqx9nCjelwDVSQEaRtt7R4Y/Kj/zJBG3bZSiIPj8Wtr8nEFRsJX9K5qcGl1o3cGEEFBE9suyoSqs/6tiOBg==",
|
|
||||||
"dependencies": [
|
|
||||||
"vanjs-core"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"redirects": {
|
"redirects": {
|
||||||
"https://deno.land/std/path/mod.ts": "https://deno.land/std@0.224.0/path/mod.ts"
|
"https://esm.sh/type-detect@^4.0.0?target=denonext": "https://esm.sh/type-detect@4.1.0?target=denonext"
|
||||||
},
|
},
|
||||||
"remote": {
|
"remote": {
|
||||||
"https://deno.land/std@0.224.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834",
|
"https://esm.sh/deep-eql@4.1.3": "324a95b802d9f87b5ed66afdf079a0c47cd1cac3db59e9face0969be8eb980f7",
|
||||||
"https://deno.land/std@0.224.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917",
|
"https://esm.sh/deep-eql@4.1.3/denonext/deep-eql.mjs": "53319cc47b4be171d3a1aeeef9f3160a818e08b35baf9018cd14093f79e2910c",
|
||||||
"https://deno.land/std@0.224.0/path/_common/assert_path.ts": "dbdd757a465b690b2cc72fc5fb7698c51507dec6bfafce4ca500c46b76ff7bd8",
|
"https://esm.sh/type-detect@4.1.0/denonext/type-detect.mjs": "ea850c5962bd47b0157c7e4cf38376cb7fb9fb3ad2438be0a724dbbadda5b94e",
|
||||||
"https://deno.land/std@0.224.0/path/_common/basename.ts": "569744855bc8445f3a56087fd2aed56bdad39da971a8d92b138c9913aecc5fa2",
|
"https://esm.sh/type-detect@4.1.0?target=denonext": "7257f955377cabc9a54bfa18f3bd16e12e40a090f25bf238299325d562e92fca"
|
||||||
"https://deno.land/std@0.224.0/path/_common/common.ts": "ef73c2860694775fe8ffcbcdd387f9f97c7a656febf0daa8c73b56f4d8a7bd4c",
|
},
|
||||||
"https://deno.land/std@0.224.0/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c",
|
"workspace": {
|
||||||
"https://deno.land/std@0.224.0/path/_common/dirname.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8",
|
"dependencies": [
|
||||||
"https://deno.land/std@0.224.0/path/_common/format.ts": "92500e91ea5de21c97f5fe91e178bae62af524b72d5fcd246d6d60ae4bcada8b",
|
"jsr:@std/assert@1",
|
||||||
"https://deno.land/std@0.224.0/path/_common/from_file_url.ts": "d672bdeebc11bf80e99bf266f886c70963107bdd31134c4e249eef51133ceccf",
|
"npm:react@*"
|
||||||
"https://deno.land/std@0.224.0/path/_common/glob_to_reg_exp.ts": "6cac16d5c2dc23af7d66348a7ce430e5de4e70b0eede074bdbcf4903f4374d8d",
|
]
|
||||||
"https://deno.land/std@0.224.0/path/_common/normalize.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8",
|
|
||||||
"https://deno.land/std@0.224.0/path/_common/normalize_string.ts": "33edef773c2a8e242761f731adeb2bd6d683e9c69e4e3d0092985bede74f4ac3",
|
|
||||||
"https://deno.land/std@0.224.0/path/_common/relative.ts": "faa2753d9b32320ed4ada0733261e3357c186e5705678d9dd08b97527deae607",
|
|
||||||
"https://deno.land/std@0.224.0/path/_common/strip_trailing_separators.ts": "7024a93447efcdcfeaa9339a98fa63ef9d53de363f1fbe9858970f1bba02655a",
|
|
||||||
"https://deno.land/std@0.224.0/path/_common/to_file_url.ts": "7f76adbc83ece1bba173e6e98a27c647712cab773d3f8cbe0398b74afc817883",
|
|
||||||
"https://deno.land/std@0.224.0/path/_interface.ts": "8dfeb930ca4a772c458a8c7bbe1e33216fe91c253411338ad80c5b6fa93ddba0",
|
|
||||||
"https://deno.land/std@0.224.0/path/_os.ts": "8fb9b90fb6b753bd8c77cfd8a33c2ff6c5f5bc185f50de8ca4ac6a05710b2c15",
|
|
||||||
"https://deno.land/std@0.224.0/path/basename.ts": "7ee495c2d1ee516ffff48fb9a93267ba928b5a3486b550be73071bc14f8cc63e",
|
|
||||||
"https://deno.land/std@0.224.0/path/common.ts": "03e52e22882402c986fe97ca3b5bb4263c2aa811c515ce84584b23bac4cc2643",
|
|
||||||
"https://deno.land/std@0.224.0/path/constants.ts": "0c206169ca104938ede9da48ac952de288f23343304a1c3cb6ec7625e7325f36",
|
|
||||||
"https://deno.land/std@0.224.0/path/dirname.ts": "85bd955bf31d62c9aafdd7ff561c4b5fb587d11a9a5a45e2b01aedffa4238a7c",
|
|
||||||
"https://deno.land/std@0.224.0/path/extname.ts": "593303db8ae8c865cbd9ceec6e55d4b9ac5410c1e276bfd3131916591b954441",
|
|
||||||
"https://deno.land/std@0.224.0/path/format.ts": "6ce1779b0980296cf2bc20d66436b12792102b831fd281ab9eb08fa8a3e6f6ac",
|
|
||||||
"https://deno.land/std@0.224.0/path/from_file_url.ts": "911833ae4fd10a1c84f6271f36151ab785955849117dc48c6e43b929504ee069",
|
|
||||||
"https://deno.land/std@0.224.0/path/glob_to_regexp.ts": "7f30f0a21439cadfdae1be1bf370880b415e676097fda584a63ce319053b5972",
|
|
||||||
"https://deno.land/std@0.224.0/path/is_absolute.ts": "4791afc8bfd0c87f0526eaa616b0d16e7b3ab6a65b62942e50eac68de4ef67d7",
|
|
||||||
"https://deno.land/std@0.224.0/path/is_glob.ts": "a65f6195d3058c3050ab905705891b412ff942a292bcbaa1a807a74439a14141",
|
|
||||||
"https://deno.land/std@0.224.0/path/join.ts": "ae2ec5ca44c7e84a235fd532e4a0116bfb1f2368b394db1c4fb75e3c0f26a33a",
|
|
||||||
"https://deno.land/std@0.224.0/path/join_globs.ts": "5b3bf248b93247194f94fa6947b612ab9d3abd571ca8386cf7789038545e54a0",
|
|
||||||
"https://deno.land/std@0.224.0/path/mod.ts": "f6bd79cb08be0e604201bc9de41ac9248582699d1b2ee0ab6bc9190d472cf9cd",
|
|
||||||
"https://deno.land/std@0.224.0/path/normalize.ts": "4155743ccceeed319b350c1e62e931600272fad8ad00c417b91df093867a8352",
|
|
||||||
"https://deno.land/std@0.224.0/path/normalize_glob.ts": "cc89a77a7d3b1d01053b9dcd59462b75482b11e9068ae6c754b5cf5d794b374f",
|
|
||||||
"https://deno.land/std@0.224.0/path/parse.ts": "77ad91dcb235a66c6f504df83087ce2a5471e67d79c402014f6e847389108d5a",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/_util.ts": "1e3937da30f080bfc99fe45d7ed23c47dd8585c5e473b2d771380d3a6937cf9d",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/basename.ts": "d2fa5fbbb1c5a3ab8b9326458a8d4ceac77580961b3739cd5bfd1d3541a3e5f0",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/constants.ts": "93481efb98cdffa4c719c22a0182b994e5a6aed3047e1962f6c2c75b7592bef1",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/dirname.ts": "76cd348ffe92345711409f88d4d8561d8645353ac215c8e9c80140069bf42f00",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/extname.ts": "e398c1d9d1908d3756a7ed94199fcd169e79466dd88feffd2f47ce0abf9d61d2",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/format.ts": "185e9ee2091a42dd39e2a3b8e4925370ee8407572cee1ae52838aed96310c5c1",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/from_file_url.ts": "951aee3a2c46fd0ed488899d024c6352b59154c70552e90885ed0c2ab699bc40",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/glob_to_regexp.ts": "76f012fcdb22c04b633f536c0b9644d100861bea36e9da56a94b9c589a742e8f",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/is_absolute.ts": "cebe561ad0ae294f0ce0365a1879dcfca8abd872821519b4fcc8d8967f888ede",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/join.ts": "7fc2cb3716aa1b863e990baf30b101d768db479e70b7313b4866a088db016f63",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/join_globs.ts": "a9475b44645feddceb484ee0498e456f4add112e181cb94042cdc6d47d1cdd25",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/mod.ts": "2301fc1c54a28b349e20656f68a85f75befa0ee9b6cd75bfac3da5aca9c3f604",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/normalize.ts": "baeb49816a8299f90a0237d214cef46f00ba3e95c0d2ceb74205a6a584b58a91",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/normalize_glob.ts": "9c87a829b6c0f445d03b3ecadc14492e2864c3ebb966f4cea41e98326e4435c6",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/parse.ts": "09dfad0cae530f93627202f28c1befa78ea6e751f92f478ca2cc3b56be2cbb6a",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/relative.ts": "3907d6eda41f0ff723d336125a1ad4349112cd4d48f693859980314d5b9da31c",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/resolve.ts": "08b699cfeee10cb6857ccab38fa4b2ec703b0ea33e8e69964f29d02a2d5257cf",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/to_file_url.ts": "7aa752ba66a35049e0e4a4be5a0a31ac6b645257d2e031142abb1854de250aaf",
|
|
||||||
"https://deno.land/std@0.224.0/path/posix/to_namespaced_path.ts": "28b216b3c76f892a4dca9734ff1cc0045d135532bfd9c435ae4858bfa5a2ebf0",
|
|
||||||
"https://deno.land/std@0.224.0/path/relative.ts": "ab739d727180ed8727e34ed71d976912461d98e2b76de3d3de834c1066667add",
|
|
||||||
"https://deno.land/std@0.224.0/path/resolve.ts": "a6f977bdb4272e79d8d0ed4333e3d71367cc3926acf15ac271f1d059c8494d8d",
|
|
||||||
"https://deno.land/std@0.224.0/path/to_file_url.ts": "88f049b769bce411e2d2db5bd9e6fd9a185a5fbd6b9f5ad8f52bef517c4ece1b",
|
|
||||||
"https://deno.land/std@0.224.0/path/to_namespaced_path.ts": "b706a4103b104cfadc09600a5f838c2ba94dbcdb642344557122dda444526e40",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/_util.ts": "d5f47363e5293fced22c984550d5e70e98e266cc3f31769e1710511803d04808",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/basename.ts": "6bbc57bac9df2cec43288c8c5334919418d784243a00bc10de67d392ab36d660",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/constants.ts": "5afaac0a1f67b68b0a380a4ef391bf59feb55856aa8c60dfc01bd3b6abb813f5",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/dirname.ts": "33e421be5a5558a1346a48e74c330b8e560be7424ed7684ea03c12c21b627bc9",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/extname.ts": "165a61b00d781257fda1e9606a48c78b06815385e7d703232548dbfc95346bef",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/format.ts": "bbb5ecf379305b472b1082cd2fdc010e44a0020030414974d6029be9ad52aeb6",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/from_file_url.ts": "ced2d587b6dff18f963f269d745c4a599cf82b0c4007356bd957cb4cb52efc01",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/glob_to_regexp.ts": "e45f1f89bf3fc36f94ab7b3b9d0026729829fabc486c77f414caebef3b7304f8",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/is_absolute.ts": "4a8f6853f8598cf91a835f41abed42112cebab09478b072e4beb00ec81f8ca8a",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/join.ts": "8d03530ab89195185103b7da9dfc6327af13eabdcd44c7c63e42e27808f50ecf",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/join_globs.ts": "a9475b44645feddceb484ee0498e456f4add112e181cb94042cdc6d47d1cdd25",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/mod.ts": "2301fc1c54a28b349e20656f68a85f75befa0ee9b6cd75bfac3da5aca9c3f604",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/normalize_glob.ts": "9c87a829b6c0f445d03b3ecadc14492e2864c3ebb966f4cea41e98326e4435c6",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/parse.ts": "08804327b0484d18ab4d6781742bf374976de662f8642e62a67e93346e759707",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/relative.ts": "3e1abc7977ee6cc0db2730d1f9cb38be87b0ce4806759d271a70e4997fc638d7",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/resolve.ts": "8dae1dadfed9d46ff46cc337c9525c0c7d959fb400a6308f34595c45bdca1972",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/to_file_url.ts": "40e560ee4854fe5a3d4d12976cef2f4e8914125c81b11f1108e127934ced502e",
|
|
||||||
"https://deno.land/std@0.224.0/path/windows/to_namespaced_path.ts": "4ffa4fb6fae321448d5fe810b3ca741d84df4d7897e61ee29be961a6aac89a4c",
|
|
||||||
"https://vanjs.org/code/van-1.5.5.nomodule.min.js": "32403d4dd6203a46513f000fd64b18e4eaef0823bf757ca0092e70130d059aa3",
|
|
||||||
"https://vanjs.org/code/van-x-0.6.3.nomodule.min.js": "e4b7de89bf2f84c22669ce7bcef592fb398d9dcf8b8a36f4562b8ac6354b1f2f"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
dist/bundle_entry.js
vendored
3
dist/bundle_entry.js
vendored
File diff suppressed because one or more lines are too long
31
hmr/hmr-listen.tsx
Normal file
31
hmr/hmr-listen.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { HMR } from "./hmr-react.tsx";
|
||||||
|
import { GroupSignal, GroupSignalHook } from "./hmr-signal.tsx";
|
||||||
|
|
||||||
|
const FileListeners = new Map() as Map<string, Array<(module:unknown)=>void>>;
|
||||||
|
export const FileListen =(inPath:string, inHandler:()=>void)=>
|
||||||
|
{
|
||||||
|
const members = FileListeners.get(inPath)??[];
|
||||||
|
members.push(inHandler);
|
||||||
|
FileListeners.set(inPath, members);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Socket:WebSocket = new WebSocket("ws://"+document.location.host);
|
||||||
|
Socket.addEventListener('message', async(event:{data:string})=>
|
||||||
|
{
|
||||||
|
// When a file changes, dynamically re-import it to get the updated members
|
||||||
|
// send the updated members to any listeners for that file
|
||||||
|
|
||||||
|
GroupSignal.reset();
|
||||||
|
|
||||||
|
const reImport = await import(document.location.origin+event.data+"?reload="+Math.random());
|
||||||
|
FileListeners.get(event.data)?.forEach(reExport=>reExport(reImport));
|
||||||
|
|
||||||
|
GroupSignal.swap();
|
||||||
|
|
||||||
|
GroupSignalHook.reset();
|
||||||
|
HMR.update();
|
||||||
|
GroupSignalHook.reset();
|
||||||
|
|
||||||
|
});
|
||||||
|
Socket.addEventListener("error", ()=>{clearInterval(SocketTimer); console.log("HMR socket lost")})
|
||||||
|
const SocketTimer = setInterval(()=>{Socket.send("ping")}, 5000);
|
176
hmr/hmr-react.tsx
Normal file
176
hmr/hmr-react.tsx
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
import * as ReactParts from "react-original";
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Each custom component is secretly modified to have an extra state and id.
|
||||||
|
When there is an HMR update, this state is changed, forcing it to re-render.
|
||||||
|
|
||||||
|
Each *user-created* React.useState is secretly modified and accompanied by an ID.
|
||||||
|
Every time its state is set, the HMR.statesNew map for this ID is set to contain the new state and updater.
|
||||||
|
When a component is removed, any of it's states in HMR.statesNew are also removed.
|
||||||
|
(HMR.statesNew is the "running total" of all states currently at play).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
When a state is interacted with:
|
||||||
|
- statesNew for this id is set
|
||||||
|
- the internal state is also set in the traditional way
|
||||||
|
|
||||||
|
When there is an HMR update:
|
||||||
|
- All custom components are re-rendered...
|
||||||
|
for each useState(value) call that then happens in the re-render:
|
||||||
|
- if there is a "statesOld" value for this state, use that and ignore the passed value, otherwise use the passed value
|
||||||
|
- if this state has not been interacted with since the last reload (statesNew is empty at this id), set statesNew<id> with whatever is in statesOld<id>
|
||||||
|
- statesNew is moved into *statesOld*
|
||||||
|
- statesNew is cleared.
|
||||||
|
|
||||||
|
*/
|
||||||
|
export const HMR =
|
||||||
|
{
|
||||||
|
reloads:1,
|
||||||
|
RegisteredComponents: new Map() as Map<string, ()=>void>,
|
||||||
|
statesNew: new Map() as Map<string, StateCapture>,
|
||||||
|
statesOld: new Map() as Map<string, StateCapture>,
|
||||||
|
wireframe: false,
|
||||||
|
RegisterComponent(reactID:string, value:()=>void):void
|
||||||
|
{
|
||||||
|
this.RegisteredComponents.set(reactID, value);
|
||||||
|
},
|
||||||
|
update()
|
||||||
|
{
|
||||||
|
this.reloads++;
|
||||||
|
this.RegisteredComponents.forEach(handler=>handler());
|
||||||
|
this.RegisteredComponents.clear();
|
||||||
|
this.statesOld = this.statesNew;
|
||||||
|
this.statesNew = new Map();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type StateType = boolean|number|string|Record<string, string>
|
||||||
|
export type StateCapture = {state:StateType, set:ReactParts.StateUpdater<StateType>, reload:number};
|
||||||
|
type FuncArgs = [element:keyof ReactParts.JSX.IntrinsicElements, props:Record<string, string>, children:ReactParts.JSX.Element[]];
|
||||||
|
|
||||||
|
|
||||||
|
const H = ReactParts.createElement;
|
||||||
|
const MapIndex =(inMap:Map<string, StateCapture>, inIndex:number)=>
|
||||||
|
{
|
||||||
|
let index = 0;
|
||||||
|
for(const kvp of inMap)
|
||||||
|
{
|
||||||
|
if(index == inIndex)
|
||||||
|
{
|
||||||
|
return kvp;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ProxyCreate =(...args:FuncArgs)=> (typeof args[0] == "string") ? H(...args) : H(ProxyElement, {__args:args, ...args[1]});
|
||||||
|
|
||||||
|
const ProxyElement = (props:{__args:FuncArgs})=>
|
||||||
|
{
|
||||||
|
const [stateGet, stateSet] = ReactParts.useState(0);
|
||||||
|
const id = ReactParts.useId();
|
||||||
|
HMR.RegisterComponent(id, ()=>stateSet(stateGet+1));
|
||||||
|
|
||||||
|
const child = H(...props.__args);
|
||||||
|
|
||||||
|
if(HMR.wireframe)
|
||||||
|
{
|
||||||
|
return H("div", {style:{padding:"10px", border:"2px solid red"}},
|
||||||
|
H("p", null, stateGet),
|
||||||
|
child
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ProxyState =(argNew:StateType)=>
|
||||||
|
{
|
||||||
|
// does statesOld have an entry for this state? use that instead of the passed arg
|
||||||
|
const check = MapIndex(HMR.statesOld, HMR.statesNew.size);
|
||||||
|
const argOld = check ? check[1].state : argNew;
|
||||||
|
|
||||||
|
const id = ReactParts.useId();
|
||||||
|
const [stateGet, stateSet] = ReactParts.useState(argOld);
|
||||||
|
|
||||||
|
// state updates due to clicks, interactivity, etc. since the last reload may already be in statesNew for this slot.
|
||||||
|
// DONT overwrite it.
|
||||||
|
if(!HMR.statesNew.get(id))
|
||||||
|
{
|
||||||
|
HMR.statesNew.set(id, {state:stateGet, set:stateSet, reload:HMR.reloads});
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastKnowReloads = HMR.reloads;
|
||||||
|
ReactParts.useEffect(()=>{
|
||||||
|
return ()=>{
|
||||||
|
if(HMR.reloads == lastKnowReloads)/*i have no idea what this does. this may have to be re-introduced when routing is added*/
|
||||||
|
{
|
||||||
|
// this is a switch/ui change, not a HMR reload change
|
||||||
|
const oldState = MapIndex(HMR.statesOld, HMR.statesNew.size-1);
|
||||||
|
oldState && HMR.statesOld.set(oldState[0], {...oldState[1], state:argNew});
|
||||||
|
}
|
||||||
|
|
||||||
|
HMR.statesNew.delete(id);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
// do we need to account for the function set?
|
||||||
|
function proxySetter ( inArg:StateType|((old:StateType)=>StateType) )
|
||||||
|
{
|
||||||
|
const stateUser = {state:inArg as StateType, set:stateSet, reload:HMR.reloads};
|
||||||
|
if(typeof inArg == "function")
|
||||||
|
{
|
||||||
|
//const passedFunction = inArg;
|
||||||
|
stateSet((oldState:StateType)=>
|
||||||
|
{
|
||||||
|
const output = inArg(oldState);
|
||||||
|
stateUser.state = output;
|
||||||
|
HMR.statesNew.set(id, stateUser);
|
||||||
|
return output;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HMR.statesNew.set(id, stateUser);
|
||||||
|
stateSet(inArg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [stateGet, proxySetter];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type Storelike = Record<string, string>
|
||||||
|
const ProxyReducer =(inReducer:(inState:Storelike, inAction:string)=>Storelike, inState:Storelike, inInit?:(inState:Storelike)=>Storelike)=>
|
||||||
|
{
|
||||||
|
const check = MapIndex(HMR.statesOld, HMR.statesNew.size);
|
||||||
|
const argOld = check ? check[1].state : (inInit ? inInit(inState) : inState);
|
||||||
|
|
||||||
|
const intercept =(inInterceptState:Storelike, inInterceptAction:string)=>
|
||||||
|
{
|
||||||
|
const capture = inReducer(inInterceptState, inInterceptAction);
|
||||||
|
const stateUser = {state:capture, set:()=>{}, reload:HMR.reloads};
|
||||||
|
HMR.statesNew.set(id, stateUser);
|
||||||
|
return capture;
|
||||||
|
};
|
||||||
|
|
||||||
|
const id = ReactParts.useId();
|
||||||
|
const [state, dispatch] = ReactParts.useReducer(intercept, argOld as Storelike);
|
||||||
|
|
||||||
|
if(!HMR.statesNew.get(id))
|
||||||
|
{
|
||||||
|
HMR.statesNew.set(id, {state:state, set:()=>{}, reload:HMR.reloads});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [state, dispatch];
|
||||||
|
};
|
||||||
|
|
||||||
|
export * from "react-original";
|
||||||
|
export {ProxyCreate as createElement, ProxyState as useState, ProxyReducer as useReducer };
|
||||||
|
export default {...ReactParts, createElement:ProxyCreate, useState:ProxyState, useReducer:ProxyReducer};
|
47
hmr/hmr-signal.tsx
Normal file
47
hmr/hmr-signal.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import * as SignalsParts from "signals-original";
|
||||||
|
import DeepEqual from "https://esm.sh/deep-eql@4.1.3";
|
||||||
|
|
||||||
|
type Entry<T> = [signal:SignalsParts.Signal<T>, initArg:T];
|
||||||
|
|
||||||
|
function ProxyGroup<T>(inFunc:(initArg:T)=>SignalsParts.Signal<T>)
|
||||||
|
{
|
||||||
|
let recordEntry:Entry<T>[] = [];
|
||||||
|
let recordEntryNew:Entry<T>[] = [];
|
||||||
|
let recordIndex = 0;
|
||||||
|
const reset =()=> recordIndex = 0;
|
||||||
|
const swap =()=>
|
||||||
|
{
|
||||||
|
recordEntry = recordEntryNew;
|
||||||
|
recordEntryNew = [] as Entry<T>[];
|
||||||
|
};
|
||||||
|
const proxy =(arg:T)=>
|
||||||
|
{
|
||||||
|
const lookupOld = recordEntry[recordIndex];
|
||||||
|
if(lookupOld && DeepEqual(lookupOld[1], arg))
|
||||||
|
{
|
||||||
|
recordEntryNew[recordIndex] = lookupOld;
|
||||||
|
recordIndex++;
|
||||||
|
return lookupOld[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const sig = inFunc(arg);
|
||||||
|
recordEntryNew[recordIndex] = [sig, arg];
|
||||||
|
recordEntry[recordIndex] = [sig, arg];
|
||||||
|
recordIndex++;
|
||||||
|
return sig;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return {reset, swap, proxy};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GroupSignal = ProxyGroup(SignalsParts.signal);
|
||||||
|
export const GroupSignalHook = ProxyGroup(SignalsParts.useSignal);
|
||||||
|
|
||||||
|
|
||||||
|
const proxySignal = GroupSignal.proxy;
|
||||||
|
const proxySignalHook = GroupSignalHook.proxy;
|
||||||
|
|
||||||
|
export * from "signals-original";
|
||||||
|
export { proxySignal as signal, proxySignalHook as useSignal };
|
||||||
|
export default {...SignalsParts, signal:proxySignal, useSignal:proxySignalHook};
|
144
hmr/hmr-static.tsx
Normal file
144
hmr/hmr-static.tsx
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
type GlyphCheck = (inGlyph:string)=>boolean
|
||||||
|
const isAlphaLike:GlyphCheck =(inGlyph:string)=>
|
||||||
|
{
|
||||||
|
const inCode = inGlyph.charCodeAt(0);
|
||||||
|
|
||||||
|
if(inCode >= 97 && inCode <= 122)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(inCode >= 65 && inCode <= 90)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `$_.`.includes(inGlyph);
|
||||||
|
}
|
||||||
|
const isWhiteSpace:GlyphCheck =(inGlyph:string)=> `\n\r\t `.includes(inGlyph);
|
||||||
|
const isQuote:GlyphCheck =(inGlyph:string)=>`"'\``.includes(inGlyph)
|
||||||
|
const isNot =(inCheck:GlyphCheck)=> (inGlyph:string)=>!inCheck(inGlyph);
|
||||||
|
const contiguous =(inText:string, inStart:number, inTest:GlyphCheck):number=>
|
||||||
|
{
|
||||||
|
let ok = true;
|
||||||
|
let index = inStart;
|
||||||
|
let count = 0;
|
||||||
|
while(ok && count < inText.length)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
ok = inTest(inText.charAt(index++));
|
||||||
|
}
|
||||||
|
return index-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const findNextExport =(inFile:string, inIndex=0, inLocal:Array<string>, inForeign:Array<string>)=>
|
||||||
|
{
|
||||||
|
const pos = inFile.indexOf("export", inIndex);
|
||||||
|
if(pos !== -1)
|
||||||
|
{
|
||||||
|
if(!isAlphaLike(inFile.charAt(pos-1)) || !isAlphaLike(inFile.charAt(pos+6)))
|
||||||
|
{
|
||||||
|
|
||||||
|
const nextCharInd = contiguous(inFile, pos+6, isWhiteSpace);
|
||||||
|
const nextChar = inFile[nextCharInd];
|
||||||
|
|
||||||
|
//console.log(inFile.substring(pos, nextCharInd+1), `>>${nextChar}<<`)
|
||||||
|
|
||||||
|
if(nextChar === "*")
|
||||||
|
{
|
||||||
|
const firstQuoteInd = contiguous(inFile, nextCharInd+1, isNot(isQuote) );
|
||||||
|
const secondQuoteInd = contiguous(inFile, firstQuoteInd+1, isNot(isQuote) );
|
||||||
|
//console.log("ASTERISK:", inFile.substring(pos, secondQuoteInd+1));
|
||||||
|
inForeign.push(inFile.substring(nextCharInd, secondQuoteInd+1));
|
||||||
|
}
|
||||||
|
else if(nextChar == "{")
|
||||||
|
{
|
||||||
|
const endBracketInd = contiguous(inFile, nextCharInd, (inGlyph:string)=>inGlyph!=="}");
|
||||||
|
const nextLetterInd = contiguous(inFile, endBracketInd+1, isWhiteSpace);
|
||||||
|
if(inFile.substring(nextLetterInd, nextLetterInd+4) == "from")
|
||||||
|
{
|
||||||
|
const firstQuoteInd = contiguous(inFile, nextLetterInd+4, isNot(isQuote) );
|
||||||
|
const secondQuoteInd = contiguous(inFile, firstQuoteInd+1, isNot(isQuote) );
|
||||||
|
//console.log(`BRACKET foreign: >>${inFile.substring(nextCharInd, secondQuoteInd+1)}<<`);
|
||||||
|
inForeign.push(inFile.substring(nextCharInd, secondQuoteInd+1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const members = inFile.substring(nextCharInd+1, endBracketInd).replace(/\s/g, '');
|
||||||
|
members.split(",").forEach(part=>
|
||||||
|
{
|
||||||
|
const renamed = part.split(" as ");
|
||||||
|
inLocal.push(renamed[1] || renamed[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(isAlphaLike(nextChar))
|
||||||
|
{
|
||||||
|
const keywordEndInd = contiguous(inFile, nextCharInd, isAlphaLike);
|
||||||
|
const keyword = inFile.substring(nextCharInd, keywordEndInd);
|
||||||
|
if(keyword === "default")
|
||||||
|
{
|
||||||
|
inLocal.push(keyword);
|
||||||
|
//console.log(`MEMBER: >>${keyword})}<<`);
|
||||||
|
}
|
||||||
|
else if(["const", "let", "var", "function", "class"].includes(keyword))
|
||||||
|
{
|
||||||
|
const varStartInd = contiguous(inFile, keywordEndInd+1, isWhiteSpace);
|
||||||
|
const varEndInd = contiguous(inFile, varStartInd+1, isAlphaLike);
|
||||||
|
//console.log(`MEMBER: >>${inFile.substring(varStartInd, varEndInd)}<<`);
|
||||||
|
inLocal.push(inFile.substring(varStartInd, varEndInd))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos + 7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ModuleShape =(inText:string)=>
|
||||||
|
{
|
||||||
|
let match = 0 as number|false;
|
||||||
|
let count = 0;
|
||||||
|
const local = [] as string[];
|
||||||
|
const foreign = [] as string[];
|
||||||
|
while(match !== false && count <200)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
match = findNextExport(inText, match, local, foreign);
|
||||||
|
}
|
||||||
|
return[local, foreign] as [local:string[], foreign:string[]];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ModuleProxy =(inText:string, inPath:string)=>
|
||||||
|
{
|
||||||
|
const [local, foreign] = ModuleShape(inText);
|
||||||
|
console.log("shape local", local);
|
||||||
|
return `
|
||||||
|
import {FileListen} from ">/hmr/hmr-listen.tsx";
|
||||||
|
import * as Import from "${inPath}?reload=${new Date().getTime()}";
|
||||||
|
${ local.map(m=>`let proxy_${m} = Import.${m}; export { proxy_${m} as ${m} };`).join("\n") }
|
||||||
|
FileListen("${inPath}", (updatedModule)=>
|
||||||
|
{
|
||||||
|
${ local.map(m=>`proxy_${m} = updatedModule.${m};`).join("\n") }
|
||||||
|
});
|
||||||
|
${ foreign.join(";\n") }`;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ///////////////////////////////////////////////
|
||||||
|
// const [local, global] = Exports(`
|
||||||
|
// // export in comment
|
||||||
|
// export * from "react";
|
||||||
|
// const fakeexport =()=>{};
|
||||||
|
// export{ thing1 as remapped, thing2}
|
||||||
|
// export { thing1 as remapped, thing2} from 'React';
|
||||||
|
// export
|
||||||
|
// export const func=()=>{};
|
||||||
|
// `);
|
||||||
|
//
|
||||||
|
// console.log(local, global);
|
@ -1,8 +1,12 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
</head>
|
</head>
|
||||||
<body></body>
|
<body>
|
||||||
|
<script type="module">
|
||||||
|
import App from ">/app.tsx";
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,13 +0,0 @@
|
|||||||
export const Root = import.meta.resolve("../");
|
|
||||||
export const Load =async(file:string)=> await fetch(Root + file).then(resp=>resp.text());
|
|
||||||
export const Save =async(text:string, name:string)=> await Deno.writeTextFile(name, text);
|
|
||||||
|
|
||||||
const index = await Load("index.html");
|
|
||||||
|
|
||||||
export const HTML = index.replace(
|
|
||||||
`</head>`,
|
|
||||||
`
|
|
||||||
<style>*{margin:0;padding:0;box-sizing:border-box;}html, body{height:100%;width:100%;font-family:Arial, sans-serif;line-height:1.6;}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}img, video{max-width:100%;height:auto;}a{text-decoration:none;color:inherit;}ul, ol{list-style:none;}button, input, textarea{font-family:inherit;font-size:inherit;line-height:inherit;border:none;background:none;padding:0;margin:0;outline:none;}table{border-collapse:collapse;width:100%;}</style>
|
|
||||||
<script type="module" src="/proxy/dist/bundle_entry.js?hmr&map"}"></script>
|
|
||||||
</head>`);
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
|||||||
export interface DenoBundleOptions {
|
|
||||||
entry: string;
|
|
||||||
output?: string;
|
|
||||||
outdir?: string;
|
|
||||||
check?: boolean | "all";
|
|
||||||
noCheck?: boolean | "remote";
|
|
||||||
frozen?: boolean;
|
|
||||||
importMap?: string;
|
|
||||||
lock?: string;
|
|
||||||
noLock?: boolean;
|
|
||||||
noNpm?: boolean;
|
|
||||||
noRemote?: boolean;
|
|
||||||
nodeModulesDir?: boolean;
|
|
||||||
reload?: boolean | string[];
|
|
||||||
vendor?: boolean;
|
|
||||||
allowImport?: string[];
|
|
||||||
allowScripts?: string[];
|
|
||||||
cert?: string;
|
|
||||||
codeSplitting?: boolean;
|
|
||||||
conditions?: string[];
|
|
||||||
config?: string;
|
|
||||||
denyImport?: string[];
|
|
||||||
inlineImports?: boolean;
|
|
||||||
minify?: boolean;
|
|
||||||
noConfig?: boolean;
|
|
||||||
packages?: "bundle" | "external";
|
|
||||||
platform?: "browser" | "deno";
|
|
||||||
preload?: string[];
|
|
||||||
sourcemap?: "linked" | "inline" | "external";
|
|
||||||
watch?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (options: DenoBundleOptions):{ out: string; err: string; }=>
|
|
||||||
{
|
|
||||||
const argify =(str: string)=> "--"+str.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
|
|
||||||
const args: string[] = ["bundle"];
|
|
||||||
const { entry, ...rest } = options;
|
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(rest))
|
|
||||||
{
|
|
||||||
let flag = argify(key);
|
|
||||||
if (value !== true)
|
|
||||||
{
|
|
||||||
if(!value)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
flag = flag + "=" + (Array.isArray(value) ? value.join(",") : value);
|
|
||||||
}
|
|
||||||
args.push(flag);
|
|
||||||
}
|
|
||||||
args.push(entry);
|
|
||||||
|
|
||||||
console.log(args);
|
|
||||||
|
|
||||||
const command = new Deno.Command("deno", {args});
|
|
||||||
const result = command.outputSync();
|
|
||||||
const decode = new TextDecoder("utf-8");
|
|
||||||
const output = (str:Uint8Array<ArrayBuffer>)=> decode.decode(str).replace(/\x1b\[[0-9;]*m/g,"").replace(/\n+$/, "");
|
|
||||||
return { out: output(result.stdout), err: output(result.stderr) }
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
import Van from "npm:vanjs-core@^1.5.5";
|
|
||||||
globalThis.van = Van;
|
|
||||||
|
|
||||||
import * as VanX from "npm:vanjs-ext@^0.6.3";
|
|
||||||
globalThis.vanX = VanX;
|
|
||||||
|
|
||||||
import Gale from "../src/gale.js";
|
|
||||||
globalThis.Gale = Gale;
|
|
||||||
|
|
||||||
const args = new URL(import.meta.url).searchParams;
|
|
||||||
|
|
||||||
//Store
|
|
||||||
vanX.Store=(e,t)=>{const a=localStorage.getItem(t),r=vanX.reactive(a?JSON.parse(a):e);return van.derive((()=>localStorage.setItem(t,JSON.stringify(vanX.compact(r))))),r};
|
|
||||||
|
|
||||||
if(args.has("hmr"))
|
|
||||||
{
|
|
||||||
const path = "/proxy/"+"src/hmr.js";
|
|
||||||
await import(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
const root = args.get("root")||"/";
|
|
||||||
fetch(root+"deno.json")
|
|
||||||
.then(text=>text.json())
|
|
||||||
.then(json=>{
|
|
||||||
const Script=(t,e)=>{let n=document.createElement("script"); n.type=t; n.textContent=e; document.head.appendChild(n); return n;};
|
|
||||||
const imports = json.imports;
|
|
||||||
for(let n in imports)
|
|
||||||
{
|
|
||||||
const path=imports[n];
|
|
||||||
path.startsWith("./")&&(imports[n]=root+path.substring(2))
|
|
||||||
}
|
|
||||||
args.has("map") && Script("importmap",JSON.stringify({imports}));
|
|
||||||
Script("module", "").src=imports["GALE@ENTRY"];
|
|
||||||
});
|
|
@ -1,13 +0,0 @@
|
|||||||
import Bundler from "./bundle.ts";
|
|
||||||
|
|
||||||
const result = Bundler({
|
|
||||||
entry: "scripts/bundle_entry.ts",
|
|
||||||
outdir: "dist",
|
|
||||||
inlineImports: true,
|
|
||||||
minify: true,
|
|
||||||
codeSplitting: true,
|
|
||||||
platform: "browser",
|
|
||||||
noLock: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(result);
|
|
@ -1,80 +0,0 @@
|
|||||||
import { contentType } from "jsr:@std/media-types";
|
|
||||||
import {HTML, Root} from "./assemble_files.ts";
|
|
||||||
|
|
||||||
// Parse the port from the command-line arguments, defaulting to 8000
|
|
||||||
const port = parseInt(Deno.args[0] || "8000", 10);
|
|
||||||
const sockets: WebSocket[] = [];
|
|
||||||
|
|
||||||
function extension(path: string): string {
|
|
||||||
// Remove trailing slash if it exists
|
|
||||||
const normalizedPath = path.endsWith("/") ? path.slice(0, -1) : path;
|
|
||||||
// Get the last part of the path
|
|
||||||
const lastPart = normalizedPath.split("/").pop() || "";
|
|
||||||
// Check if the last part contains a "."
|
|
||||||
return lastPart.split(".")[1] || "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the HTTP server using Deno.serve
|
|
||||||
Deno.serve({ port }, async (req: Request) => {
|
|
||||||
const path = new URL(req.url).pathname;
|
|
||||||
|
|
||||||
// Handle WebSocket connections
|
|
||||||
if (path === "/ws") {
|
|
||||||
const { socket, response } = Deno.upgradeWebSocket(req);
|
|
||||||
sockets.push(socket);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serve static files or the predefined HTML for non-file routes
|
|
||||||
const ext = extension(path);
|
|
||||||
|
|
||||||
// Serve the predefined HTML for non-file routes
|
|
||||||
if (!ext) {
|
|
||||||
return new Response(HTML, {
|
|
||||||
headers: { "Content-Type": "text/html" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const proxyPrefix = "/proxy/";
|
|
||||||
let streamable;
|
|
||||||
if(path.startsWith(proxyPrefix))
|
|
||||||
{
|
|
||||||
const file = await fetch(Root + path.slice(proxyPrefix.length));
|
|
||||||
streamable = file.body;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const file = await Deno.open("." + path, { read: true });
|
|
||||||
streamable = file.readable;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response(streamable, {
|
|
||||||
headers: { "Content-Type": contentType(ext) || "application/javascript" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (err)
|
|
||||||
{
|
|
||||||
if (err instanceof Deno.errors.NotFound) {
|
|
||||||
return new Response("File not found", { status: 404 });
|
|
||||||
} else {
|
|
||||||
return new Response("Internal server error", { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Start watching for file changes
|
|
||||||
const watcher = Deno.watchFs(".");
|
|
||||||
for await (const event of watcher) {
|
|
||||||
if (event.kind === "modify") {
|
|
||||||
for (const ws of sockets) {
|
|
||||||
if (ws.readyState === WebSocket.OPEN) {
|
|
||||||
ws.send("reload");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
import { resolve, toFileUrl } from "https://deno.land/std/path/mod.ts";
|
|
||||||
|
|
||||||
async function main()
|
|
||||||
{
|
|
||||||
// Read and parse the deno.json file
|
|
||||||
const denoJson = JSON.parse(await Deno.readTextFile("./deno.json"));
|
|
||||||
|
|
||||||
// Check if compilerOptions and types are defined
|
|
||||||
if (denoJson.compilerOptions?.types)
|
|
||||||
{
|
|
||||||
const types:string[] = denoJson.compilerOptions.types;
|
|
||||||
|
|
||||||
// Iterate over each type file and cache it
|
|
||||||
for (const typeFile of types)
|
|
||||||
{
|
|
||||||
let lookup:string = typeFile;
|
|
||||||
console.log(`found ambient type file`, lookup);
|
|
||||||
|
|
||||||
if(typeFile.startsWith("."))
|
|
||||||
{
|
|
||||||
lookup = toFileUrl(resolve(Deno.cwd(), typeFile)).href;
|
|
||||||
}
|
|
||||||
console.log(`Scan found types: ${lookup}`);
|
|
||||||
await import(lookup); // This will cache the file
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Scan complete; be sure to restart the Deno Language Server!!");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
console.log("No types found in compilerOptions.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main().catch((error) => {
|
|
||||||
console.error("Error:", error);
|
|
||||||
Deno.exit(1);
|
|
||||||
});
|
|
@ -1,16 +0,0 @@
|
|||||||
import { parseArgs } from "jsr:@std/cli/parse-args";
|
|
||||||
import {HTML, Save, Load, Root} from "./assemble_files.ts";
|
|
||||||
|
|
||||||
const args = parseArgs(Deno.args);
|
|
||||||
if(args.html)
|
|
||||||
{
|
|
||||||
Save(HTML, "index.html");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const config = await Load("deno.json");
|
|
||||||
const json = JSON.parse(config);
|
|
||||||
json.imports["GALE@HOST/"] = Root;
|
|
||||||
Save(JSON.stringify(json, null, "\t"), "deno.json");
|
|
||||||
Save(await Load("app.js"), "app.js");
|
|
||||||
}
|
|
140
server.ts
Normal file
140
server.ts
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
import { ModuleProxy } from "./hmr/hmr-static.tsx";
|
||||||
|
|
||||||
|
const keyProxy = encodeURI(">");
|
||||||
|
const keyAdjacent = "^";
|
||||||
|
const keyReload = "reload";
|
||||||
|
const keysRemote = ["npm:", "jsr:", "http"];
|
||||||
|
const keysExtension = ["ts", "tsx"];
|
||||||
|
const extractExtension =(path)=>
|
||||||
|
{
|
||||||
|
return path.substring(path.lastIndexOf(".")+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const RootRunning = new URL(`file://${Deno.cwd()}`).toString();
|
||||||
|
const RootSiblings = import.meta.resolve("./");
|
||||||
|
|
||||||
|
console.log(RootRunning);
|
||||||
|
console.log(RootSiblings);
|
||||||
|
|
||||||
|
const bakeConfigPackage:Deno.bundle.Options =
|
||||||
|
{
|
||||||
|
entrypoints:[""],
|
||||||
|
platform: "browser",
|
||||||
|
write: false,
|
||||||
|
minify: true,
|
||||||
|
}
|
||||||
|
const bakeConfigLocal:Deno.bundle.Options = {...bakeConfigPackage, minify:false, sourcemap:"inline", inlineImports:false };
|
||||||
|
async function BakeForce(path:string, type?:"package")
|
||||||
|
{
|
||||||
|
console.log("baking", path);
|
||||||
|
const config = type ? bakeConfigPackage : bakeConfigLocal;
|
||||||
|
config.entrypoints[0] = type ? path : RootRunning+path;
|
||||||
|
const result = await Deno.bundle(config);
|
||||||
|
|
||||||
|
if(result.outputFiles)
|
||||||
|
{
|
||||||
|
const body = result.outputFiles.map(file=>file.text()).join("\n");
|
||||||
|
const save:CachedTranspile = [body, type ? "" : ModuleProxy(body, path)];
|
||||||
|
BakeCache[path] = save;
|
||||||
|
return save;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
async function BakeCheck(path:string, type?:"package")
|
||||||
|
{
|
||||||
|
const lookup:CachedTranspile = await BakeCache[path];
|
||||||
|
if(!lookup)
|
||||||
|
{
|
||||||
|
return BakeForce(path, type);
|
||||||
|
}
|
||||||
|
return lookup;
|
||||||
|
}
|
||||||
|
type CachedTranspile = [file:string, profile:string]
|
||||||
|
const BakeCache:Record<string, CachedTranspile> = {}
|
||||||
|
|
||||||
|
|
||||||
|
const JSResponse =(body:string)=>new Response(body, {headers:{"content-type":"application/javascript"}});
|
||||||
|
|
||||||
|
Deno.serve(async(req:Request)=>
|
||||||
|
{
|
||||||
|
const url = new URL(req.url);
|
||||||
|
const parts = url.pathname.split("/").filter(part=>part);
|
||||||
|
|
||||||
|
const lastPart = parts.at(-1);
|
||||||
|
const extension = extractExtension(lastPart);
|
||||||
|
|
||||||
|
console.log("REQUEST:", parts, extension);
|
||||||
|
|
||||||
|
if(parts[0] == keyProxy)
|
||||||
|
{
|
||||||
|
const proxiedPath = parts.slice(1).join("/");
|
||||||
|
console.log("PROXIED:", proxiedPath);
|
||||||
|
const transpiled = await BakeCheck(proxiedPath, "package");
|
||||||
|
return JSResponse(transpiled[0]);
|
||||||
|
}
|
||||||
|
if(keysExtension.includes(extension))
|
||||||
|
{
|
||||||
|
const transpiled = await BakeCheck(url.pathname);
|
||||||
|
return JSResponse(transpiled[url.searchParams.has(keyReload) ? 0 : 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req.headers.get("upgrade") == "websocket")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const { response, socket } = Deno.upgradeWebSocket(req);
|
||||||
|
socket.onopen = () => SocketsLive.add(socket);
|
||||||
|
socket.onclose = () => SocketsLive.delete(socket);
|
||||||
|
socket.onmessage = () => {};
|
||||||
|
socket.onerror = (e) => console.log("Socket errored:", e);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch(e){ console.log("Socket errored:", e); }
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response();
|
||||||
|
});
|
||||||
|
|
||||||
|
const SocketsLive:Set<WebSocket> = new Set();
|
||||||
|
const SocketsSend =(inData:string)=>{ for (const socket of SocketsLive){ socket.send(inData); } }
|
||||||
|
|
||||||
|
const Watcher =async()=>
|
||||||
|
{
|
||||||
|
let blocking = false;
|
||||||
|
const filesChanged:Map<string, string> = new Map();
|
||||||
|
for await (const event of Deno.watchFs(Deno.cwd()))
|
||||||
|
{
|
||||||
|
event.paths.forEach( path => filesChanged.set(path, event.kind) );
|
||||||
|
if(!blocking)
|
||||||
|
{
|
||||||
|
blocking = true;
|
||||||
|
setTimeout(async()=>
|
||||||
|
{
|
||||||
|
for await (const [path, action] of filesChanged)
|
||||||
|
{
|
||||||
|
const extension = extractExtension(path);
|
||||||
|
|
||||||
|
if(keysExtension.includes(extension))
|
||||||
|
{
|
||||||
|
console.log("File change", path);
|
||||||
|
const key = path.substring(Deno.cwd().length).replaceAll("\\", "/");
|
||||||
|
if(action != "remove")
|
||||||
|
{
|
||||||
|
BakeForce(path);
|
||||||
|
SocketsSend(key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete BakeCache[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filesChanged.clear();
|
||||||
|
blocking = false;
|
||||||
|
}
|
||||||
|
, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Watcher();
|
43
shadow.html
43
shadow.html
@ -1,43 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Shadow DOM Example</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// Define the custom web component
|
|
||||||
class APP extends HTMLElement {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
// Attach a shadow root to the custom element
|
|
||||||
const shadowRoot = this.attachShadow({ mode: 'open' });
|
|
||||||
|
|
||||||
// Add custom markup and styles to the shadow root
|
|
||||||
shadowRoot.innerHTML = `
|
|
||||||
<style>
|
|
||||||
.shadow-content {
|
|
||||||
color: white;
|
|
||||||
background-color: black;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div class="shadow-content">
|
|
||||||
This is content inside the shadow root of a web component.
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the custom element
|
|
||||||
customElements.define('gale-app', APP);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<gale-app></gale-app>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,54 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
Sheet({
|
|
||||||
fontSize:`12px`
|
|
||||||
},{
|
|
||||||
1024:
|
|
||||||
{
|
|
||||||
fontSize:`14px`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
function Prox()
|
|
||||||
{
|
|
||||||
const obj = new Proxy({}, {
|
|
||||||
get(target, propName, receiver)
|
|
||||||
{
|
|
||||||
console.log("get:", propName)
|
|
||||||
return obj;
|
|
||||||
},
|
|
||||||
set(target, propName, value, receiver)
|
|
||||||
{
|
|
||||||
console.log("set:", propName)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// const sheet = {};
|
|
||||||
//
|
|
||||||
// sheet
|
|
||||||
// .Font.size`8px`.color`#aabbcc`
|
|
||||||
// [512]
|
|
||||||
// .Font.size`10px`
|
|
||||||
// [1024]
|
|
||||||
// .Font.size`12px`
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// sheet(1024,
|
|
||||||
// Font.size`12px`.color`#aabbcc`
|
|
||||||
// )(512,
|
|
||||||
// Font.size`10px`);
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
const p1 = Prox();
|
|
||||||
|
|
||||||
p1.read
|
|
||||||
|
|
||||||
p1.write = 123;
|
|
||||||
|
|
89
src/gale.js
89
src/gale.js
@ -1,89 +0,0 @@
|
|||||||
/** @type {Gale.CreateSheet} */
|
|
||||||
export default (sheet, hash="")=>
|
|
||||||
{
|
|
||||||
const KeyQuery = "@";
|
|
||||||
const KeyState = ":";
|
|
||||||
const KeyChild = ".";
|
|
||||||
const KeyGroup = "^";
|
|
||||||
|
|
||||||
/** @type {Gale.Tier} */
|
|
||||||
const Tier=(selector, obj, suffix)=>
|
|
||||||
{
|
|
||||||
const styles = Object.keys(obj).map((key)=>
|
|
||||||
{
|
|
||||||
const value = obj[key];
|
|
||||||
switch(key[0])
|
|
||||||
{
|
|
||||||
case KeyQuery :
|
|
||||||
return Tier(`@media(max-width:${key.substring(KeyQuery.length)})`, value, suffix);
|
|
||||||
case KeyState :
|
|
||||||
return Tier(`&${key}`, value, suffix);
|
|
||||||
case KeyChild :
|
|
||||||
return Tier(`${key}${suffix}`, value, suffix);
|
|
||||||
case KeyGroup :
|
|
||||||
return Tier(`&:hover .${key.substring(KeyGroup.length)}${suffix}`, value, suffix);
|
|
||||||
}
|
|
||||||
return `${ key.replace(/([a-z])([A-Z])/g, '$1-$2') }: ${value};`
|
|
||||||
});
|
|
||||||
|
|
||||||
return `${selector}{${styles.join("\n")}}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {(needle:string, str:string)=>string} */
|
|
||||||
const extractLast =(needle, str)=>{
|
|
||||||
const ind = str.lastIndexOf(needle)+needle.length;
|
|
||||||
return ind ? str.substring(ind) : str;
|
|
||||||
}
|
|
||||||
|
|
||||||
const collect =(tagName)=>
|
|
||||||
{
|
|
||||||
const pending = van.tags[tagName];
|
|
||||||
let mentioned = [];
|
|
||||||
const collector = new Proxy(
|
|
||||||
(...args)=>
|
|
||||||
{
|
|
||||||
const element = pending(...args);
|
|
||||||
element.className = mentioned.join(id+" ")+id + " " + element.className;
|
|
||||||
mentioned = [];
|
|
||||||
return element;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
get(_, prop)
|
|
||||||
{
|
|
||||||
mentioned.push(prop.substring(prop.lastIndexOf(".")+1));
|
|
||||||
return collector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return collector;
|
|
||||||
}
|
|
||||||
|
|
||||||
const id = hash ? "_"+hash : "";
|
|
||||||
const css = Object.keys(sheet).map(key=>Tier("."+key+id, sheet[key], id)).join(`\n`);
|
|
||||||
globalThis.document?.head.insertAdjacentHTML("beforeend", `<style data-sheet="${id}">${css}</style>`);
|
|
||||||
|
|
||||||
return {
|
|
||||||
Tag(...args){
|
|
||||||
return args.map((arg)=>extractLast(KeyGroup, extractLast(KeyChild, arg))).join(id+" ")+id;
|
|
||||||
},
|
|
||||||
CSS: css,
|
|
||||||
DOM: new Proxy(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
get(_, prop)
|
|
||||||
{
|
|
||||||
return collect(prop)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
Div: new Proxy(
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
get(_, prop)
|
|
||||||
{
|
|
||||||
return collect("div")[prop]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
118
src/hmr.js
118
src/hmr.js
@ -1,118 +0,0 @@
|
|||||||
|
|
||||||
let Time = 0;
|
|
||||||
/** @type {Record<string, string>} */
|
|
||||||
let Temp = {};
|
|
||||||
function Tick()
|
|
||||||
{
|
|
||||||
for(const k in Temp)
|
|
||||||
{
|
|
||||||
sessionStorage.setItem(k, Temp[k]);
|
|
||||||
}
|
|
||||||
Temp = {};
|
|
||||||
Time = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {(key:string, value:string)=>void} */
|
|
||||||
function Save(key, value)
|
|
||||||
{
|
|
||||||
Temp[key] = value;
|
|
||||||
if(!Time)
|
|
||||||
{
|
|
||||||
Time = setTimeout(Tick, 500);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @type {(key:string)=>string|null} */
|
|
||||||
function Load(key)
|
|
||||||
{
|
|
||||||
const value = sessionStorage.getItem(key);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {string|undefined} */
|
|
||||||
let _ID = undefined;
|
|
||||||
let _index = 0;
|
|
||||||
|
|
||||||
/** @type {(id:string|undefined = undefined)=>void} */
|
|
||||||
function StartID(id)
|
|
||||||
{
|
|
||||||
_index = 0;
|
|
||||||
_ID = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
function NextID()
|
|
||||||
{
|
|
||||||
return _ID ? _ID + "_" + (_index++) + "_" : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//bind Van
|
|
||||||
const origninalState = globalThis.van.state;
|
|
||||||
globalThis.van.state =(value, key="")=>
|
|
||||||
{
|
|
||||||
const type = typeof value;
|
|
||||||
let reader =d=>d;
|
|
||||||
let writer =d=>d?.toString() || null;
|
|
||||||
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case "boolean" :
|
|
||||||
reader =(data)=> data === "true"; break;
|
|
||||||
case "number" :
|
|
||||||
reader = parseFloat; break;
|
|
||||||
case "object" :
|
|
||||||
reader = JSON.parse;
|
|
||||||
writer = JSON.stringify;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fullKey = "HMR_" + NextID() + key;
|
|
||||||
const stringValue = Load(fullKey);
|
|
||||||
const signal = origninalState((stringValue ? reader(stringValue) : value));
|
|
||||||
van.derive(()=>Save(fullKey, writer(signal.val)));
|
|
||||||
|
|
||||||
return signal;
|
|
||||||
};
|
|
||||||
|
|
||||||
//bind VanX
|
|
||||||
const originalReactive = globalThis.vanX.reactive;
|
|
||||||
globalThis.vanX = {...globalThis.VanX, reactive:(obj, id)=>
|
|
||||||
{
|
|
||||||
StartID(id);
|
|
||||||
const state = originalReactive(obj);
|
|
||||||
StartID();
|
|
||||||
return state;
|
|
||||||
}};
|
|
||||||
|
|
||||||
// added in devmode to index.html
|
|
||||||
new WebSocket('ws://'+window.location.host+'/ws').addEventListener('message',e=>e.data==='reload'&&window.location.reload());
|
|
||||||
|
|
||||||
vanX.Store =(obj, key)=>
|
|
||||||
{
|
|
||||||
let checkInit = JSON.stringify(obj);
|
|
||||||
let checkStore = localStorage.getItem(key+"check");
|
|
||||||
localStorage.setItem(key+"check", checkInit);
|
|
||||||
|
|
||||||
let recallJSON;
|
|
||||||
if(checkInit == checkStore)
|
|
||||||
{
|
|
||||||
let recallText = localStorage.getItem(key);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
recallJSON = JSON.parse(recallText) || obj;
|
|
||||||
}
|
|
||||||
catch(e)
|
|
||||||
{
|
|
||||||
recallJSON = obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
recallJSON = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
const store = vanX.reactive( recallJSON );
|
|
||||||
van.derive(() => localStorage.setItem(key, JSON.stringify(vanX.compact(store))));
|
|
||||||
return store;
|
|
||||||
}
|
|
71
types.d.ts
vendored
71
types.d.ts
vendored
@ -1,71 +0,0 @@
|
|||||||
import type * as VAN from "https://vanjs.org/code/van-1.5.5.d.ts";
|
|
||||||
import type * as VANX from "https://vanjs.org/code/van-x-0.6.3.d.ts";
|
|
||||||
type Replace<T extends object, K extends keyof T, R> = Omit<T, K> & { readonly [P in K]: R };
|
|
||||||
declare module "vanjs-core" { export type State<T> = VAN.State<T> }
|
|
||||||
declare global
|
|
||||||
{
|
|
||||||
namespace Van { export type * from "https://vanjs.org/code/van-1.5.5.d.ts"; }
|
|
||||||
namespace VanX { export type * from "https://vanjs.org/code/van-x-0.6.3.d.ts"; }
|
|
||||||
const van: Replace<VAN.Van, "state", <T>(arg:T, HMRKey?:string)=>VAN.State<T>>
|
|
||||||
const vanX: Replace<typeof VANX, "reactive", <T extends object>(obj: T, HMRKey?:string) => T> & {Store:<T>(obj:T, key:string)=>T}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
|
|
||||||
namespace Gale {
|
|
||||||
type KeyQuery = "@";
|
|
||||||
type KeyState = ":";
|
|
||||||
type KeyChild = ".";
|
|
||||||
type KeyGroup = "^";
|
|
||||||
type UserStyles = Partial<CSSStyleDeclaration> & {[key: `${KeyQuery|KeyState|KeyChild|KeyGroup}${string}`]: UserStyles }
|
|
||||||
type UserSheet = Record<string, UserStyles>
|
|
||||||
type CollectKeys<Obj> = {[Key in keyof Obj]: Obj[Key] extends object ? Key | CollectKeys<Obj[Key]> : Key }[keyof Obj]
|
|
||||||
type FilterKeys<Keys> = Keys extends `${KeyChild|KeyGroup}${infer Rest}` ? Keys : never
|
|
||||||
type CrossMultiply<A, B> = A extends string ? B extends string ? `${A}${B}` : never : never
|
|
||||||
type CrossMultiplyRecord<Rec> = keyof Rec | { [K in keyof Rec]: K extends string ? CrossMultiply<K, FilterKeys<CollectKeys<Rec[K]>>> : never }[keyof Rec]
|
|
||||||
type Tier = (selector:string, obj:UserStyles, suffix:string)=>string;
|
|
||||||
type CreateSheet = <T extends UserSheet>(sheet:UserSheet&T, hash?:string)=>{
|
|
||||||
Tag:(...args:CrossMultiplyRecord<T>[])=>string,
|
|
||||||
CSS:string,
|
|
||||||
DOM:Elemental<CrossMultiplyRecord<T>>,
|
|
||||||
Div:Circular<CrossMultiplyRecord<T>, Van.TagFunc<HTMLDivElement>>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type Elemental<T extends string> = {[K in keyof HTMLElementTagNameMap]: Van.TagFunc<HTMLElementTagNameMap[K]>&Circular<T, Van.TagFunc<HTMLElementTagNameMap[K]>>}
|
|
||||||
|
|
||||||
type Circular<Keys extends string, Func> = {
|
|
||||||
[K in Keys]: Circular<Keys, Func>&Func
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const Gale:Gale.CreateSheet
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
declare global
|
|
||||||
{
|
|
||||||
namespace JSS
|
|
||||||
{
|
|
||||||
|
|
||||||
type Block = Partial<Record<keyof CSSStyleDeclaration, UnitValue>>
|
|
||||||
type Responsive = Record<number, Block>
|
|
||||||
type Unit = "px" | "em" | "rem" | "%" | "vh" | "vw" | "vmin" | "vmax" | "cm" | "mm" | "in" | "pt" | "pc" | "ch" | "ex"
|
|
||||||
type UnitValue = `${number}${Unit}` | [amount:number, unit:Unit]
|
|
||||||
|
|
||||||
type HexNumber = "1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"|"0"|"a"|"b"|"c"|"d"|"e"|"f"
|
|
||||||
type HexTriplet = `#${HexNumber}${HexNumber}${HexNumber}`
|
|
||||||
type HexColor = `#${HexNumber}${HexNumber}${HexNumber}${HexNumber}${HexNumber}${HexNumber}`
|
|
||||||
|
|
||||||
type Rules = {
|
|
||||||
fontSize: UnitValue,
|
|
||||||
letterSpacing: UnitValue
|
|
||||||
}
|
|
||||||
|
|
||||||
type SheetGen =(mobile:Block, conditions?:Responsive)=> void
|
|
||||||
}
|
|
||||||
|
|
||||||
const Sheet:JSS.SheetGen
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user