Handle custom elements in nested JSX (#792)

* Handle custom elements in nested JSX

* Adds a changeset
This commit is contained in:
Matthew Phillips 2021-07-21 10:22:39 -04:00 committed by GitHub
parent b7e579a9cb
commit b85e68a713
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 35 additions and 8 deletions

View file

@ -0,0 +1,6 @@
---
'astro': patch
'@astrojs/parser': patch
---
Fixes case where custom elements are not handled within JSX expressions

View file

@ -29,7 +29,7 @@ export class Parser {
js: Script[] = [];
meta_tags = {};
last_auto_closed_tag?: LastAutoClosedTag;
feature_flags: 0;
feature_flags: number = 0;
constructor(template: string, options: ParserOptions) {
if (typeof template !== 'string') {

View file

@ -9,6 +9,7 @@ interface ParseState {
curlyCount: number;
bracketCount: number;
root: Expression;
parser: Parser;
}
function peek_char(state: ParseState) {
@ -159,12 +160,13 @@ function consume_tag(state: ParseState) {
const source = state.source.substring(start, state.index);
const ast = parseAstro(source);
state.parser.feature_flags |= ast.meta.features;
const fragment = ast.html;
return fragment;
}
function consume_expression(source: string, start: number): Expression {
function consume_expression(parser: Parser, source: string, start: number): Expression {
const expr: Expression = {
type: 'Expression',
start,
@ -182,6 +184,7 @@ function consume_expression(source: string, start: number): Expression {
curlyCount: 1,
bracketCount: 0,
root: expr,
parser,
};
do {
@ -234,15 +237,15 @@ function consume_expression(source: string, start: number): Expression {
return expr;
}
export const parse_expression_at = (source: string, index: number): Expression => {
const expression = consume_expression(source, index);
export const parse_expression_at = (parser: Parser, source: string, index: number): Expression => {
const expression = consume_expression(parser, source, index);
return expression;
};
export default function read_expression(parser: Parser) {
try {
const expression = parse_expression_at(parser.template, parser.index);
const expression = parse_expression_at(parser, parser.template, parser.index);
parser.index = expression.end;
return expression;
} catch (err) {

View file

@ -72,4 +72,12 @@ CustomElements('Custom elements not claimed by renderer are rendered as regular
assert.equal($('client-element').length, 1, 'Rendered the client-only element');
});
CustomElements('Can import a client-only element that is nested in JSX', async ({ runtime }) => {
const result = await runtime.load('/nested');
assert.ok(!result.error, 'No error loading');
const html = result.contents;
const $ = doc(html);
assert.equal($('client-only-element').length, 1, 'Element rendered');
});
CustomElements.run();

View file

@ -1,3 +1,5 @@
import './shim.js';
function getConstructor(Component) {
if(typeof Component === 'string') {
const tagName = Component;

View file

@ -1,4 +1,3 @@
globalThis.customElements = {
_elements: new Map(),
define(name, ctr) {

View file

@ -1,5 +1,3 @@
import './custom-elements.shim.js';
export const tagName = 'my-element';
class MyElement extends HTMLElement {

View file

@ -0,0 +1,11 @@
---
let show = true
---
<html>
<head>
<title>Custom element not imported but nested</title>
</head>
<body>
{show && <client-only-element></client-only-element>}
</body>
</html>