Skip to content

Commit 1a357fb

Browse files
authored
Merge pull request #405 from etodanik/compatibility
Improve compatibility with more browser-like environments
2 parents 7b4608f + 49c7352 commit 1a357fb

File tree

10 files changed

+967
-3
lines changed

10 files changed

+967
-3
lines changed

packages/babel-plugin-jsx-dom-expressions/README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,24 @@ Checks for properly formed HTML by checking for elements that would not be allow
157157
### omitNestedClosingTags
158158

159159
- Type: `boolean`
160-
- Default: `true`
160+
- Default: `false`
161161

162162
Removes unnecessary closing tags from the template output. This may not work in all browser-like environments the same. The solution has been tested again Chrome/Edge/Firefox/Safari.
163163

164+
### omitLastClosingTag
165+
166+
- Type: `boolean`
167+
- Default: `true`
168+
169+
Removes tags from the template output if they have no closing parents and are the last element. This may not work in all browser-like environments the same. The solution has been tested again Chrome/Edge/Firefox/Safari.
170+
171+
### omitQuotes
172+
173+
- Type: `boolean`
174+
- Default: `true`
175+
176+
Removes quotes for html attributes when possible from the template output. This may not work in all browser-like environments the same. The solution has been tested again Chrome/Edge/Firefox/Safari.
177+
164178
## Special Binding
165179

166180
### ref

