Skip to content

Commit

Permalink
[labs/ssr] Fix attribute part bindings following element part binding (
Browse files Browse the repository at this point in the history
  • Loading branch information
augustjk authored Jan 9, 2024
1 parent 9a4d569 commit ee97d08
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/sharp-suns-sing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@lit-labs/ssr': patch
---

Fix incorrect attribute names being matched to values when attribute expressions are followed by element expressions such as using the `ref` directive.
9 changes: 4 additions & 5 deletions packages/labs/ssr/src/lib/render-value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,6 @@ const getTemplateOpcodes = (
if (template !== undefined) {
return template;
}
// The property '_$litType$' needs to remain unminified.
const [html, attrNames] = getTemplateHtml(
result.strings,
// SVG TemplateResultType functionality is only required on the client,
Expand Down Expand Up @@ -445,16 +444,16 @@ const getTemplateOpcodes = (
// nodes with bindings, we don't account for it in the nodeIndex because
// that will not be injected into the client template
const strings = attr.value.split(marker);
// We store the case-sensitive name from `attrNames` (generated
// while parsing the template strings); note that this assumes
// parse5 attribute ordering matches string ordering
const name = attrNames[attrIndex++];
const attrSourceLocation =
node.sourceCodeLocation!.attrs![attr.name]!;
const attrNameStartOffset = attrSourceLocation.startOffset;
const attrEndOffset = attrSourceLocation.endOffset;
flushTo(attrNameStartOffset);
if (isAttrBinding) {
// We store the case-sensitive name from `attrNames` (generated
// while parsing the template strings); note that this assumes
// parse5 attribute ordering matches string ordering
const name = attrNames[attrIndex++];
const [, prefix, caseSensitiveName] = /([.?@])?(.*)/.exec(
name as string
)!;
Expand Down
14 changes: 14 additions & 0 deletions packages/labs/ssr/src/test/integration/tests/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3926,6 +3926,20 @@ export const tests: {[name: string]: SSRTest} = {
stableSelectors: ['div', 'span', 'p'],
},

'ElementPart followed by Multiple AttributeParts': {
render(x, y) {
const ref1 = createRef();
return html` <div ${ref(ref1)} x=${x} y=${y}></div> `;
},
expectations: [
{
args: ['x', 'y'],
html: '<div x="x" y="y"></div>',
},
],
stableSelectors: ['div'],
},

'All part types with at various depths': () => {
const handler1 = (e: Event) => ((e.target as any).triggered1 = true);
const handler2 = (e: Event) => ((e.target as any).triggered2 = true);
Expand Down
13 changes: 13 additions & 0 deletions packages/labs/ssr/src/test/lib/render-lit_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,19 @@ for (const global of [emptyVmGlobal, shimmedVmGlobal]) {
);
});

test('multiple attribute expressions with string value preceded by element expression', async () => {
const {render, templateWithElementAndMultipleAttributeExpressions} =
await setup();
const result = await render(
templateWithElementAndMultipleAttributeExpressions('foo', 'bar')
);
// Has marker attribute for number of bound attributes.
assert.is(
result,
`<!--lit-part NdVlqfEioQk=--><!--lit-node 0--><div x="foo" y="bar" z="not-dynamic"></div><!--/lit-part-->`
);
});

test('attribute expression with multiple bindings', async () => {
const {render, templateWithMultiBindingAttributeExpression} = await setup();
const result = await render(
Expand Down
6 changes: 6 additions & 0 deletions packages/labs/ssr/src/test/test-files/render-test-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import {html, svg, nothing} from 'lit';
import {repeat} from 'lit/directives/repeat.js';
import {classMap} from 'lit/directives/class-map.js';
import {ref, createRef} from 'lit/directives/ref.js';
import {LitElement, css, PropertyValues} from 'lit';
import {property, customElement} from 'lit/decorators.js';
import {html as serverhtml} from '../../lib/server-template.js';
Expand Down Expand Up @@ -36,6 +37,11 @@ export const templateWithMultipleAttributeExpressions = (
y: string
) => html`<div x=${x} y=${y} z="not-dynamic"></div>`;
// prettier-ignore
export const templateWithElementAndMultipleAttributeExpressions = (
x: string,
y: string
) => html`<div ${ref(createRef())} x=${x} y=${y} z="not-dynamic"></div>`;
// prettier-ignore
export const templateWithMultiBindingAttributeExpression = (
x: string,
y: string
Expand Down

0 comments on commit ee97d08

Please sign in to comment.