Handle custom elements in nested JSX (#792)
* Handle custom elements in nested JSX * Adds a changeset
This commit is contained in:
parent
b7e579a9cb
commit
b85e68a713
8 changed files with 35 additions and 8 deletions
6
.changeset/two-squids-film.md
Normal file
6
.changeset/two-squids-film.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
'@astrojs/parser': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fixes case where custom elements are not handled within JSX expressions
|
|
@ -29,7 +29,7 @@ export class Parser {
|
||||||
js: Script[] = [];
|
js: Script[] = [];
|
||||||
meta_tags = {};
|
meta_tags = {};
|
||||||
last_auto_closed_tag?: LastAutoClosedTag;
|
last_auto_closed_tag?: LastAutoClosedTag;
|
||||||
feature_flags: 0;
|
feature_flags: number = 0;
|
||||||
|
|
||||||
constructor(template: string, options: ParserOptions) {
|
constructor(template: string, options: ParserOptions) {
|
||||||
if (typeof template !== 'string') {
|
if (typeof template !== 'string') {
|
||||||
|
|
|
@ -9,6 +9,7 @@ interface ParseState {
|
||||||
curlyCount: number;
|
curlyCount: number;
|
||||||
bracketCount: number;
|
bracketCount: number;
|
||||||
root: Expression;
|
root: Expression;
|
||||||
|
parser: Parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
function peek_char(state: ParseState) {
|
function peek_char(state: ParseState) {
|
||||||
|
@ -159,12 +160,13 @@ function consume_tag(state: ParseState) {
|
||||||
const source = state.source.substring(start, state.index);
|
const source = state.source.substring(start, state.index);
|
||||||
|
|
||||||
const ast = parseAstro(source);
|
const ast = parseAstro(source);
|
||||||
|
state.parser.feature_flags |= ast.meta.features;
|
||||||
const fragment = ast.html;
|
const fragment = ast.html;
|
||||||
|
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
function consume_expression(source: string, start: number): Expression {
|
function consume_expression(parser: Parser, source: string, start: number): Expression {
|
||||||
const expr: Expression = {
|
const expr: Expression = {
|
||||||
type: 'Expression',
|
type: 'Expression',
|
||||||
start,
|
start,
|
||||||
|
@ -182,6 +184,7 @@ function consume_expression(source: string, start: number): Expression {
|
||||||
curlyCount: 1,
|
curlyCount: 1,
|
||||||
bracketCount: 0,
|
bracketCount: 0,
|
||||||
root: expr,
|
root: expr,
|
||||||
|
parser,
|
||||||
};
|
};
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -234,15 +237,15 @@ function consume_expression(source: string, start: number): Expression {
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parse_expression_at = (source: string, index: number): Expression => {
|
export const parse_expression_at = (parser: Parser, source: string, index: number): Expression => {
|
||||||
const expression = consume_expression(source, index);
|
const expression = consume_expression(parser, source, index);
|
||||||
|
|
||||||
return expression;
|
return expression;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function read_expression(parser: Parser) {
|
export default function read_expression(parser: Parser) {
|
||||||
try {
|
try {
|
||||||
const expression = parse_expression_at(parser.template, parser.index);
|
const expression = parse_expression_at(parser, parser.template, parser.index);
|
||||||
parser.index = expression.end;
|
parser.index = expression.end;
|
||||||
return expression;
|
return expression;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -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');
|
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();
|
CustomElements.run();
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import './shim.js';
|
||||||
|
|
||||||
function getConstructor(Component) {
|
function getConstructor(Component) {
|
||||||
if(typeof Component === 'string') {
|
if(typeof Component === 'string') {
|
||||||
const tagName = Component;
|
const tagName = Component;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
globalThis.customElements = {
|
globalThis.customElements = {
|
||||||
_elements: new Map(),
|
_elements: new Map(),
|
||||||
define(name, ctr) {
|
define(name, ctr) {
|
|
@ -1,5 +1,3 @@
|
||||||
import './custom-elements.shim.js';
|
|
||||||
|
|
||||||
export const tagName = 'my-element';
|
export const tagName = 'my-element';
|
||||||
|
|
||||||
class MyElement extends HTMLElement {
|
class MyElement extends HTMLElement {
|
||||||
|
|
11
packages/astro/test/fixtures/custom-elements/src/pages/nested.astro
vendored
Normal file
11
packages/astro/test/fixtures/custom-elements/src/pages/nested.astro
vendored
Normal 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>
|
Loading…
Add table
Reference in a new issue