Skip to content

Commit d369bdb

Browse files
Merge pull request #4798 from preactjs/10.x-precompile-attr
fix: signal attribute values not working with precompile transform
2 parents 2a57866 + c6defb4 commit d369bdb

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

jsx-runtime/src/index.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,19 @@ function jsxTemplate(templates, ...exprs) {
9595
const JS_TO_CSS = {};
9696
const CSS_REGEX = /[A-Z]/g;
9797

98+
/**
99+
* Unwrap potential signals.
100+
* @param {*} value
101+
* @returns {*}
102+
*/
103+
function normalizeAttrValue(value) {
104+
return value !== null &&
105+
typeof value === 'object' &&
106+
typeof value.valueOf === 'function'
107+
? value.valueOf()
108+
: value;
109+
}
110+
98111
/**
99112
* Serialize an HTML attribute to a string. This function is not
100113
* expected to be used directly, but rather through a precompile
@@ -109,6 +122,8 @@ function jsxAttr(name, value) {
109122
if (typeof result === 'string') return result;
110123
}
111124

125+
value = normalizeAttrValue(value);
126+
112127
if (name === 'ref' || name === 'key') return '';
113128
if (name === 'style' && typeof value === 'object') {
114129
let str = '';
@@ -145,7 +160,7 @@ function jsxAttr(name, value) {
145160
return '';
146161
} else if (value === true) return name;
147162

148-
return name + '="' + encodeEntities(value) + '"';
163+
return name + '="' + encodeEntities('' + value) + '"';
149164
}
150165

151166
/**

jsx-runtime/test/browser/jsx-runtime.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,24 @@ import {
1111
import { setupScratch, teardown } from '../../../test/_util/helpers';
1212
import { encodeEntities } from '../../src/utils';
1313

14+
function createSignal(value) {
15+
return {
16+
value,
17+
peek() {
18+
return value;
19+
},
20+
subscribe() {
21+
return () => {};
22+
},
23+
valueOf() {
24+
return value;
25+
},
26+
toString() {
27+
return String(value);
28+
}
29+
};
30+
}
31+
1432
describe('Babel jsx/jsxDEV', () => {
1533
let scratch;
1634
let prevVNodeOption;
@@ -167,6 +185,12 @@ describe('precompiled JSX', () => {
167185
);
168186
});
169187

188+
it('should support signals', () => {
189+
const sig = createSignal(`&<'"`);
190+
expect(jsxAttr('foo', sig)).to.equal(`foo="&amp;&lt;'&quot;"`);
191+
expect(jsxAttr('style', sig)).to.equal(`style="&amp;&lt;'&quot;"`);
192+
});
193+
170194
it('should call options.attr()', () => {
171195
options.attr = (name, value) => {
172196
return `data-${name}="foo${value}"`;

0 commit comments

Comments
 (0)