@primate/solid 0.4.4 → 0.6.0
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/lib/private/Default.d.ts +13 -0
- package/lib/private/Default.js +30 -0
- package/lib/private/Head/ClientChild.d.ts +3 -0
- package/lib/private/Head/ClientChild.js +2 -0
- package/lib/private/Head/ServerChild.d.ts +8 -0
- package/lib/private/Head/ServerChild.js +2 -0
- package/lib/private/Head/browser.d.ts +9 -0
- package/lib/private/Head/browser.js +36 -0
- package/lib/private/Head/default.d.ts +9 -0
- package/lib/private/Head/default.js +44 -0
- package/lib/private/Head.d.ts +8 -0
- package/lib/private/Head.js +8 -0
- package/lib/private/Runtime.d.ts +11 -0
- package/lib/private/Runtime.js +22 -0
- package/lib/private/client/Validated.d.ts +10 -0
- package/lib/private/client/Validated.js +2 -0
- package/lib/private/client/index.d.ts +11 -0
- package/lib/private/client/index.js +29 -0
- package/lib/private/client/validate.d.ts +25 -0
- package/lib/private/client/validate.js +29 -0
- package/lib/private/context/app.d.ts +13 -0
- package/lib/private/context/app.js +10 -0
- package/lib/private/context/head.d.ts +3 -0
- package/{src → lib}/private/context/head.js +1 -1
- package/lib/private/create-root.d.ts +3 -0
- package/lib/private/create-root.js +35 -0
- package/lib/private/i18n/Bridge.browser.d.ts +8 -0
- package/lib/private/i18n/Bridge.browser.js +25 -0
- package/lib/private/i18n/Bridge.default.d.ts +8 -0
- package/lib/private/i18n/Bridge.default.js +12 -0
- package/lib/public/Head.d.ts +2 -0
- package/lib/public/Head.js +2 -0
- package/lib/public/Validated.d.ts +2 -0
- package/lib/public/Validated.js +2 -0
- package/lib/public/browser.d.ts +2 -0
- package/lib/public/browser.js +2 -0
- package/lib/public/context/app.d.ts +2 -0
- package/{src → lib}/public/context/app.js +1 -0
- package/lib/public/context/head.d.ts +2 -0
- package/{src → lib}/public/context/head.js +1 -0
- package/lib/public/default.d.ts +4 -0
- package/lib/public/default.js +3 -0
- package/lib/public/i18n/Bridge/browser.d.ts +2 -0
- package/lib/public/i18n/Bridge/browser.js +2 -0
- package/lib/public/i18n/Bridge/default.d.ts +2 -0
- package/lib/public/i18n/Bridge/default.js +2 -0
- package/lib/public/runtime.d.ts +4 -0
- package/lib/public/runtime.js +3 -0
- package/lib/public/validate.d.ts +2 -0
- package/lib/public/validate.js +2 -0
- package/package.json +38 -48
- package/src/private/build/client.js +0 -7
- package/src/private/build/index.js +0 -14
- package/src/private/build/publish.js +0 -26
- package/src/private/build/server.js +0 -8
- package/src/private/client/create-root.js +0 -33
- package/src/private/client/expose.js +0 -7
- package/src/private/client/index.js +0 -25
- package/src/private/client/spa.js +0 -14
- package/src/private/context/app.js +0 -3
- package/src/private/extension.js +0 -1
- package/src/private/i18n/index.js +0 -10
- package/src/private/i18n/locale.js +0 -37
- package/src/private/name.js +0 -1
- package/src/private/pkgname.js +0 -1
- package/src/private/serve/index.js +0 -16
- package/src/private/serve/render.js +0 -17
- package/src/public/default.js +0 -14
- package/src/public/head.js +0 -92
- package/src/public/i18n.js +0 -1
- package/src/public/locale.js +0 -1
- package/src/public/runtime.js +0 -12
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import Runtime from "#Runtime";
|
|
2
|
+
export default class Default extends Runtime {
|
|
3
|
+
root: {
|
|
4
|
+
create: (length: number, i18n_active: boolean) => string;
|
|
5
|
+
};
|
|
6
|
+
compile: {
|
|
7
|
+
client: (text: string) => {
|
|
8
|
+
js: string;
|
|
9
|
+
};
|
|
10
|
+
server: (text: string) => string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=Default.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import create_root from "#create-root";
|
|
2
|
+
import Runtime from "#Runtime";
|
|
3
|
+
import { transformSync } from "@babel/core";
|
|
4
|
+
import transform from "@rcompat/build/sync/transform";
|
|
5
|
+
// @ts-expect-error no declaration file
|
|
6
|
+
import solid from "babel-preset-solid";
|
|
7
|
+
function compile(text, presets) {
|
|
8
|
+
return transformSync(transform(text, {
|
|
9
|
+
format: "esm",
|
|
10
|
+
jsx: "preserve",
|
|
11
|
+
loader: "tsx",
|
|
12
|
+
target: "esnext",
|
|
13
|
+
}).code, { presets })?.code ?? "";
|
|
14
|
+
}
|
|
15
|
+
export default class Default extends Runtime {
|
|
16
|
+
root = {
|
|
17
|
+
create: create_root,
|
|
18
|
+
};
|
|
19
|
+
compile = {
|
|
20
|
+
client: (text) => {
|
|
21
|
+
const presets = [[solid, { generate: "dom", hydratable: true }]];
|
|
22
|
+
return { js: compile(text, presets) };
|
|
23
|
+
},
|
|
24
|
+
server: (text) => {
|
|
25
|
+
const presets = [[solid, { generate: "ssr", hydratable: true }]];
|
|
26
|
+
return compile(text, presets);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=Default.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { onCleanup, onMount } from "solid-js";
|
|
2
|
+
const data_attribute = "data-sh";
|
|
3
|
+
const data_ssr = "ssr";
|
|
4
|
+
const render = (children, id) => {
|
|
5
|
+
// DOM elements
|
|
6
|
+
const titles = children.filter(({ tagName }) => tagName === "TITLE");
|
|
7
|
+
const others = children.filter(({ tagName }) => tagName !== "TITLE");
|
|
8
|
+
titles.forEach(title => {
|
|
9
|
+
globalThis.document.title = title.innerText;
|
|
10
|
+
});
|
|
11
|
+
others.forEach(other => {
|
|
12
|
+
other.dataset.sh = id;
|
|
13
|
+
globalThis.document.head.prepend(other);
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
const clear = (data_value) => {
|
|
17
|
+
const selector = `[${data_attribute}="${data_value}"]`;
|
|
18
|
+
globalThis.document.querySelectorAll(selector).forEach(element => {
|
|
19
|
+
element.remove();
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
const Head = function Head(props) {
|
|
23
|
+
let id;
|
|
24
|
+
onMount(() => {
|
|
25
|
+
id = crypto.randomUUID();
|
|
26
|
+
render(props.children, id);
|
|
27
|
+
});
|
|
28
|
+
onCleanup(() => {
|
|
29
|
+
// remove managed tags
|
|
30
|
+
clear(id);
|
|
31
|
+
});
|
|
32
|
+
return null;
|
|
33
|
+
};
|
|
34
|
+
Head.clear = (data_value = data_ssr) => clear(data_value);
|
|
35
|
+
export default Head;
|
|
36
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import HeadContext from "#context/head";
|
|
2
|
+
import { useContext } from "solid-js";
|
|
3
|
+
const data_attribute = "data-sh";
|
|
4
|
+
const data_ssr = "ssr";
|
|
5
|
+
const allowed = ["title", "meta", "style", "meta", "link", "script", "base"];
|
|
6
|
+
const make_tag = (tag, id) => {
|
|
7
|
+
const parts = tag.split(" ");
|
|
8
|
+
return [
|
|
9
|
+
parts[0],
|
|
10
|
+
`${data_attribute}="${id}"`,
|
|
11
|
+
...parts.slice(1),
|
|
12
|
+
].join(" ");
|
|
13
|
+
};
|
|
14
|
+
const get_tag = (child) => child.match(/^<(?<tag>[a-z]*) .*$/u)?.groups?.tag ?? "";
|
|
15
|
+
const render = (children, id) => {
|
|
16
|
+
const tags = children.map(({ t: tag }) => tag);
|
|
17
|
+
const all_good = tags.every(tag => allowed.includes(get_tag(tag)));
|
|
18
|
+
if (!all_good) {
|
|
19
|
+
const bad = get_tag(tags.find(tag => !allowed.includes(get_tag(tag))) ?? "");
|
|
20
|
+
const alloweds = `${allowed.map(tag => `<${tag}>`).join(", ")}`;
|
|
21
|
+
const error = `Head may only contain ${alloweds}, found <${bad}>`;
|
|
22
|
+
throw new Error(error);
|
|
23
|
+
}
|
|
24
|
+
const titles = tags.filter(tag => get_tag(tag) === "title");
|
|
25
|
+
const others = tags.filter(tag => get_tag(tag) !== "title");
|
|
26
|
+
return [
|
|
27
|
+
...titles,
|
|
28
|
+
...others.map(other => make_tag(other, id)),
|
|
29
|
+
];
|
|
30
|
+
};
|
|
31
|
+
const clear = (data_value) => {
|
|
32
|
+
const selector = `[${data_attribute}="${data_value}"]`;
|
|
33
|
+
globalThis.document.querySelectorAll(selector).forEach(element => {
|
|
34
|
+
element.remove();
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
const Head = function Head(props) {
|
|
38
|
+
const context = useContext(HeadContext);
|
|
39
|
+
context(render(props.children, data_ssr));
|
|
40
|
+
return null;
|
|
41
|
+
};
|
|
42
|
+
Head.clear = (data_value = data_ssr) => clear(data_value);
|
|
43
|
+
export default Head;
|
|
44
|
+
//# sourceMappingURL=default.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import FrontendModule from "@primate/core/frontend/Module";
|
|
2
|
+
import type Render from "@primate/core/frontend/Render";
|
|
3
|
+
import type { Component } from "solid-js";
|
|
4
|
+
export default class Runtime extends FrontendModule<Component> {
|
|
5
|
+
name: string;
|
|
6
|
+
defaultExtensions: string[];
|
|
7
|
+
client: boolean;
|
|
8
|
+
layouts: boolean;
|
|
9
|
+
render: Render<Component>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=Runtime.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import FrontendModule from "@primate/core/frontend/Module";
|
|
2
|
+
import { renderToString } from "solid-js/web";
|
|
3
|
+
export default class Runtime extends FrontendModule {
|
|
4
|
+
name = "solid";
|
|
5
|
+
defaultExtensions = [".jsx", ".tsx"];
|
|
6
|
+
client = true;
|
|
7
|
+
layouts = true;
|
|
8
|
+
render = (view, props) => {
|
|
9
|
+
const heads = [];
|
|
10
|
+
const push_heads = (sub_heads) => {
|
|
11
|
+
heads.push(...sub_heads);
|
|
12
|
+
};
|
|
13
|
+
const body = renderToString(() => view({ ...props, push_heads }));
|
|
14
|
+
if (heads.filter(head => head.startsWith("<title")).length > 1) {
|
|
15
|
+
const error = "May only contain one <title> across component hierarchy";
|
|
16
|
+
throw new Error(error);
|
|
17
|
+
}
|
|
18
|
+
const head = heads.join("\n");
|
|
19
|
+
return { body, head };
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=Runtime.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type ValidateUpdater from "@primate/core/client/ValidateUpdater";
|
|
2
|
+
import type ValidationError from "@primate/core/client/ValidationError";
|
|
3
|
+
type Validated<T> = {
|
|
4
|
+
error: () => null | ValidationError;
|
|
5
|
+
loading: () => boolean;
|
|
6
|
+
update: (updater: ValidateUpdater<T>) => Promise<void>;
|
|
7
|
+
value: () => T;
|
|
8
|
+
};
|
|
9
|
+
export type { Validated as default };
|
|
10
|
+
//# sourceMappingURL=Validated.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type ClientData from "@primate/core/client/Data";
|
|
2
|
+
import type Dict from "@rcompat/type/Dict";
|
|
3
|
+
type Data = ClientData<{
|
|
4
|
+
views: string[];
|
|
5
|
+
props: Dict[];
|
|
6
|
+
}>;
|
|
7
|
+
export default class Solid {
|
|
8
|
+
static mount(_view: string, data: ClientData<Data>): void;
|
|
9
|
+
}
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import spa from "@primate/core/client/spa";
|
|
2
|
+
import SolidHead from "@primate/solid/Head";
|
|
3
|
+
import { hydrate, render } from "solid-js/web";
|
|
4
|
+
import root_view from "solid:root";
|
|
5
|
+
import * as views from "solid:views";
|
|
6
|
+
// @ts-expect-error solid hydration
|
|
7
|
+
globalThis._$HY = { completed: new WeakSet(), events: [], r: {} };
|
|
8
|
+
const { body } = globalThis.window.document;
|
|
9
|
+
SolidHead.clear();
|
|
10
|
+
const make_props = (data) => ({
|
|
11
|
+
views: data.views.map(name => views[name]),
|
|
12
|
+
props: data.props,
|
|
13
|
+
request: {
|
|
14
|
+
...data.request,
|
|
15
|
+
url: new URL(location.href),
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
export default class Solid {
|
|
19
|
+
static mount(_view, data) {
|
|
20
|
+
let dispose = hydrate(() => root_view(make_props(data)), body);
|
|
21
|
+
if (data.spa) {
|
|
22
|
+
window.addEventListener("DOMContentLoaded", _ => spa(_data => {
|
|
23
|
+
dispose();
|
|
24
|
+
dispose = render(() => root_view(make_props(_data)), body);
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type Validated from "#client/Validated";
|
|
2
|
+
declare const _default: <T>(initial: T) => {
|
|
3
|
+
delete: (url: string, options?: {
|
|
4
|
+
headers?: import("@rcompat/type/Dict").default<string>;
|
|
5
|
+
map?: ((v: T) => import("@rcompat/type/JSONValue").default) | undefined;
|
|
6
|
+
path?: import("@rcompat/type/JSONPointer").default;
|
|
7
|
+
} | undefined) => Validated<T>;
|
|
8
|
+
patch: (url: string, options?: {
|
|
9
|
+
headers?: import("@rcompat/type/Dict").default<string>;
|
|
10
|
+
map?: ((v: T) => import("@rcompat/type/JSONValue").default) | undefined;
|
|
11
|
+
path?: import("@rcompat/type/JSONPointer").default;
|
|
12
|
+
} | undefined) => Validated<T>;
|
|
13
|
+
post: (url: string, options?: {
|
|
14
|
+
headers?: import("@rcompat/type/Dict").default<string>;
|
|
15
|
+
map?: ((v: T) => import("@rcompat/type/JSONValue").default) | undefined;
|
|
16
|
+
path?: import("@rcompat/type/JSONPointer").default;
|
|
17
|
+
} | undefined) => Validated<T>;
|
|
18
|
+
put: (url: string, options?: {
|
|
19
|
+
headers?: import("@rcompat/type/Dict").default<string>;
|
|
20
|
+
map?: ((v: T) => import("@rcompat/type/JSONValue").default) | undefined;
|
|
21
|
+
path?: import("@rcompat/type/JSONPointer").default;
|
|
22
|
+
} | undefined) => Validated<T>;
|
|
23
|
+
};
|
|
24
|
+
export default _default;
|
|
25
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import toValidated from "@primate/core/client/toValidated";
|
|
2
|
+
import validate from "@primate/core/client/validate";
|
|
3
|
+
import { createSignal } from "solid-js";
|
|
4
|
+
function useValidate(init) {
|
|
5
|
+
const [value, setValue] = createSignal(init.initial);
|
|
6
|
+
const [loading, setLoading] = createSignal(false);
|
|
7
|
+
const [error, setError] = createSignal(null);
|
|
8
|
+
async function update(updater) {
|
|
9
|
+
const previous = value();
|
|
10
|
+
const next = updater(previous);
|
|
11
|
+
setValue(() => next);
|
|
12
|
+
setLoading(true);
|
|
13
|
+
setError(null);
|
|
14
|
+
try {
|
|
15
|
+
await validate(init, next);
|
|
16
|
+
}
|
|
17
|
+
catch (e) {
|
|
18
|
+
// rollback
|
|
19
|
+
setValue(() => previous);
|
|
20
|
+
setError(() => e);
|
|
21
|
+
}
|
|
22
|
+
finally {
|
|
23
|
+
setLoading(false);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return { error, loading, update, value };
|
|
27
|
+
}
|
|
28
|
+
export default toValidated(useValidate);
|
|
29
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type ContextData from "@primate/core/i18n/ContextData";
|
|
2
|
+
import type Dict from "@rcompat/type/Dict";
|
|
3
|
+
import { type Accessor, type Setter } from "solid-js";
|
|
4
|
+
type Context = {
|
|
5
|
+
i18n: ContextData;
|
|
6
|
+
} & Dict;
|
|
7
|
+
export type AppContextValue = {
|
|
8
|
+
context: Accessor<Context>;
|
|
9
|
+
setContext: Setter<Context>;
|
|
10
|
+
};
|
|
11
|
+
declare const _default: import("solid-js").Context<AppContextValue>;
|
|
12
|
+
export default _default;
|
|
13
|
+
//# sourceMappingURL=app.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export default (length, i18n_active) => {
|
|
2
|
+
const n = length - 1;
|
|
3
|
+
const body = Array.from({ length: n }, (_, i) => i - 1)
|
|
4
|
+
.reduceRight((child, _, i) => `views[${i + 1}] !== undefined
|
|
5
|
+
? createComponent(views[${i}], {request, ...props[${i}],
|
|
6
|
+
children: ${child}})
|
|
7
|
+
: createComponent(views[${i}], {request, ...props[${i}]})
|
|
8
|
+
`, `createComponent(views[${n}], {request, ...props[${n}]})`);
|
|
9
|
+
const i18n_imports = i18n_active
|
|
10
|
+
? `
|
|
11
|
+
import I18nBridge from "@primate/solid/i18n/Bridge";
|
|
12
|
+
import t from "#i18n";`
|
|
13
|
+
: "";
|
|
14
|
+
const tree = i18n_active
|
|
15
|
+
? `<I18nBridge t={t}>{${body}}</I18nBridge>`
|
|
16
|
+
: `{${body}}`;
|
|
17
|
+
return `
|
|
18
|
+
import { createSignal } from "solid-js";
|
|
19
|
+
import { createComponent } from "solid-js/web";
|
|
20
|
+
import AppContext from "@primate/solid/context/app";
|
|
21
|
+
import HeadContext from "@primate/solid/context/head";${i18n_imports}
|
|
22
|
+
|
|
23
|
+
export default ({ views, props, request, push_heads: value }) => {
|
|
24
|
+
const [context, setContext] = createSignal(request.context);
|
|
25
|
+
const $value = { context, setContext };
|
|
26
|
+
|
|
27
|
+
return <AppContext.Provider value={$value}>
|
|
28
|
+
<HeadContext.Provider value={value}>
|
|
29
|
+
${tree}
|
|
30
|
+
</HeadContext.Provider>
|
|
31
|
+
</AppContext.Provider>
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=create-root.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type API from "@primate/core/i18n/API";
|
|
2
|
+
import type Catalogs from "@primate/core/i18n/Catalogs";
|
|
3
|
+
import { type JSX } from "solid-js";
|
|
4
|
+
export default function I18nBridge<C extends Catalogs>(props: {
|
|
5
|
+
t: API<C>;
|
|
6
|
+
children?: JSX.Element;
|
|
7
|
+
}): any;
|
|
8
|
+
//# sourceMappingURL=Bridge.browser.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { memo as _$memo } from "solid-js/web";
|
|
2
|
+
import AppContext from "#context/app";
|
|
3
|
+
import sInternal from "@primate/core/i18n/sInternal";
|
|
4
|
+
import { createSignal, onCleanup, onMount, useContext } from "solid-js";
|
|
5
|
+
function I18nBridge(props) {
|
|
6
|
+
const {
|
|
7
|
+
context
|
|
8
|
+
} = useContext(AppContext);
|
|
9
|
+
const server = context().i18n.locale;
|
|
10
|
+
if (server !== void 0 && server !== props.t.locale.get()) {
|
|
11
|
+
props.t[sInternal].init(server);
|
|
12
|
+
}
|
|
13
|
+
const [version, setVersion] = createSignal(props.t[sInternal].version);
|
|
14
|
+
const removeDepend = props.t[sInternal].depend(() => {
|
|
15
|
+
version();
|
|
16
|
+
});
|
|
17
|
+
const off = props.t.subscribe(() => setVersion(v => v + 1));
|
|
18
|
+
onMount(() => props.t[sInternal].restore());
|
|
19
|
+
onCleanup(() => {
|
|
20
|
+
off();
|
|
21
|
+
removeDepend();
|
|
22
|
+
});
|
|
23
|
+
return _$memo(() => props.children);
|
|
24
|
+
}
|
|
25
|
+
export { I18nBridge as default };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type API from "@primate/core/i18n/API";
|
|
2
|
+
import type Catalogs from "@primate/core/i18n/Catalogs";
|
|
3
|
+
import { type JSX } from "solid-js";
|
|
4
|
+
export default function I18nBridge<C extends Catalogs>(props: {
|
|
5
|
+
t: API<C>;
|
|
6
|
+
children?: JSX.Element;
|
|
7
|
+
}): any;
|
|
8
|
+
//# sourceMappingURL=Bridge.default.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { memo as _$memo } from "solid-js/web";
|
|
2
|
+
import AppContext from "#context/app";
|
|
3
|
+
import sInternal from "@primate/core/i18n/sInternal";
|
|
4
|
+
import { useContext } from "solid-js";
|
|
5
|
+
function I18nBridge(props) {
|
|
6
|
+
const {
|
|
7
|
+
context
|
|
8
|
+
} = useContext(AppContext);
|
|
9
|
+
props.t[sInternal].init(context().i18n.locale);
|
|
10
|
+
return _$memo(() => props.children);
|
|
11
|
+
}
|
|
12
|
+
export { I18nBridge as default };
|
package/package.json
CHANGED
|
@@ -1,74 +1,64 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primate/solid",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Primate Solid frontend",
|
|
5
|
-
"homepage": "https://
|
|
6
|
-
"bugs": "https://github.com/
|
|
5
|
+
"homepage": "https://primate.run/docs/frontend/solid",
|
|
6
|
+
"bugs": "https://github.com/primate-run/primate/issues",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"files": [
|
|
9
|
-
"
|
|
10
|
-
"
|
|
9
|
+
"/lib/**/*.js",
|
|
10
|
+
"/lib/**/*.d.ts",
|
|
11
|
+
"!/**/*.spec.*"
|
|
11
12
|
],
|
|
12
13
|
"repository": {
|
|
13
14
|
"type": "git",
|
|
14
|
-
"url": "https://github.com/
|
|
15
|
+
"url": "https://github.com/primate-run/primate",
|
|
15
16
|
"directory": "packages/solid"
|
|
16
17
|
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/babel__core": "^7.20.5"
|
|
20
|
+
},
|
|
17
21
|
"dependencies": {
|
|
18
|
-
"@babel/core": "^7.
|
|
19
|
-
"@rcompat/build": "^0.
|
|
20
|
-
"@rcompat/fs": "^0.
|
|
21
|
-
"@rcompat/runtime": "^0.
|
|
22
|
-
"babel-preset-solid": "^1.
|
|
23
|
-
"
|
|
22
|
+
"@babel/core": "^7.28.4",
|
|
23
|
+
"@rcompat/build": "^0.14.0",
|
|
24
|
+
"@rcompat/fs": "^0.21.1",
|
|
25
|
+
"@rcompat/runtime": "^0.6.0",
|
|
26
|
+
"babel-preset-solid": "^1.9.9",
|
|
27
|
+
"fast-glob": "^3.3.3",
|
|
28
|
+
"@primate/core": "^0.3.0"
|
|
24
29
|
},
|
|
25
30
|
"peerDependencies": {
|
|
26
31
|
"solid-js": "1",
|
|
27
|
-
"
|
|
28
|
-
"primate": "^0.32.6"
|
|
29
|
-
},
|
|
30
|
-
"peerDependenciesMeta": {
|
|
31
|
-
"@primate/i18n": {
|
|
32
|
-
"optional": true
|
|
33
|
-
}
|
|
32
|
+
"primate": "^0.34.0"
|
|
34
33
|
},
|
|
35
34
|
"type": "module",
|
|
36
35
|
"imports": {
|
|
37
36
|
"#*": {
|
|
38
|
-
"
|
|
39
|
-
"default": "./
|
|
40
|
-
},
|
|
41
|
-
"#build": {
|
|
42
|
-
"livetypes": "./src/private/build/index.js",
|
|
43
|
-
"default": "./src/private/build/index.js"
|
|
44
|
-
},
|
|
45
|
-
"#serve": {
|
|
46
|
-
"livetypes": "./src/private/serve/index.js",
|
|
47
|
-
"default": "./src/private/serve/index.js"
|
|
37
|
+
"apekit": "./src/private/*.ts",
|
|
38
|
+
"default": "./lib/private/*.js"
|
|
48
39
|
},
|
|
49
|
-
"#
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
"#client": {
|
|
54
|
-
"livetypes": "./src/private/client/index.js",
|
|
55
|
-
"default": "./src/private/client/index.js"
|
|
56
|
-
},
|
|
57
|
-
"#client/*": {
|
|
58
|
-
"livetypes": "./src/private/client/*.js",
|
|
59
|
-
"default": "./src/private/client/*.js"
|
|
60
|
-
},
|
|
61
|
-
"#i18n/*": {
|
|
62
|
-
"livetypes": "./src/private/i18n/*.js",
|
|
63
|
-
"default": "./src/private/i18n/*.js"
|
|
40
|
+
"#HeadImpl": {
|
|
41
|
+
"apekit": "./src/private/Head/default.ts",
|
|
42
|
+
"browser": "./lib/private/Head/browser.js",
|
|
43
|
+
"default": "./lib/private/Head/default.js"
|
|
64
44
|
}
|
|
65
45
|
},
|
|
66
46
|
"exports": {
|
|
67
47
|
".": {
|
|
68
|
-
"
|
|
69
|
-
"
|
|
48
|
+
"browser": "./lib/public/browser.js",
|
|
49
|
+
"runtime": "./lib/public/runtime.js",
|
|
50
|
+
"default": "./lib/public/default.js"
|
|
70
51
|
},
|
|
71
|
-
"./*": "./
|
|
72
|
-
"./
|
|
52
|
+
"./*": "./lib/public/*.js",
|
|
53
|
+
"./i18n/Bridge": {
|
|
54
|
+
"browser": "./lib/public/i18n/Bridge/browser.js",
|
|
55
|
+
"default": "./lib/public/i18n/Bridge/default.js"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "npm run clean && tsc",
|
|
60
|
+
"postbuild": "node scripts/compile-jsx.js",
|
|
61
|
+
"clean": "rm -rf ./lib",
|
|
62
|
+
"lint": "eslint ."
|
|
73
63
|
}
|
|
74
64
|
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import create_root from "#client/create-root";
|
|
2
|
-
import expose from "#client/expose";
|
|
3
|
-
import name from "#name";
|
|
4
|
-
import build from "@primate/frontend/core/build";
|
|
5
|
-
import client from "./client.js";
|
|
6
|
-
import publish from "./publish.js";
|
|
7
|
-
import server from "./server.js";
|
|
8
|
-
|
|
9
|
-
export default extension => build({
|
|
10
|
-
create_root,
|
|
11
|
-
extension,
|
|
12
|
-
name,
|
|
13
|
-
actions: { compile: { client, server }, expose, publish },
|
|
14
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import file from "@rcompat/fs/file";
|
|
2
|
-
import client from "./client.js";
|
|
3
|
-
|
|
4
|
-
const root_filter = /^root:solid/u;
|
|
5
|
-
|
|
6
|
-
export default (app, extension) => ({
|
|
7
|
-
name: "solid",
|
|
8
|
-
setup(build) {
|
|
9
|
-
build.onResolve({ filter: root_filter }, ({ path }) => {
|
|
10
|
-
return { path, namespace: "solidroot" };
|
|
11
|
-
});
|
|
12
|
-
build.onLoad({ filter: root_filter }, ({ path }) => {
|
|
13
|
-
const contents = app.build.load(path);
|
|
14
|
-
return contents
|
|
15
|
-
? { contents, loader: "js", resolveDir: app.root.path }
|
|
16
|
-
: null;
|
|
17
|
-
});
|
|
18
|
-
build.onLoad({ filter: new RegExp(`${extension}$`, "u") }, async args => {
|
|
19
|
-
// Load the file from the file system
|
|
20
|
-
const source = await file(args.path).text();
|
|
21
|
-
|
|
22
|
-
// Convert JSX syntax to JavaScript
|
|
23
|
-
return { contents: (await client(source)).js };
|
|
24
|
-
});
|
|
25
|
-
},
|
|
26
|
-
});
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
export default length => {
|
|
2
|
-
const n = length - 1;
|
|
3
|
-
const body = Array.from({ length: n }, (_, i) => i - 1)
|
|
4
|
-
.reduceRight((child, _, i) => `components[${i + 1}] !== undefined
|
|
5
|
-
? createComponent(components[${i}], {request, ...data[${i}],
|
|
6
|
-
children: ${child}})
|
|
7
|
-
: createComponent(components[${i}], {request, ...data[${i}]})
|
|
8
|
-
`, `createComponent(components[${n}], {request, ...data[${n}]})`);
|
|
9
|
-
|
|
10
|
-
return `
|
|
11
|
-
import { createSignal } from "solid-js";
|
|
12
|
-
import { createComponent } from "solid-js/web";
|
|
13
|
-
import AppContext from "@primate/solid/context/app";
|
|
14
|
-
import HeadContext from "@primate/solid/context/head";
|
|
15
|
-
|
|
16
|
-
export default ({
|
|
17
|
-
components,
|
|
18
|
-
data,
|
|
19
|
-
request,
|
|
20
|
-
context: c,
|
|
21
|
-
push_heads: value,
|
|
22
|
-
}) => {
|
|
23
|
-
const [context, setContext] = createSignal(c);
|
|
24
|
-
const $value = { context, setContext };
|
|
25
|
-
|
|
26
|
-
return <AppContext.Provider value={$value}>
|
|
27
|
-
<HeadContext.Provider value={value}>
|
|
28
|
-
{${body}}
|
|
29
|
-
</HeadContext.Provider>
|
|
30
|
-
</AppContext.Provider>
|
|
31
|
-
}
|
|
32
|
-
`;
|
|
33
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { generateHydrationScript } from "solid-js/web";
|
|
2
|
-
import spa from "./spa.js";
|
|
3
|
-
|
|
4
|
-
const { groups: { code: hydration_script } } = generateHydrationScript()
|
|
5
|
-
.match(/^<script>(?<code>.*?)<\/script>/u);
|
|
6
|
-
|
|
7
|
-
export default ({ names, data, context, request }, options) => `
|
|
8
|
-
import * as components from "app";
|
|
9
|
-
import { hydrate_solid, render_solid, SolidHead } from "app";
|
|
10
|
-
|
|
11
|
-
window._$HY = { events: [], completed: new WeakSet(), r: {} };
|
|
12
|
-
|
|
13
|
-
${hydration_script}
|
|
14
|
-
|
|
15
|
-
SolidHead.clear();
|
|
16
|
-
let dispose = hydrate_solid(() => components.root_solid({
|
|
17
|
-
components: [${names.map(name => `components.${name}`).join(", ")}],
|
|
18
|
-
data: ${JSON.stringify(data)},
|
|
19
|
-
context: ${JSON.stringify(context)},
|
|
20
|
-
request: {
|
|
21
|
-
...${JSON.stringify(request)},
|
|
22
|
-
url: new URL(location.href),
|
|
23
|
-
},
|
|
24
|
-
}), globalThis.window.document.body);
|
|
25
|
-
${options.spa ? spa : ""}`;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export default `
|
|
2
|
-
const { spa } = components;
|
|
3
|
-
window.addEventListener("DOMContentLoaded", _ => spa((props, update) => {
|
|
4
|
-
dispose();
|
|
5
|
-
dispose = render_solid(() => components.root_solid({
|
|
6
|
-
components: props.names.map(name => components[name]),
|
|
7
|
-
data: props.data,
|
|
8
|
-
context: props.context,
|
|
9
|
-
request: {
|
|
10
|
-
...props.request,
|
|
11
|
-
url: new URL(location.href),
|
|
12
|
-
},
|
|
13
|
-
}), globalThis.window.document.body);
|
|
14
|
-
}));`;
|
package/src/private/extension.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default ".jsx";
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import resolve from "@primate/i18n/core/resolve";
|
|
2
|
-
import AppContext from "#context/app";
|
|
3
|
-
import { useContext } from "solid-js";
|
|
4
|
-
import locale_store from "./locale.js";
|
|
5
|
-
|
|
6
|
-
export default (key, placeholders) => {
|
|
7
|
-
locale_store.init();
|
|
8
|
-
const { locales, locale } = useContext(AppContext).context().i18n;
|
|
9
|
-
return resolve(locales[locale], key, placeholders);
|
|
10
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import AppContext from "#context/app";
|
|
2
|
-
import save from "@primate/i18n/core/save";
|
|
3
|
-
import { useContext } from "solid-js";
|
|
4
|
-
|
|
5
|
-
const $ = {
|
|
6
|
-
context: Symbol("context"),
|
|
7
|
-
setContext: Symbol("setContext"),
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export default {
|
|
11
|
-
[$.context]: undefined,
|
|
12
|
-
[$.setContext]: undefined,
|
|
13
|
-
get() {
|
|
14
|
-
this.init();
|
|
15
|
-
return this[$.context].i18n.locale;
|
|
16
|
-
},
|
|
17
|
-
set(locale) {
|
|
18
|
-
this.init();
|
|
19
|
-
this[$.setContext]({
|
|
20
|
-
...this[$.context],
|
|
21
|
-
i18n: {
|
|
22
|
-
locale,
|
|
23
|
-
locales: this[$.context].i18n.locales,
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
save(locale);
|
|
27
|
-
},
|
|
28
|
-
init() {
|
|
29
|
-
if (this[$.context] !== undefined) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const { context, setContext } = useContext(AppContext);
|
|
34
|
-
this[$.context] = context();
|
|
35
|
-
this[$.setContext] = setContext;
|
|
36
|
-
},
|
|
37
|
-
};
|
package/src/private/name.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default "solid";
|
package/src/private/pkgname.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default "@primate/solid";
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import handler from "@primate/frontend/core/handler";
|
|
2
|
-
import client from "#client";
|
|
3
|
-
import name from "#name";
|
|
4
|
-
import render from "./render.js";
|
|
5
|
-
|
|
6
|
-
export default (extension, spa) => (app, next) => {
|
|
7
|
-
app.register(extension, handler({
|
|
8
|
-
app,
|
|
9
|
-
render,
|
|
10
|
-
client,
|
|
11
|
-
name,
|
|
12
|
-
spa,
|
|
13
|
-
}));
|
|
14
|
-
|
|
15
|
-
return next(app);
|
|
16
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { renderToString } from "solid-js/web";
|
|
2
|
-
|
|
3
|
-
export default (component, props) => {
|
|
4
|
-
const heads = [];
|
|
5
|
-
const push_heads = sub_heads => {
|
|
6
|
-
heads.push(...sub_heads);
|
|
7
|
-
};
|
|
8
|
-
const body = renderToString(() => component({ ...props, push_heads }));
|
|
9
|
-
|
|
10
|
-
if (heads.filter(head => head.startsWith("<title")).length > 1) {
|
|
11
|
-
const error = "May only contain one <title> across component hierarchy";
|
|
12
|
-
throw new Error(error);
|
|
13
|
-
}
|
|
14
|
-
const head = heads.join("\n");
|
|
15
|
-
|
|
16
|
-
return { body, head };
|
|
17
|
-
};
|
package/src/public/default.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import build from "#build";
|
|
2
|
-
import default_extension from "#extension";
|
|
3
|
-
import pkgname from "#pkgname";
|
|
4
|
-
import serve from "#serve";
|
|
5
|
-
|
|
6
|
-
export default ({
|
|
7
|
-
extension = default_extension,
|
|
8
|
-
// activate fetch-based browsing
|
|
9
|
-
spa = true,
|
|
10
|
-
} = {}) => ({
|
|
11
|
-
name: pkgname,
|
|
12
|
-
build: build(extension),
|
|
13
|
-
serve: serve(extension, spa),
|
|
14
|
-
});
|
package/src/public/head.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import HeadContext from "#context/head";
|
|
2
|
-
import runtime from "@rcompat/runtime";
|
|
3
|
-
import { onCleanup, onMount, useContext } from "solid-js";
|
|
4
|
-
|
|
5
|
-
const is_client = runtime === "browser";
|
|
6
|
-
|
|
7
|
-
const to_array = maybe => Array.isArray(maybe) ? maybe : [maybe];
|
|
8
|
-
|
|
9
|
-
const data_attribute = "data-sh";
|
|
10
|
-
const data_ssr = "ssr";
|
|
11
|
-
const allowed = ["title", "meta", "style", "meta", "link", "script", "base"];
|
|
12
|
-
|
|
13
|
-
const make_tag = (tag, id) => {
|
|
14
|
-
const parts = tag.split(" ");
|
|
15
|
-
return [
|
|
16
|
-
parts[0],
|
|
17
|
-
`${data_attribute}="${id}"`,
|
|
18
|
-
...parts.slice(1),
|
|
19
|
-
].join(" ");
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const get_tag = child => child.match(/^<(?<tag>[a-z]*) .*$/u).groups.tag;
|
|
23
|
-
|
|
24
|
-
const render = (maybe_children, id) => {
|
|
25
|
-
const children = to_array(maybe_children);
|
|
26
|
-
|
|
27
|
-
if (is_client) {
|
|
28
|
-
// DOM elements
|
|
29
|
-
const titles = children.filter(({ tagName }) => tagName === "TITLE");
|
|
30
|
-
const others = children.filter(({ tagName }) => tagName !== "TITLE");
|
|
31
|
-
|
|
32
|
-
titles.forEach(title => {
|
|
33
|
-
globalThis.document.title = title.innerText;
|
|
34
|
-
});
|
|
35
|
-
others.forEach(other => {
|
|
36
|
-
other.dataset.sh = id;
|
|
37
|
-
globalThis.document.head.prepend(other);
|
|
38
|
-
});
|
|
39
|
-
} else {
|
|
40
|
-
const tags = children.map(({ t: tag }) => tag);
|
|
41
|
-
const all_good = tags.every(tag => allowed.includes(get_tag(tag)));
|
|
42
|
-
if (!all_good) {
|
|
43
|
-
const bad = get_tag(tags.find(tag => !allowed.includes(get_tag(tag))));
|
|
44
|
-
const alloweds = `${allowed.map(tag => `<${tag}>`).join(", ")}`;
|
|
45
|
-
const error = `Head may only contain ${alloweds}, found <${bad}>`;
|
|
46
|
-
throw new Error(error);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const titles = tags.filter(tag => get_tag(tag) === "title");
|
|
50
|
-
const others = tags.filter(tag => get_tag(tag) !== "title");
|
|
51
|
-
|
|
52
|
-
return [
|
|
53
|
-
...titles,
|
|
54
|
-
...others.map(other => make_tag(other, id)),
|
|
55
|
-
];
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const clear = (data_value) => {
|
|
60
|
-
const selector = `[${data_attribute}="${data_value}"]`;
|
|
61
|
-
globalThis.document.querySelectorAll(selector).forEach(element => {
|
|
62
|
-
element.remove();
|
|
63
|
-
});
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const Head = function Head(props) {
|
|
67
|
-
let id;
|
|
68
|
-
onMount(() => {
|
|
69
|
-
if (is_client) {
|
|
70
|
-
id = crypto.randomUUID();
|
|
71
|
-
render(props.children, id);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
onCleanup(() => {
|
|
76
|
-
if (is_client) {
|
|
77
|
-
// remove managed tags
|
|
78
|
-
clear(id);
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
if (!is_client) {
|
|
83
|
-
const context = useContext(HeadContext);
|
|
84
|
-
context(render(props.children, data_ssr));
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// no return, nothing rendered
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
Head.clear = (data_value = data_ssr) => clear(data_value);
|
|
91
|
-
|
|
92
|
-
export default Head;
|
package/src/public/i18n.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "#i18n/index";
|
package/src/public/locale.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from "#i18n/locale";
|
package/src/public/runtime.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import default_extension from "#extension";
|
|
2
|
-
import pkgname from "#pkgname";
|
|
3
|
-
import serve from "#serve";
|
|
4
|
-
|
|
5
|
-
export default ({
|
|
6
|
-
extension = default_extension,
|
|
7
|
-
// activate fetch-based browsing
|
|
8
|
-
spa = true,
|
|
9
|
-
} = {}) => ({
|
|
10
|
-
name: pkgname,
|
|
11
|
-
serve: serve(extension, spa),
|
|
12
|
-
});
|