Skip to content

Commit d39a579

Browse files
authored
Merge branch 'main' into fix/template-hydration-reuse-dom
2 parents 414ce0c + 9103e8f commit d39a579

File tree

5 files changed

+57
-4
lines changed

5 files changed

+57
-4
lines changed

compat/src/forwardRef.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function forwardRef(fn) {
2222
// It expects an object here with a `render` property,
2323
// and prototype.render will fail. Without this
2424
// mobx-react throws.
25-
Forwarded.render = Forwarded;
25+
Forwarded.render = fn;
2626

2727
Forwarded.prototype.isReactComponent = true;
2828
Forwarded.displayName = 'ForwardRef(' + (fn.displayName || fn.name) + ')';

compat/test/browser/forwardRef.test.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,4 +498,15 @@ describe('forwardRef', () => {
498498

499499
expect(actual).to.equal(null);
500500
});
501+
502+
// Issue #4769
503+
it('should attach .render pointing to the original render function', () => {
504+
function Foo(props, ref) {
505+
return <div ref={ref} />;
506+
}
507+
508+
const Forwarded = forwardRef(Foo);
509+
510+
expect(Forwarded.render).to.equal(Foo);
511+
});
501512
});

jsx-runtime/src/index.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ function jsxTemplate(templates, ...exprs) {
8686
const JS_TO_CSS = {};
8787
const CSS_REGEX = /[A-Z]/g;
8888

89+
/**
90+
* Unwrap potential signals.
91+
* @param {*} value
92+
* @returns {*}
93+
*/
94+
function normalizeAttrValue(value) {
95+
return value !== null &&
96+
typeof value === 'object' &&
97+
typeof value.valueOf === 'function'
98+
? value.valueOf()
99+
: value;
100+
}
101+
89102
/**
90103
* Serialize an HTML attribute to a string. This function is not
91104
* expected to be used directly, but rather through a precompile
@@ -100,6 +113,8 @@ function jsxAttr(name, value) {
100113
if (typeof result === 'string') return result;
101114
}
102115

116+
value = normalizeAttrValue(value);
117+
103118
if (name === 'ref' || name === 'key') return '';
104119
if (name === 'style' && typeof value === 'object') {
105120
let str = '';
@@ -115,7 +130,7 @@ function jsxAttr(name, value) {
115130
str = str + name + ':' + val + ';';
116131
}
117132
}
118-
return name + '="' + str + '"';
133+
return name + '="' + encodeEntities(str) + '"';
119134
}
120135

121136
if (
@@ -127,7 +142,7 @@ function jsxAttr(name, value) {
127142
return '';
128143
} else if (value === true) return name;
129144

130-
return name + '="' + encodeEntities(value) + '"';
145+
return name + '="' + encodeEntities('' + value) + '"';
131146
}
132147

133148
/**

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

Lines changed: 27 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;
@@ -122,6 +140,15 @@ describe('precompiled JSX', () => {
122140

123141
it('should escape values', () => {
124142
expect(jsxAttr('foo', "&<'")).to.equal('foo="&amp;&lt;\'"');
143+
expect(jsxAttr('style', { foo: `"&<'"` })).to.equal(
144+
'style="foo:&quot;&amp;&lt;\'&quot;;"'
145+
);
146+
});
147+
148+
it('should support signals', () => {
149+
const sig = createSignal(`&<'"`);
150+
expect(jsxAttr('foo', sig)).to.equal(`foo="&amp;&lt;'&quot;"`);
151+
expect(jsxAttr('style', sig)).to.equal(`style="&amp;&lt;'&quot;"`);
125152
});
126153

127154
it('should call options.attr()', () => {

src/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export interface VNode<P = {}> {
3838
export type Key = string | number | any;
3939

4040
export type RefObject<T> = { current: T };
41-
export type RefCallback<T> = (instance: T | null) => void;
41+
export type RefCallback<T> = (instance: T | null) => void | (() => void);
4242
export type Ref<T> = RefCallback<T> | RefObject<T | null> | null;
4343

4444
export type ComponentChild =

0 commit comments

Comments
 (0)