Skip to content

Commit 79a9c25

Browse files
committed
Attribute hook render option
1 parent e02629e commit 79a9c25

File tree

3 files changed

+72
-6
lines changed

3 files changed

+72
-6
lines changed

src/index.d.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,27 @@
11
import { VNode } from 'preact';
22

3-
export default function renderToString(vnode: VNode, context?: any): string;
3+
interface RenderOptions {
4+
attrHook?: (name: string) => string;
5+
}
46

5-
export function render(vnode: VNode, context?: any): string;
6-
export function renderToString(vnode: VNode, context?: any): string;
7-
export function renderToStaticMarkup(vnode: VNode, context?: any): string;
7+
export default function renderToString(
8+
vnode: VNode,
9+
context?: any,
10+
renderOpts?: RenderOptions
11+
): string;
12+
13+
export function render(
14+
vnode: VNode,
15+
context?: any,
16+
renderOpts?: RenderOptions
17+
): string;
18+
export function renderToString(
19+
vnode: VNode,
20+
context?: any,
21+
renderOpts?: RenderOptions
22+
): string;
23+
export function renderToStaticMarkup(
24+
vnode: VNode,
25+
context?: any,
26+
renderOpts?: RenderOptions
27+
): string;

src/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ const isArray = Array.isArray;
2121
const assign = Object.assign;
2222

2323
// Global state for the current render pass
24-
let beforeDiff, afterDiff, renderHook, ummountHook;
24+
let beforeDiff, afterDiff, renderHook, ummountHook, attrHook;
2525

2626
/**
2727
* Render Preact JSX + Components to an HTML string.
2828
* @param {VNode} vnode JSX Element / VNode to render
2929
* @param {Object} [context={}] Initial root context object
3030
* @returns {string} serialized HTML
3131
*/
32-
export function renderToString(vnode, context) {
32+
export function renderToString(vnode, context, renderOpts) {
3333
// Performance optimization: `renderToString` is synchronous and we
3434
// therefore don't execute any effects. To do that we pass an empty
3535
// array to `options._commit` (`__c`). But we can go one step further
@@ -43,6 +43,7 @@ export function renderToString(vnode, context) {
4343
afterDiff = options[DIFFED];
4444
renderHook = options[RENDER];
4545
ummountHook = options.unmount;
46+
attrHook = renderOpts?.attrHook;
4647

4748
const parent = h(Fragment, null);
4849
parent[CHILDREN] = [vnode];
@@ -399,6 +400,8 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
399400
}
400401
}
401402

403+
if (attrHook) name = attrHook(name);
404+
402405
// write this attribute to the buffer
403406
if (v != null && v !== false && typeof v !== 'function') {
404407
if (v === true || v === '') {

test/render.test.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,4 +1598,47 @@ describe('render', () => {
15981598
});
15991599
});
16001600
});
1601+
1602+
describe('Render Options', () => {
1603+
describe('Attribute Hook', () => {
1604+
it('Transforms attributes with custom attrHook option', () => {
1605+
function attrHook(name) {
1606+
const DASHED_ATTRS = /^(acceptC|httpE|(clip|color|fill|font|glyph|marker|stop|stroke|text|vert)[A-Z])/;
1607+
const CAMEL_ATTRS = /^(isP|viewB)/;
1608+
const COLON_ATTRS = /^(xlink|xml|xmlns)([A-Z])/;
1609+
const CAPITAL_REGEXP = /([A-Z])/g;
1610+
if (CAMEL_ATTRS.test(name)) return name;
1611+
if (DASHED_ATTRS.test(name))
1612+
return name.replace(CAPITAL_REGEXP, '-$1').toLowerCase();
1613+
if (COLON_ATTRS.test(name))
1614+
return name.replace(CAPITAL_REGEXP, ':$1').toLowerCase();
1615+
return name.toLowerCase();
1616+
}
1617+
1618+
const content = (
1619+
<html>
1620+
<head>
1621+
<meta charSet="utf=8" />
1622+
<meta httpEquiv="refresh" />
1623+
<link rel="preconnect" href="https://foo.com" crossOrigin />
1624+
</head>
1625+
<body>
1626+
<img srcSet="foo.png, foo2.png 2x" />
1627+
<svg xmlSpace="preserve" viewBox="0 0 10 10" fillRule="nonzero">
1628+
<foreignObject>
1629+
<div xlinkHref="#" />
1630+
</foreignObject>
1631+
</svg>
1632+
</body>
1633+
</html>
1634+
);
1635+
1636+
const expected =
1637+
'<html><head><meta charset="utf=8"/><meta http-equiv="refresh"/><link rel="preconnect" href="https://foo.com" crossorigin/></head><body><img srcset="foo.png, foo2.png 2x"/><svg xml:space="preserve" viewBox="0 0 10 10" fill-rule="nonzero"><foreignObject><div xlink:href="#"></div></foreignObject></svg></body></html>';
1638+
1639+
const rendered = render(content, {}, { attrHook });
1640+
expect(rendered).to.equal(expected);
1641+
});
1642+
});
1643+
});
16011644
});

0 commit comments

Comments
 (0)