From f99c1462dd04a938f9a161b063fe0541f8b68165 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sat, 22 Jun 2024 08:57:40 -0500 Subject: [PATCH 1/7] feat: Support `prop:` and `attr:` directives --- src/diff/props.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/diff/props.js b/src/diff/props.js index 316146f0fd..2a564a8a18 100644 --- a/src/diff/props.js +++ b/src/diff/props.js @@ -35,7 +35,9 @@ let eventClock = 0; * @param {string} namespace Whether or not this DOM node is an SVG node or not */ export function setProperty(dom, name, value, oldValue, namespace) { - let useCapture; + let useCapture, + split = name.split(':'); + name = name.replace(/(.+):/, ''); o: if (name === 'style') { if (typeof value == 'string') { @@ -104,6 +106,8 @@ export function setProperty(dom, name, value, oldValue, namespace) { // - className --> class name = name.replace(/xlink(H|:h)/, 'h').replace(/sName$/, 's'); } else if ( + split[0] == 'prop' || + split[0] != 'attr' && name != 'width' && name != 'height' && name != 'href' && From 60e6e7e5c50ca79929f22f48215bb5c99724c2c1 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sat, 22 Jun 2024 08:58:03 -0500 Subject: [PATCH 2/7] test: Add tests & ensure Babel supports namespaced props --- babel.config.js | 2 +- test/browser/render.test.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/babel.config.js b/babel.config.js index 9601cdf30b..1ef9948eca 100644 --- a/babel.config.js +++ b/babel.config.js @@ -31,7 +31,7 @@ module.exports = function (api) { ], plugins: [ '@babel/plugin-proposal-object-rest-spread', - '@babel/plugin-transform-react-jsx', + ['@babel/plugin-transform-react-jsx', { throwIfNamespace: false }], 'babel-plugin-transform-async-to-promises', ['babel-plugin-transform-rename-properties', { rename }] ], diff --git a/test/browser/render.test.js b/test/browser/render.test.js index 4755607c12..2ec29214f6 100644 --- a/test/browser/render.test.js +++ b/test/browser/render.test.js @@ -631,6 +631,17 @@ describe('render()', () => { expect(links[3].hasAttribute('href')).to.equal(true); }); + it('should support using `prop:` directive to set properties', () => { + render(, scratch); + expect(scratch.firstChild.foo).to.equal('bar'); + expect(scratch.firstChild.getAttribute('foo')).to.equal(null); + }); + + it('should support using `attr:` directive to set attributes', () => { + render(, scratch); + expect(scratch.firstChild.getAttribute('value')).to.equal('foo'); + }); + describe('dangerouslySetInnerHTML', () => { it('should support dangerouslySetInnerHTML', () => { let html = 'foo & bar'; From 4a23fa276b5d4bd1d74dbe032cd60dc46fb61040 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Sat, 22 Jun 2024 09:59:10 -0500 Subject: [PATCH 3/7] refactor: Better perf? --- src/diff/props.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/diff/props.js b/src/diff/props.js index 2a564a8a18..67b711333d 100644 --- a/src/diff/props.js +++ b/src/diff/props.js @@ -37,7 +37,7 @@ let eventClock = 0; export function setProperty(dom, name, value, oldValue, namespace) { let useCapture, split = name.split(':'); - name = name.replace(/(.+):/, ''); + if (split.length > 1) name = split[1]; o: if (name === 'style') { if (typeof value == 'string') { @@ -107,21 +107,21 @@ export function setProperty(dom, name, value, oldValue, namespace) { name = name.replace(/xlink(H|:h)/, 'h').replace(/sName$/, 's'); } else if ( split[0] == 'prop' || - split[0] != 'attr' && - name != 'width' && - name != 'height' && - name != 'href' && - name != 'list' && - name != 'form' && - // Default value in browsers is `-1` and an empty string is - // cast to `0` instead - name != 'tabIndex' && - name != 'download' && - name != 'rowSpan' && - name != 'colSpan' && - name != 'role' && - name != 'popover' && - name in dom + (split[0] != 'attr' && + name != 'width' && + name != 'height' && + name != 'href' && + name != 'list' && + name != 'form' && + // Default value in browsers is `-1` and an empty string is + // cast to `0` instead + name != 'tabIndex' && + name != 'download' && + name != 'rowSpan' && + name != 'colSpan' && + name != 'role' && + name != 'popover' && + name in dom) ) { try { dom[name] = value == null ? '' : value; From 64ca5dffc92a9346ffa01b67b6a784de6838c8bc Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Mon, 24 Jun 2024 21:54:09 -0500 Subject: [PATCH 4/7] refactor: Apply PR suggestions Co-authored-by: Marvin Hagemeister --- src/diff/props.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/diff/props.js b/src/diff/props.js index 67b711333d..429ad643e7 100644 --- a/src/diff/props.js +++ b/src/diff/props.js @@ -35,9 +35,15 @@ let eventClock = 0; * @param {string} namespace Whether or not this DOM node is an SVG node or not */ export function setProperty(dom, name, value, oldValue, namespace) { - let useCapture, - split = name.split(':'); - if (split.length > 1) name = split[1]; + let useCapture, prefix; + if (name[0] == 'a' || name[0] == 'p') { + let idx = name.indexOf(':'); + if (idx > -1) { + // Only slices here, should be faster than array allocation + prefix = name.slice(0, idx); + name = name.slice(idx + 1); + } + } o: if (name === 'style') { if (typeof value == 'string') { @@ -106,8 +112,7 @@ export function setProperty(dom, name, value, oldValue, namespace) { // - className --> class name = name.replace(/xlink(H|:h)/, 'h').replace(/sName$/, 's'); } else if ( - split[0] == 'prop' || - (split[0] != 'attr' && + (prefix != 'attr' && name != 'width' && name != 'height' && name != 'href' && @@ -121,7 +126,8 @@ export function setProperty(dom, name, value, oldValue, namespace) { name != 'colSpan' && name != 'role' && name != 'popover' && - name in dom) + name in dom) || + prefix == 'prop' ) { try { dom[name] = value == null ? '' : value; From 8b52a1952fa92189c6eb615178d6fa8db575e226 Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Tue, 16 Jul 2024 14:53:39 -0500 Subject: [PATCH 5/7] refactor: Apply PR suggestion Co-authored-by: Jovi De Croock --- src/diff/props.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/diff/props.js b/src/diff/props.js index 429ad643e7..ab01468fc6 100644 --- a/src/diff/props.js +++ b/src/diff/props.js @@ -36,13 +36,9 @@ let eventClock = 0; */ export function setProperty(dom, name, value, oldValue, namespace) { let useCapture, prefix; - if (name[0] == 'a' || name[0] == 'p') { - let idx = name.indexOf(':'); - if (idx > -1) { - // Only slices here, should be faster than array allocation - prefix = name.slice(0, idx); - name = name.slice(idx + 1); - } + if (name[0] == 'a' || (name[0] == 'p' && name[5] == ':')) { + prefix = name.slice(0, 4); + name = name.slice(5); } o: if (name === 'style') { From 8edfe2a20e77f03db6441d54708f1b2931e160ba Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Tue, 16 Jul 2024 14:55:30 -0500 Subject: [PATCH 6/7] refactor: Wrong automatic parenthesis --- src/diff/props.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diff/props.js b/src/diff/props.js index ab01468fc6..0c7d4fdb0d 100644 --- a/src/diff/props.js +++ b/src/diff/props.js @@ -36,7 +36,7 @@ let eventClock = 0; */ export function setProperty(dom, name, value, oldValue, namespace) { let useCapture, prefix; - if (name[0] == 'a' || (name[0] == 'p' && name[5] == ':')) { + if ((name[0] == 'a' || name[0] == 'p') && name[5] == ':') { prefix = name.slice(0, 4); name = name.slice(5); } From a9bb51fefa04b51ff2fa1f7ca08b095ebed4805d Mon Sep 17 00:00:00 2001 From: Ryan Christian Date: Tue, 16 Jul 2024 15:00:35 -0500 Subject: [PATCH 7/7] fix: Wrong index --- src/diff/props.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diff/props.js b/src/diff/props.js index 0c7d4fdb0d..51bbd4d7e5 100644 --- a/src/diff/props.js +++ b/src/diff/props.js @@ -36,7 +36,7 @@ let eventClock = 0; */ export function setProperty(dom, name, value, oldValue, namespace) { let useCapture, prefix; - if ((name[0] == 'a' || name[0] == 'p') && name[5] == ':') { + if ((name[0] == 'a' || name[0] == 'p') && name[4] == ':') { prefix = name.slice(0, 4); name = name.slice(5); }