twynejs 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/jsx-runtime.d.ts +40 -0
- package/dist/jsx-runtime.js +66 -0
- package/package.json +1 -1
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -4,6 +4,46 @@ export interface HtmlValue {
|
|
|
4
4
|
readonly value: string;
|
|
5
5
|
toString(): string;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Registers the CSS-module map `jsx()` should use to resolve plain class
|
|
9
|
+
* names for the *current* render, so you don't have to write
|
|
10
|
+
* `className={styles.title}` on every single element. Call it once,
|
|
11
|
+
* before building the JSX tree that should use it — typically as the
|
|
12
|
+
* first line of a page's `mount()`:
|
|
13
|
+
*
|
|
14
|
+
* ```tsx
|
|
15
|
+
* import styles from "./about.module.css";
|
|
16
|
+
* import { useStyles } from "twynejs/jsx-runtime";
|
|
17
|
+
*
|
|
18
|
+
* export default function mount(el: HTMLElement) {
|
|
19
|
+
* useStyles(styles);
|
|
20
|
+
* el.innerHTML = (
|
|
21
|
+
* <>
|
|
22
|
+
* <h1 className="title">About</h1>
|
|
23
|
+
* <p className="title lead">Still just a plain string.</p>
|
|
24
|
+
* </>
|
|
25
|
+
* );
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* Every whitespace-separated class token that matches a key in `styles`
|
|
30
|
+
* is swapped for its scoped/hashed value (`"title"` → `styles.title`,
|
|
31
|
+
* e.g. `"_title_a1b2c3_1"`); any token that doesn't match (utility
|
|
32
|
+
* classes, classes from a global stylesheet, …) is left exactly as
|
|
33
|
+
* written. Pass `null` (or nothing) to go back to plain, unresolved class
|
|
34
|
+
* names.
|
|
35
|
+
*
|
|
36
|
+
* Because this whole library renders synchronously — there is no `await`
|
|
37
|
+
* between `useStyles()` and the `jsx()` calls it applies to — one
|
|
38
|
+
* module-level value is enough for a single page's render. It does,
|
|
39
|
+
* however, stay set until something changes it again: if your app's
|
|
40
|
+
* router calls multiple pages' `mount()` functions over the page's
|
|
41
|
+
* lifetime (as the `singleFile` hash-router example does), call
|
|
42
|
+
* `useStyles(null)` right before invoking a page's `mount()` (or have
|
|
43
|
+
* every page call `useStyles()` itself, even with `null`) so a previous
|
|
44
|
+
* page's classes can't leak into one that doesn't expect them.
|
|
45
|
+
*/
|
|
46
|
+
export declare function useStyles(styles: Record<string, string> | null): void;
|
|
7
47
|
export declare function jsx(tag: string | ((props: any) => any), props: Record<string, any> | null, ...children: any[]): HtmlValue | string;
|
|
8
48
|
export declare function jsxs(tag: string | ((props: any) => any), props: Record<string, any> | null): HtmlValue | string;
|
|
9
49
|
export declare function Fragment(props: {
|
package/dist/jsx-runtime.js
CHANGED
|
@@ -1,5 +1,64 @@
|
|
|
1
1
|
// Custom JSX Runtime for the SSG Pages Plugin
|
|
2
2
|
const HTML = Symbol("html");
|
|
3
|
+
/**
|
|
4
|
+
* The CSS-module map (e.g. `import styles from "./about.module.css"`)
|
|
5
|
+
* that `jsx()` should currently consult when resolving `class`/
|
|
6
|
+
* `className` attribute values — see `useStyles()` below.
|
|
7
|
+
*/
|
|
8
|
+
let activeStyles = null;
|
|
9
|
+
/**
|
|
10
|
+
* Registers the CSS-module map `jsx()` should use to resolve plain class
|
|
11
|
+
* names for the *current* render, so you don't have to write
|
|
12
|
+
* `className={styles.title}` on every single element. Call it once,
|
|
13
|
+
* before building the JSX tree that should use it — typically as the
|
|
14
|
+
* first line of a page's `mount()`:
|
|
15
|
+
*
|
|
16
|
+
* ```tsx
|
|
17
|
+
* import styles from "./about.module.css";
|
|
18
|
+
* import { useStyles } from "twynejs/jsx-runtime";
|
|
19
|
+
*
|
|
20
|
+
* export default function mount(el: HTMLElement) {
|
|
21
|
+
* useStyles(styles);
|
|
22
|
+
* el.innerHTML = (
|
|
23
|
+
* <>
|
|
24
|
+
* <h1 className="title">About</h1>
|
|
25
|
+
* <p className="title lead">Still just a plain string.</p>
|
|
26
|
+
* </>
|
|
27
|
+
* );
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* Every whitespace-separated class token that matches a key in `styles`
|
|
32
|
+
* is swapped for its scoped/hashed value (`"title"` → `styles.title`,
|
|
33
|
+
* e.g. `"_title_a1b2c3_1"`); any token that doesn't match (utility
|
|
34
|
+
* classes, classes from a global stylesheet, …) is left exactly as
|
|
35
|
+
* written. Pass `null` (or nothing) to go back to plain, unresolved class
|
|
36
|
+
* names.
|
|
37
|
+
*
|
|
38
|
+
* Because this whole library renders synchronously — there is no `await`
|
|
39
|
+
* between `useStyles()` and the `jsx()` calls it applies to — one
|
|
40
|
+
* module-level value is enough for a single page's render. It does,
|
|
41
|
+
* however, stay set until something changes it again: if your app's
|
|
42
|
+
* router calls multiple pages' `mount()` functions over the page's
|
|
43
|
+
* lifetime (as the `singleFile` hash-router example does), call
|
|
44
|
+
* `useStyles(null)` right before invoking a page's `mount()` (or have
|
|
45
|
+
* every page call `useStyles()` itself, even with `null`) so a previous
|
|
46
|
+
* page's classes can't leak into one that doesn't expect them.
|
|
47
|
+
*/
|
|
48
|
+
export function useStyles(styles) {
|
|
49
|
+
activeStyles = styles;
|
|
50
|
+
}
|
|
51
|
+
function resolveClassName(value) {
|
|
52
|
+
if (!activeStyles) {
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
const styles = activeStyles;
|
|
56
|
+
return value
|
|
57
|
+
.split(/\s+/)
|
|
58
|
+
.filter(Boolean)
|
|
59
|
+
.map((token) => styles[token] ?? token)
|
|
60
|
+
.join(" ");
|
|
61
|
+
}
|
|
3
62
|
function renderChildren(children) {
|
|
4
63
|
return children
|
|
5
64
|
.flat(Infinity)
|
|
@@ -47,6 +106,13 @@ export function jsx(tag, props, ...children) {
|
|
|
47
106
|
if (typeof value === "boolean" && booleanHtmlAttributes.has(attribute)) {
|
|
48
107
|
return value ? ` ${attribute}` : "";
|
|
49
108
|
}
|
|
109
|
+
// `class`/`className`: plain class-name tokens get resolved against
|
|
110
|
+
// whatever `useStyles()` last registered, so authors can keep
|
|
111
|
+
// writing ordinary string class names instead of `styles.xxx` on
|
|
112
|
+
// every element.
|
|
113
|
+
if (attribute === "class" && typeof value === "string") {
|
|
114
|
+
value = resolveClassName(value);
|
|
115
|
+
}
|
|
50
116
|
// Alles andere (inkl. data-*/aria-*) bekommt immer einen expliziten
|
|
51
117
|
// String-Wert, damit z.B. dataset.nested === "false" verlässlich geht.
|
|
52
118
|
if (typeof value === "boolean") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "twynejs",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "twine A Vite SSG plugin that turns .ts/.tsx pages, Markdown docs and Liquid/EJS templates into a multi-page static build with a virtual:pages module.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|