@react-x11/components 0.4.0 → 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/README.md +143 -8
- package/dist/charts/components.d.ts +3 -1
- package/dist/charts/components.d.ts.map +1 -1
- package/dist/charts/components.js +8 -4
- package/dist/charts/components.js.map +1 -1
- package/dist/charts/node.d.ts +13 -6
- package/dist/charts/node.d.ts.map +1 -1
- package/dist/charts/node.js +75 -24
- package/dist/charts/node.js.map +1 -1
- package/dist/charts/render.d.ts +4 -0
- package/dist/charts/render.d.ts.map +1 -1
- package/dist/charts/render.js +11 -6
- package/dist/charts/render.js.map +1 -1
- package/dist/code-editor/node.d.ts +47 -16
- package/dist/code-editor/node.d.ts.map +1 -1
- package/dist/code-editor/node.js +121 -51
- package/dist/code-editor/node.js.map +1 -1
- package/dist/flow/draw.d.ts +19 -1
- package/dist/flow/draw.d.ts.map +1 -1
- package/dist/flow/draw.js +64 -35
- package/dist/flow/draw.js.map +1 -1
- package/dist/flow/index.d.ts.map +1 -1
- package/dist/flow/index.js +24 -8
- package/dist/flow/index.js.map +1 -1
- package/dist/flow/model.d.ts +4 -2
- package/dist/flow/model.d.ts.map +1 -1
- package/dist/flow/model.js +4 -2
- package/dist/flow/model.js.map +1 -1
- package/dist/flow/node.d.ts +40 -9
- package/dist/flow/node.d.ts.map +1 -1
- package/dist/flow/node.js +142 -53
- package/dist/flow/node.js.map +1 -1
- package/dist/flow/types.d.ts +46 -21
- package/dist/flow/types.d.ts.map +1 -1
- package/dist/formula/index.d.ts +4 -2
- package/dist/formula/index.d.ts.map +1 -1
- package/dist/formula/index.js.map +1 -1
- package/dist/formula/node.d.ts +5 -1
- package/dist/formula/node.d.ts.map +1 -1
- package/dist/formula/node.js +19 -3
- package/dist/formula/node.js.map +1 -1
- package/dist/html/controls.d.ts +4 -1
- package/dist/html/controls.d.ts.map +1 -1
- package/dist/html/controls.js.map +1 -1
- package/dist/html/css/cascade.d.ts +11 -5
- package/dist/html/css/cascade.d.ts.map +1 -1
- package/dist/html/css/cascade.js +18 -8
- package/dist/html/css/cascade.js.map +1 -1
- package/dist/html/css/parse.d.ts +15 -10
- package/dist/html/css/parse.d.ts.map +1 -1
- package/dist/html/css/parse.js +41 -16
- package/dist/html/css/parse.js.map +1 -1
- package/dist/html/css/style.d.ts +3 -0
- package/dist/html/css/style.d.ts.map +1 -1
- package/dist/html/css/style.js +3 -1
- package/dist/html/css/style.js.map +1 -1
- package/dist/html/css/values.d.ts +14 -1
- package/dist/html/css/values.d.ts.map +1 -1
- package/dist/html/css/values.js +11 -8
- package/dist/html/css/values.js.map +1 -1
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +1 -0
- package/dist/html/index.js.map +1 -1
- package/dist/html/layout/boxes.d.ts +12 -5
- package/dist/html/layout/boxes.d.ts.map +1 -1
- package/dist/html/layout/boxes.js +7 -4
- package/dist/html/layout/boxes.js.map +1 -1
- package/dist/html/layout/inline.d.ts.map +1 -1
- package/dist/html/layout/inline.js +22 -1
- package/dist/html/layout/inline.js.map +1 -1
- package/dist/html/node.d.ts +22 -8
- package/dist/html/node.d.ts.map +1 -1
- package/dist/html/node.js +97 -15
- package/dist/html/node.js.map +1 -1
- package/dist/html/paint.d.ts +3 -0
- package/dist/html/paint.d.ts.map +1 -1
- package/dist/html/paint.js +2 -2
- package/dist/html/paint.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -1
- package/dist/maps/clip.d.ts +43 -0
- package/dist/maps/clip.d.ts.map +1 -0
- package/dist/maps/clip.js +171 -0
- package/dist/maps/clip.js.map +1 -0
- package/dist/maps/gzip.d.ts +15 -0
- package/dist/maps/gzip.d.ts.map +1 -0
- package/dist/maps/gzip.js +56 -0
- package/dist/maps/gzip.js.map +1 -0
- package/dist/maps/index.d.ts +55 -0
- package/dist/maps/index.d.ts.map +1 -0
- package/dist/maps/index.js +141 -0
- package/dist/maps/index.js.map +1 -0
- package/dist/maps/labels.d.ts +123 -0
- package/dist/maps/labels.d.ts.map +1 -0
- package/dist/maps/labels.js +323 -0
- package/dist/maps/labels.js.map +1 -0
- package/dist/maps/mvt.d.ts +244 -0
- package/dist/maps/mvt.d.ts.map +1 -0
- package/dist/maps/mvt.js +820 -0
- package/dist/maps/mvt.js.map +1 -0
- package/dist/maps/node.d.ts +278 -0
- package/dist/maps/node.d.ts.map +1 -0
- package/dist/maps/node.js +1459 -0
- package/dist/maps/node.js.map +1 -0
- package/dist/maps/overlay.d.ts +157 -0
- package/dist/maps/overlay.d.ts.map +1 -0
- package/dist/maps/overlay.js +472 -0
- package/dist/maps/overlay.js.map +1 -0
- package/dist/maps/paint.d.ts +226 -0
- package/dist/maps/paint.d.ts.map +1 -0
- package/dist/maps/paint.js +705 -0
- package/dist/maps/paint.js.map +1 -0
- package/dist/maps/proj.d.ts +281 -0
- package/dist/maps/proj.d.ts.map +1 -0
- package/dist/maps/proj.js +451 -0
- package/dist/maps/proj.js.map +1 -0
- package/dist/maps/sources.d.ts +256 -0
- package/dist/maps/sources.d.ts.map +1 -0
- package/dist/maps/sources.js +210 -0
- package/dist/maps/sources.js.map +1 -0
- package/dist/maps/style.d.ts +141 -0
- package/dist/maps/style.d.ts.map +1 -0
- package/dist/maps/style.js +147 -0
- package/dist/maps/style.js.map +1 -0
- package/dist/maps/styles.d.ts +82 -0
- package/dist/maps/styles.d.ts.map +1 -0
- package/dist/maps/styles.js +898 -0
- package/dist/maps/styles.js.map +1 -0
- package/dist/maps/tiles.d.ts +283 -0
- package/dist/maps/tiles.d.ts.map +1 -0
- package/dist/maps/tiles.js +469 -0
- package/dist/maps/tiles.js.map +1 -0
- package/dist/maps/types.d.ts +244 -0
- package/dist/maps/types.d.ts.map +1 -0
- package/dist/maps/types.js +2 -0
- package/dist/maps/types.js.map +1 -0
- package/dist/markdown/ast.d.ts +80 -6
- package/dist/markdown/ast.d.ts.map +1 -1
- package/dist/markdown/ast.js +13 -4
- package/dist/markdown/ast.js.map +1 -1
- package/dist/markdown/expressions.d.ts +27 -0
- package/dist/markdown/expressions.d.ts.map +1 -0
- package/dist/markdown/expressions.js +203 -0
- package/dist/markdown/expressions.js.map +1 -0
- package/dist/markdown/index.d.ts +61 -2
- package/dist/markdown/index.d.ts.map +1 -1
- package/dist/markdown/index.js +101 -2
- package/dist/markdown/index.js.map +1 -1
- package/dist/markdown/parse.d.ts +1 -1
- package/dist/markdown/parse.d.ts.map +1 -1
- package/dist/markdown/parse.js +163 -15
- package/dist/markdown/parse.js.map +1 -1
- package/dist/markdown/spans.d.ts.map +1 -1
- package/dist/markdown/spans.js +4 -0
- package/dist/markdown/spans.js.map +1 -1
- package/dist/markdown/tags.d.ts +35 -0
- package/dist/markdown/tags.d.ts.map +1 -0
- package/dist/markdown/tags.js +213 -0
- package/dist/markdown/tags.js.map +1 -0
- package/dist/reorder/hx.d.ts +18 -0
- package/dist/reorder/hx.d.ts.map +1 -0
- package/dist/reorder/hx.js +10 -0
- package/dist/reorder/hx.js.map +1 -0
- package/dist/reorder/index.d.ts +314 -0
- package/dist/reorder/index.d.ts.map +1 -0
- package/dist/reorder/index.js +1539 -0
- package/dist/reorder/index.js.map +1 -0
- package/dist/reorder/model.d.ts +107 -0
- package/dist/reorder/model.d.ts.map +1 -0
- package/dist/reorder/model.js +162 -0
- package/dist/reorder/model.js.map +1 -0
- package/dist/richtext/node.d.ts +15 -5
- package/dist/richtext/node.d.ts.map +1 -1
- package/dist/richtext/node.js +40 -11
- package/dist/richtext/node.js.map +1 -1
- package/dist/richtext/runs.d.ts +35 -13
- package/dist/richtext/runs.d.ts.map +1 -1
- package/dist/richtext/runs.js +83 -27
- package/dist/richtext/runs.js.map +1 -1
- package/dist/tabs/index.d.ts +17 -0
- package/dist/tabs/index.d.ts.map +1 -1
- package/dist/tabs/index.js +849 -186
- package/dist/tabs/index.js.map +1 -1
- package/dist/terminal/vt/fonts.d.ts +45 -15
- package/dist/terminal/vt/fonts.d.ts.map +1 -1
- package/dist/terminal/vt/fonts.js +89 -19
- package/dist/terminal/vt/fonts.js.map +1 -1
- package/dist/terminal/vt/node.d.ts +42 -0
- package/dist/terminal/vt/node.d.ts.map +1 -1
- package/dist/terminal/vt/node.js +95 -11
- package/dist/terminal/vt/node.js.map +1 -1
- package/dist/terminal/vt/renderer.d.ts.map +1 -1
- package/dist/terminal/vt/renderer.js +13 -3
- package/dist/terminal/vt/renderer.js.map +1 -1
- package/package.json +14 -3
- package/src/charts/components.ts +14 -7
- package/src/charts/node.ts +81 -26
- package/src/charts/render.ts +16 -6
- package/src/code-editor/node.ts +147 -53
- package/src/flow/draw.ts +104 -35
- package/src/flow/index.ts +33 -13
- package/src/flow/model.ts +4 -2
- package/src/flow/node.ts +158 -59
- package/src/flow/types.ts +46 -21
- package/src/formula/index.ts +4 -2
- package/src/formula/node.ts +24 -5
- package/src/html/controls.ts +4 -1
- package/src/html/css/cascade.ts +18 -7
- package/src/html/css/parse.ts +46 -21
- package/src/html/css/style.ts +6 -1
- package/src/html/css/values.ts +25 -9
- package/src/html/index.ts +1 -0
- package/src/html/layout/boxes.ts +19 -9
- package/src/html/layout/inline.ts +23 -1
- package/src/html/node.ts +110 -17
- package/src/html/paint.ts +17 -2
- package/src/index.ts +102 -0
- package/src/maps/clip.ts +184 -0
- package/src/maps/gzip.ts +66 -0
- package/src/maps/index.ts +316 -0
- package/src/maps/labels.ts +442 -0
- package/src/maps/mvt.ts +857 -0
- package/src/maps/node.ts +1819 -0
- package/src/maps/overlay.ts +639 -0
- package/src/maps/paint.ts +978 -0
- package/src/maps/proj.ts +641 -0
- package/src/maps/sources.ts +425 -0
- package/src/maps/style.ts +309 -0
- package/src/maps/styles.ts +1040 -0
- package/src/maps/tiles.ts +676 -0
- package/src/maps/types.ts +260 -0
- package/src/markdown/ast.ts +85 -9
- package/src/markdown/expressions.ts +223 -0
- package/src/markdown/index.ts +190 -5
- package/src/markdown/parse.ts +230 -15
- package/src/markdown/spans.ts +4 -0
- package/src/markdown/tags.ts +240 -0
- package/src/reorder/hx.ts +31 -0
- package/src/reorder/index.ts +2223 -0
- package/src/reorder/model.ts +232 -0
- package/src/richtext/node.ts +49 -14
- package/src/richtext/runs.ts +115 -30
- package/src/tabs/index.ts +1040 -204
- package/src/terminal/vt/fonts.ts +128 -36
- package/src/terminal/vt/node.ts +105 -12
- package/src/terminal/vt/renderer.ts +13 -3
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// Scanning a JSX-shaped tag, for the MDX direction (docs/prd-mdx.md).
|
|
2
|
+
//
|
|
3
|
+
// Deliberately not a JavaScript parser, and deliberately not an HTML one.
|
|
4
|
+
// What it recognises is `<Name …>`, `</Name>` and `<Name … />` where `Name`
|
|
5
|
+
// is a component the *caller* claims — a tag whose name nobody claims is not
|
|
6
|
+
// a tag, it is the literal text it has always been. That one rule is what
|
|
7
|
+
// lets this exist inside a parser whose documents are full of `<box>` and
|
|
8
|
+
// `{braces}` without changing what any of them mean.
|
|
9
|
+
//
|
|
10
|
+
// Attribute values are read at parse time. A quoted string is a string, a
|
|
11
|
+
// bare name is `true`, and `{…}` is **JSON** — until the caller passes
|
|
12
|
+
// `expressions`, when a brace that is not JSON is kept as *source* for
|
|
13
|
+
// someone else to compile (docs/prd-mdx.md, M2). Nothing is evaluated here
|
|
14
|
+
// on either rung: this file finds where an expression ends, and holding it
|
|
15
|
+
// as text is what lets one parse be rendered against two scopes.
|
|
16
|
+
//
|
|
17
|
+
// Finding where it ends is the only part that has to know about JavaScript,
|
|
18
|
+
// and it knows the least it can: strings (including template literals and
|
|
19
|
+
// their `${…}` holes), comments, and bracket depth. It never parses an
|
|
20
|
+
// expression, the way `src/qml/parse.ts` never does.
|
|
21
|
+
import type { AttributeValue } from './ast.js';
|
|
22
|
+
|
|
23
|
+
/** A tag's shape. `end` is the index just past its `>`. */
|
|
24
|
+
export interface ScannedTag {
|
|
25
|
+
kind: 'open' | 'close' | 'self';
|
|
26
|
+
name: string;
|
|
27
|
+
attributes: Record<string, AttributeValue>;
|
|
28
|
+
end: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* What a scan can say. `null` is "not a tag, never will be"; `'incomplete'`
|
|
33
|
+
* is "could still become one if more text arrives", which is what a
|
|
34
|
+
* streaming document needs in order to hold the tail back rather than
|
|
35
|
+
* flashing `<Cha` on the screen.
|
|
36
|
+
*/
|
|
37
|
+
export type ScanResult = ScannedTag | 'incomplete' | null;
|
|
38
|
+
|
|
39
|
+
/** A component name, dotted paths included. Deliberately not HTML's. */
|
|
40
|
+
const RE_NAME = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*/;
|
|
41
|
+
/** An attribute name: JSX's, plus the `-` and `:` that data attributes use. */
|
|
42
|
+
const RE_ATTR = /^[A-Za-z_$][\w$:-]*/;
|
|
43
|
+
|
|
44
|
+
function isSpace(ch: string | undefined): boolean {
|
|
45
|
+
return ch === ' ' || ch === '\t' || ch === '\n' || ch === '\r';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The index just past the closing quote of the string literal starting at
|
|
50
|
+
* `from`, or -1 if the text ends first. A template literal's `${…}` holes
|
|
51
|
+
* are walked as expressions, so a brace or a quote inside one counts for
|
|
52
|
+
* nothing outside it.
|
|
53
|
+
*/
|
|
54
|
+
function skipString(text: string, from: number): number {
|
|
55
|
+
const quote = text[from];
|
|
56
|
+
let i = from + 1;
|
|
57
|
+
while (i < text.length) {
|
|
58
|
+
const ch = text[i];
|
|
59
|
+
if (ch === '\\') {
|
|
60
|
+
i += 2;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (ch === quote) return i + 1;
|
|
64
|
+
if (quote === '`' && ch === '$' && text[i + 1] === '{') {
|
|
65
|
+
const end = closeBrace(text, i + 1);
|
|
66
|
+
if (end === -1) return -1;
|
|
67
|
+
i = end;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
i += 1;
|
|
71
|
+
}
|
|
72
|
+
return -1;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The index just past a `//` or block comment starting at `from`. */
|
|
76
|
+
function skipComment(text: string, from: number): number {
|
|
77
|
+
if (text[from + 1] === '/') {
|
|
78
|
+
const nl = text.indexOf('\n', from);
|
|
79
|
+
return nl === -1 ? text.length : nl;
|
|
80
|
+
}
|
|
81
|
+
const end = text.indexOf('*/', from + 2);
|
|
82
|
+
return end === -1 ? -1 : end + 2;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The index just past the `}` that closes the `{` at `from`, or -1 if the
|
|
87
|
+
* text ends first — the one piece here that has to know JavaScript's shape.
|
|
88
|
+
* Strings, template holes and comments are stepped over whole, so a brace
|
|
89
|
+
* inside any of them closes nothing.
|
|
90
|
+
*/
|
|
91
|
+
export function closeBrace(text: string, from: number): number {
|
|
92
|
+
let depth = 0;
|
|
93
|
+
let i = from;
|
|
94
|
+
while (i < text.length) {
|
|
95
|
+
const ch = text[i];
|
|
96
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
97
|
+
const end = skipString(text, i);
|
|
98
|
+
if (end === -1) return -1;
|
|
99
|
+
i = end;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (ch === '/' && (text[i + 1] === '/' || text[i + 1] === '*')) {
|
|
103
|
+
const end = skipComment(text, i);
|
|
104
|
+
if (end === -1) return -1;
|
|
105
|
+
i = end;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (ch === '{') depth += 1;
|
|
109
|
+
else if (ch === '}') {
|
|
110
|
+
depth -= 1;
|
|
111
|
+
if (depth === 0) return i + 1;
|
|
112
|
+
}
|
|
113
|
+
i += 1;
|
|
114
|
+
}
|
|
115
|
+
return -1;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Scan the tag starting at `text[at]`, which must be `<`.
|
|
120
|
+
*
|
|
121
|
+
* `isComponent` is asked before anything else is parsed, so a `<` that opens
|
|
122
|
+
* nothing anybody claims costs one regex and a lookup.
|
|
123
|
+
*
|
|
124
|
+
* `expressions` is the second rung: with it, a `{…}` that is not JSON is
|
|
125
|
+
* kept as source instead of making the tag unreadable, and `{...spread}`
|
|
126
|
+
* becomes an attribute. Without it — the default — neither exists, and a
|
|
127
|
+
* document can only hand a component data it wrote down literally.
|
|
128
|
+
*/
|
|
129
|
+
export function scanTag(
|
|
130
|
+
text: string,
|
|
131
|
+
at: number,
|
|
132
|
+
isComponent: (name: string) => boolean,
|
|
133
|
+
expressions = false,
|
|
134
|
+
): ScanResult {
|
|
135
|
+
if (text[at] !== '<') return null;
|
|
136
|
+
let i = at + 1;
|
|
137
|
+
|
|
138
|
+
const close = text[i] === '/';
|
|
139
|
+
if (close) i += 1;
|
|
140
|
+
|
|
141
|
+
const nameMatch = RE_NAME.exec(text.slice(i));
|
|
142
|
+
if (!nameMatch) {
|
|
143
|
+
// `<` at the very end could still grow into a tag; anything else is text.
|
|
144
|
+
return i >= text.length ? 'incomplete' : null;
|
|
145
|
+
}
|
|
146
|
+
const name = nameMatch[0];
|
|
147
|
+
i += name.length;
|
|
148
|
+
// A name that reaches the end may still be growing — `<Cha` could be
|
|
149
|
+
// `<Chart`, and a document that decided too early would flash the wrong
|
|
150
|
+
// thing. Only ask about names we have all of.
|
|
151
|
+
if (i >= text.length) return 'incomplete';
|
|
152
|
+
if (!isComponent(name)) return null;
|
|
153
|
+
|
|
154
|
+
if (close) {
|
|
155
|
+
while (isSpace(text[i])) i += 1;
|
|
156
|
+
if (i >= text.length) return 'incomplete';
|
|
157
|
+
if (text[i] !== '>') return null;
|
|
158
|
+
return { kind: 'close', name, attributes: {}, end: i + 1 };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const attributes: Record<string, AttributeValue> = {};
|
|
162
|
+
let spreads = 0;
|
|
163
|
+
for (;;) {
|
|
164
|
+
const hadSpace = isSpace(text[i]);
|
|
165
|
+
while (isSpace(text[i])) i += 1;
|
|
166
|
+
if (i >= text.length) return 'incomplete';
|
|
167
|
+
|
|
168
|
+
if (text[i] === '>') return { kind: 'open', name, attributes, end: i + 1 };
|
|
169
|
+
if (text[i] === '/') {
|
|
170
|
+
i += 1;
|
|
171
|
+
while (isSpace(text[i])) i += 1;
|
|
172
|
+
if (i >= text.length) return 'incomplete';
|
|
173
|
+
if (text[i] !== '>') return null;
|
|
174
|
+
return { kind: 'self', name, attributes, end: i + 1 };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// `<Chart data="x"height={2}>` is a typo, not a tag.
|
|
178
|
+
if (!hadSpace) return null;
|
|
179
|
+
|
|
180
|
+
// `{...props}` — an attribute with no name. Its key records where it
|
|
181
|
+
// sat among the named ones, because a spread after `height` overrides
|
|
182
|
+
// it and one before it does not; `...` cannot collide with a real
|
|
183
|
+
// attribute name, which must start with a letter.
|
|
184
|
+
if (text[i] === '{') {
|
|
185
|
+
if (!expressions) return null;
|
|
186
|
+
const end = closeBrace(text, i);
|
|
187
|
+
if (end === -1) return 'incomplete';
|
|
188
|
+
const inner = text.slice(i + 1, end - 1).trim();
|
|
189
|
+
if (!inner.startsWith('...')) return null;
|
|
190
|
+
attributes[`...${spreads}`] = {
|
|
191
|
+
kind: 'expression',
|
|
192
|
+
src: inner.slice(3).trim(),
|
|
193
|
+
};
|
|
194
|
+
spreads += 1;
|
|
195
|
+
i = end;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const attr = RE_ATTR.exec(text.slice(i));
|
|
200
|
+
if (!attr) return null;
|
|
201
|
+
const key = attr[0];
|
|
202
|
+
i += key.length;
|
|
203
|
+
if (i >= text.length) return 'incomplete';
|
|
204
|
+
|
|
205
|
+
if (text[i] !== '=') {
|
|
206
|
+
// A bare attribute is `true`, as it is in JSX.
|
|
207
|
+
attributes[key] = { kind: 'literal', value: true };
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
i += 1;
|
|
211
|
+
if (i >= text.length) return 'incomplete';
|
|
212
|
+
|
|
213
|
+
const ch = text[i];
|
|
214
|
+
if (ch === '"' || ch === "'") {
|
|
215
|
+
const end = text.indexOf(ch, i + 1);
|
|
216
|
+
if (end === -1) return 'incomplete';
|
|
217
|
+
attributes[key] = { kind: 'literal', value: text.slice(i + 1, end) };
|
|
218
|
+
i = end + 1;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (ch === '{') {
|
|
222
|
+
const end = closeBrace(text, i);
|
|
223
|
+
if (end === -1) return 'incomplete';
|
|
224
|
+
const src = text.slice(i + 1, end - 1);
|
|
225
|
+
try {
|
|
226
|
+
attributes[key] = { kind: 'literal', value: JSON.parse(src) };
|
|
227
|
+
} catch {
|
|
228
|
+
// Not JSON. On the rung that compiles, that is an expression and it
|
|
229
|
+
// is kept as source; on the rung that does not, it is unreadable and
|
|
230
|
+
// the tag is text.
|
|
231
|
+
if (!expressions) return null;
|
|
232
|
+
attributes[key] = { kind: 'expression', src: src.trim() };
|
|
233
|
+
}
|
|
234
|
+
i = end;
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
// An unquoted value is HTML's, not JSX's.
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// `React.createElement`, typed against react-x11's host elements — a copy of
|
|
2
|
+
// `src/tabs/hx.ts`, duplicated on purpose: components in this package do not
|
|
3
|
+
// import each other (a lateral import welds two components into one
|
|
4
|
+
// tree-shaking unit — see AGENTS.md), and thirty shared lines are cheaper
|
|
5
|
+
// than that. See `src/internal/hx.ts` for the full why of the shape.
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import type { Key, ReactElement, ReactNode } from 'react';
|
|
8
|
+
import type { ReactX11Elements, Theme } from 'react-x11';
|
|
9
|
+
|
|
10
|
+
/** The host elements, by name. */
|
|
11
|
+
export type Host = ReactX11Elements;
|
|
12
|
+
|
|
13
|
+
interface CommonProps {
|
|
14
|
+
key?: Key;
|
|
15
|
+
/** Honoured by every node at runtime; declared only on `<window>` — the
|
|
16
|
+
* same narrow declaration the calendar works around. */
|
|
17
|
+
theme?: Theme | Record<string, string | number>;
|
|
18
|
+
/** The query hook every component forwards (docs/README.md,
|
|
19
|
+
* "Conventions"). react-x11 passes `data-*` through; the declarations
|
|
20
|
+
* just do not spell it, so it is added here rather than cast away at
|
|
21
|
+
* every call site. */
|
|
22
|
+
'data-testname'?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function hx<K extends keyof Host>(
|
|
26
|
+
type: K,
|
|
27
|
+
props?: (Omit<Host[K], 'theme'> & CommonProps) | null,
|
|
28
|
+
...children: ReactNode[]
|
|
29
|
+
): ReactElement {
|
|
30
|
+
return React.createElement(type as string, props as never, ...children);
|
|
31
|
+
}
|