Skip to content

Commit 34d43ae

Browse files
Merge pull request #571 from Shopify/rd/fix-innerHTML
fix innerHTML not allowing newlines before attributes
2 parents c36a650 + 0bba42b commit 34d43ae

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

.changeset/chilled-items-eat.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@remote-dom/polyfill': patch
3+
---
4+
5+
fix Element.innerHTML not allowing newlines before attributes

packages/polyfill/source/serialization.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ import type {Element} from './Element.ts';
2222
// const attributeTokenizer = / ([^<>'"\n=\s]+)=(['"])([^>'"\n]*)\2/g;
2323

2424
const elementTokenizer =
25-
/(?:<([a-z][a-z0-9-:]*)((?:\s[^<>'"=\n\s]+(?:=(['"])[^\n]*?\3|=[^>'"\n\s]*|))*)\s*(\/?)\s*>|<\/([a-z][a-z0-9-:]*)>|<!--(.*?)-->|([^&<>]+))/gi;
25+
/(?:<([a-z][a-z0-9-:]*)((?:[\s]+[^<>'"=\s]+(?:=(['"])[^]*?\3|=[^>'"\s]*|))*)[\s]*(\/?)\s*>|<\/([a-z][a-z0-9-:]*)>|<!--(.*?)-->|([^&<>]+))/gi;
2626

2727
const attributeTokenizer =
28-
/\s([^<>'"=\n\s]+)(?:=(['"])([^\n]*?)\2|=([^>'"\n\s]*)|)/g;
28+
/\s([^<>'"=\n\s]+)(?:=(["'])([\s\S]*?)\2|=([^>'"\n\s]*)|)/g;
2929

3030
export function parseHtml(html: string, contextNode: Node) {
3131
const document = contextNode.ownerDocument;
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {Window} from '../index.ts';
2+
3+
import {describe, it, expect, beforeEach} from 'vitest';
4+
5+
describe('innerHtml', () => {
6+
beforeEach(() => {
7+
const window = new Window();
8+
Window.setGlobalThis(window);
9+
});
10+
11+
it('parses a simple element', () => {
12+
const element = document.createElement('div');
13+
element.innerHTML = '<ui-button>Press me!</ui-button>';
14+
15+
const button = element.querySelector('ui-button');
16+
expect(button?.textContent).toBe('Press me!');
17+
});
18+
19+
it('parses an element with attributes', () => {
20+
const element = document.createElement('div');
21+
element.innerHTML = '<ui-button data-id="123">Press me!</ui-button>';
22+
23+
const button = element.querySelector('ui-button');
24+
expect(button?.textContent).toBe('Press me!');
25+
expect(button?.getAttribute('data-id')).toBe('123');
26+
});
27+
28+
it('parses an element with attributes on newlines', () => {
29+
const element = document.createElement('div');
30+
element.innerHTML = `<ui-button
31+
data-id="123"
32+
data-id2="456"
33+
data-id3="789"
34+
data-id4="multiline
35+
content
36+
works too"
37+
variant="primary" tone="neutral"
38+
>Press me!</ui-button>`;
39+
40+
const button = element.querySelector('ui-button');
41+
42+
expect(button?.getAttribute('data-id')).toBe('123');
43+
expect(button?.getAttribute('data-id2')).toBe('456');
44+
expect(button?.getAttribute('data-id3')).toBe('789');
45+
expect(button?.getAttribute('data-id4')).toBe(
46+
'multiline\ncontent\nworks too',
47+
);
48+
expect(button?.getAttribute('variant')).toBe('primary');
49+
expect(button?.getAttribute('tone')).toBe('neutral');
50+
});
51+
});

0 commit comments

Comments
 (0)