packages/babel-plugin-jsx-dom-expressions/src/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ export default {
88
requireImportSource: false,
99
wrapConditionals: true,
1010
omitNestedClosingTags: false,
11+
omitLastClosingTag: true,
12+
omitQuotes: true,
1113
contextToCustomElements: false,
1214
staticMarker: "@once",
1315
effectWrapper: "effect",

packages/babel-plugin-jsx-dom-expressions/src/dom/element.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export function transformElement(path, info) {
122122
if (!voidTag) {
123123
// always close tags can still be skipped if they have no closing parents and are the last element
124124
const toBeClosed =
125-
!info.lastElement ||
125+
(!info.lastElement || !config.omitLastClosingTag) ||
126126
(info.toBeClosed && (!config.omitNestedClosingTags || info.toBeClosed.has(tagName)));
127127
if (toBeClosed) {
128128
results.toBeClosed = new Set(info.toBeClosed || alwaysClose);
@@ -839,7 +839,7 @@ function transformAttributes(path, results) {
839839

840840
let text = value.value;
841841
if (typeof text === "number") text = String(text);
842-
let needsQuoting = false;
842+
let needsQuoting = !config.omitQuotes;
843843

844844
if (key === "style" || key === "class") {
845845
text = trimWhitespace(text);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const template = (
2+
<svg width="300" height="130" xmlns="http://www.w3.org/2000/svg">
3+
<rect width="200" height="100" x="10" y="10" rx="20" ry="20" fill="blue" />
4+
</svg>
5+
);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { template as _$template } from "r-dom";
2+
var _tmpl$ = /*#__PURE__*/ _$template(
3+
`<svg width="300"height="130"xmlns="http://www.w3.org/2000/svg"><rect width="200"height="100"x="10"y="10"rx="20"ry="20"fill="blue"></rect></svg>`
4+
);
5+
const template = _tmpl$();
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
import * as styles from "./styles.module.css";
2+
import { binding } from "somewhere";
3+
4+
function refFn() {}
5+
const refConst = null;
6+
7+
const selected = true;
8+
let id = "my-h1";
9+
let link;
10+
const template = (
11+
<div id="main" {...results} classList={{ selected: unknown }} style={{ color }}>
12+
<h1
13+
class="base"
14+
id={id}
15+
{...results()}
16+
foo
17+
disabled
18+
title={welcoming()}
19+
style={{ "background-color": color(), "margin-right": "40px" }}
20+
classList={{ dynamic: dynamic(), selected }}
21+
>
22+
<a href={"/"} ref={link} classList={{ "ccc ddd": true }}>
23+
Welcome
24+
</a>
25+
</h1>
26+
</div>
27+
);
28+
29+
const template2 = (
30+
<div {...getProps("test")}>
31+
<div textContent={rowId} />
32+
<div textContent={row.label} />
33+
<div innerHTML={"<div/>"} />
34+
</div>
35+
);
36+
37+
const template3 = (
38+
<div
39+
foo
40+
id={/*@once*/ state.id}
41+
style={/*@once*/ { "background-color": state.color }}
42+
name={state.name}
43+
textContent={/*@once*/ state.content}
44+
/>
45+
);
46+
47+
const template4 = <div class="hi" className={state.class} classList={{ "ccc:ddd": true }} />;
48+
49+
const template5 = <div class="a" className="b"></div>;
50+
51+
const template6 = <div style={someStyle()} textContent="Hi" />;
52+
53+
let undefVar;
54+
const template7 = (
55+
<div
56+
style={{ "background-color": color(), "margin-right": "40px", ...props.style }}
57+
style:padding-top={props.top}
58+
class:my-class={props.active}
59+
class:other-class={undefVar}
60+
classList={{ "other-class2": undefVar }}
61+
/>
62+
);
63+
64+
let refTarget;
65+
const template8 = <div ref={refTarget} />;
66+
67+
const template9 = <div ref={e => console.log(e)} />;
68+
69+
const template10 = <div ref={refFactory()} />;
70+
71+
const template11 = <div use:something use:another={thing} use:zero={0} />;
72+
73+
const template12 = <div prop:htmlFor={thing} prop:number={123} attr:onclick="console.log('hi')" />;
74+
75+
const template13 = <input type="checkbox" checked={true} />;
76+
77+
const template14 = <input type="checkbox" checked={state.visible} />;
78+
79+
const template15 = <div class="`a">`$`</div>;
80+
81+
const template16 = (
82+
<button
83+
class="static"
84+
classList={{
85+
hi: "k"
86+
}}
87+
type="button"
88+
>
89+
Write
90+
</button>
91+
);
92+
93+
const template17 = (
94+
<button
95+
classList={{
96+
a: true,
97+
b: true,
98+
c: true
99+
}}
100+
onClick={increment}
101+
>
102+
Hi
103+
</button>
104+
);
105+
106+
const template18 = (
107+
<div
108+
{...{
109+
get [key()]() {
110+
return props.value;
111+
}
112+
}}
113+
/>
114+
);
115+
116+
const template19 = <div classList={{ "bg-red-500": true }} class="flex flex-col" />;
117+
118+
const template20 = (
119+
<div>
120+
<input value={s()} min={min()} max={max()} onInput={doSomething} readonly="" />
121+
<input checked={s2()} min={min()} max={max()} onInput={doSomethingElse} readonly={value} />
122+
</div>
123+
);
124+
125+
const template21 = <div style={{ a: "static", ...rest }}></div>;
126+
127+
const template22 = <div data='"hi"' data2={'"'} />;
128+
129+
const template23 = <div disabled={"t" in test}>{"t" in test && "true"}</div>;
130+
131+
const template24 = <a {...props} something />;
132+
133+
const template25 = (
134+
<div>
135+
{props.children}
136+
<a {...props} something />
137+
</div>
138+
);
139+
140+
const template26 = (
141+
<div start="Hi" middle={middle} {...spread}>
142+
Hi
143+
</div>
144+
);
145+
146+
const template27 = (
147+
<div start="Hi" {...first} middle={middle} {...second}>
148+
Hi
149+
</div>
150+
);
151+
152+
const template28 = (
153+
<label {...api()}>
154+
<span {...api()}>Input is {api() ? "checked" : "unchecked"}</span>
155+
<input {...api()} />
156+
<div {...api()} />
157+
</label>
158+
);
159+
160+
const template29 = <div attribute={!!someValue}>{!!someValue}</div>;
161+
162+
const template30 = (
163+
<div
164+
class="class1 class2
165+
class3 class4
166+
class5 class6"
167+
style="color: red;
168+
background-color: blue !important;
169+
border: 1px solid black;
170+
font-size: 12px;"
171+
random="random1 random2
172+
random3 random4"
173+
/>
174+
);
175+
176+
const template31 = <div style={{ "background-color": getStore.itemProperties.color }} />;
177+
178+
const template32 = <div style={{ "background-color": undefined }} />;
179+
180+
const template33 = (
181+
<>
182+
<button class={styles.button}></button>
183+
<button class={styles["foo--bar"]}></button>
184+
<button class={styles.foo.bar}></button>
185+
<button class={styles[foo()]}></button>
186+
</>
187+
);
188+
189+
const template34 = <div use:something {...somethingElse} use:zero={0} />;
190+
191+
const template35 = <div ref={a().b.c} />;
192+
193+
const template36 = <div ref={a().b?.c} />;
194+
195+
const template37 = <div ref={a() ? b : c} />;
196+
197+
const template38 = <div ref={a() ?? b} />;
198+
199+
const template39 = <input value={10} />;
200+
201+
const template40 = <div style={{ color: a() }} />;
202+
203+
const template41 = (
204+
<select value={state.color}>
205+
<option value={Color.Red}>Red</option>
206+
<option value={Color.Blue}>Blue</option>
207+
</select>
208+
);
209+
210+
// bool:
211+
function boolTest(){return true}
212+
const boolTestBinding = false
213+
const boolTestObjBinding = {value:false}
214+
215+
const template42 = <div bool:quack="">empty string</div>;
216+
const template43 = <div bool:quack={""}>js empty</div>;
217+
const template44 = <div bool:quack="hola">hola</div>;
218+
const template45 = <div bool:quack={"hola js"}>"hola js"</div>;
219+
const template46 = <div bool:quack={true}>true</div>;
220+
const template47 = <div bool:quack={false}>false</div>;
221+
const template48 = <div bool:quack={1}>1</div>;
222+
const template49 = <div bool:quack={0}>0</div>;
223+
const template50 = <div bool:quack={"1"}>"1"</div>;
224+
const template51 = <div bool:quack={"0"}>"0"</div>;
225+
const template52 = <div bool:quack={undefined}>undefined</div>;
226+
const template53 = <div bool:quack={null}>null</div>;
227+
const template54 = <div bool:quack={boolTest()}>boolTest()</div>;
228+
const template55 = <div bool:quack={boolTest}>boolTest</div>;
229+
const template56 = <div bool:quack={boolTestBinding}>boolTestBinding</div>;
230+
const template57 = <div bool:quack={boolTestObjBinding.value}>boolTestObjBinding.value</div>;
231+
const template58 = <div bool:quack={()=>false}>fn</div>;
232+
233+
const template59 = <div before bool:quack="true">should have space before</div>;
234+
const template60 = <div before bool:quack="true" after>should have space before/after</div>;
235+
const template61 = <div bool:quack="true" after>should have space before/after</div>;
236+
// this crash it for some reason- */ const template62 = <div bool:quack>really empty</div>;
237+
238+
const template63 = <img src="" />;
239+
const template64 = <div><img src=""/></div>;
240+
241+
const template65 = <img src="" loading="lazy"/>;
242+
const template66 = <div><img src="" loading="lazy"/></div>;
243+
244+
const template67 = <iframe src=""></iframe>;
245+
const template68 = <div><iframe src=""></iframe></div>;
246+
247+
const template69 = <iframe src="" loading="lazy"></iframe>;
248+
const template70 = <div><iframe src="" loading="lazy"></iframe></div>;
249+
250+
const template71 = <div title="<u>data</u>"/>
251+
252+
const template72 = <div ref={binding} />;
253+
const template73 = <div ref={binding.prop} />;
254+
const template74 = <div ref={refFn} />
255+
const template75 = <div ref={refConst} />
256+
257+
const template76 = <div ref={refUnknown} />
258+
259+
const template77 = <div true={true} truestr="true" truestrjs={"true"}/>
260+
const template78 = <div false={false} falsestr="false" falsestrjs={"false"} />
261+
const template79 = <div prop:true={true} prop:false={false}/>
262+
const template80 = <div attr:true={true} attr:false={false}/>
263+
264+
const template81 = <math display="block"><mrow></mrow></math>
265+
const template82 = <mrow><mi>x</mi><mo>=</mo></mrow>
266+

0 commit comments

Comments
 (0)