feat: event handler implicit components

This commit is contained in:
dpiercey 2024-04-18 09:52:32 -07:00 committed by Dylan Piercey
parent c8970e0719
commit 2d0a566a56
19 changed files with 103 additions and 11 deletions

View File

@ -0,0 +1,7 @@
---
"@marko/translator-default": minor
"@marko/compiler": minor
"marko": minor
---
Using event handlers now causes a template to become an implicit component or split component (depending on if a string event handler is used).

View File

@ -0,0 +1 @@
module.exports = {};

View File

@ -0,0 +1,4 @@
<button id=input.id onClick(() => {
component.emit("click");
})>Click me</button>

View File

@ -0,0 +1,2 @@
$ if (typeof window === "object") throw new Error("Should be server only");
<button id=input.id onClick("emit", "click")>Click me</button>

View File

@ -0,0 +1,9 @@
module.exports = {
onMount() {
window.testComponent = this;
this.clicks = 0;
},
trackClick() {
this.clicks++;
}
}

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
html lang="en"
head
meta charset="UTF-8"
title -- Marko Components Tests
body
div id="test"
div id="mocha"
div id="testsTarget"
app-button-split id="a" onClick("trackClick")
app-button-component id="b" onClick("trackClick")

View File

@ -0,0 +1,9 @@
var expect = require("chai").expect;
it("should have initialized both components", function () {
var component = window.testComponent;
expect(component.clicks).to.equal(0);
document.getElementById("a").click();
expect(component.clicks).to.equal(1);
document.getElementById("b").click();
});

View File

@ -49,8 +49,8 @@ export const analyze = {
exit(program) {
const { file } = program.hub;
const meta = file.metadata.marko;
const { styleFile, packageFile, componentBrowserFile } =
getComponentFiles(program);
const componentFiles = getComponentFiles(program);
const { styleFile, packageFile, componentBrowserFile } = componentFiles;
if (packageFile) {
meta.deps.unshift(`package: ${packageFile}`);
@ -62,8 +62,16 @@ export const analyze = {
if (meta.hasComponentBrowser) {
meta.component = componentBrowserFile;
} else if (meta.hasComponent || meta.hasStatefulTagParams) {
} else if (
meta.hasComponent ||
meta.hasStatefulTagParams ||
meta.hasFunctionEventHandlers
) {
meta.component = file.opts.filename;
} else if (meta.hasStringEventHandlers) {
meta.component = componentFiles.componentBrowserFile =
"marko/src/runtime/helpers/empty-component.js";
meta.hasComponentBrowser = true;
}
meta.component =
@ -114,6 +122,26 @@ export const analyze = {
}
}
if (!meta.hasFunctionEventHandlers || !meta.hasStringEventHandlers) {
for (const attr of tag.node.attributes) {
if (
t.isMarkoAttribute(attr) &&
attr.arguments &&
/^on[-A-Z]/.test(attr.name)
) {
if (
attr.arguments.length >= 1 &&
attr.arguments[0].type === "StringLiteral"
) {
meta.hasStringEventHandlers = true;
} else {
meta.hasFunctionEventHandlers = true;
}
break;
}
}
}
if (
meta.hasStatefulTagParams ||
isNativeTag(tag) ||
@ -138,6 +166,7 @@ export const analyze = {
meta.hasStatefulTagParams =
childMeta &&
(childMeta.hasStatefulTagParams ||
childMeta.hasFunctionEventHandlers ||
(childMeta.hasComponent && !childMeta.hasComponentBrowser));
},
ImportDeclaration: {

View File

@ -92,6 +92,7 @@ export default function (path, isNullable) {
if (isHTML) {
if (
(!meta.hasStatefulTagParams &&
!meta.hasFunctionEventHandlers &&
(meta.hasComponentBrowser || !meta.hasComponent)) ||
isPreserved(path)
) {

View File

@ -1,7 +1,7 @@
import path from "path";
import { escapeRegExp } from "./escape-regexp";
const COMPONENT_FILES_KEY = Symbol();
const COMPONENT_FILES_KEY = "___marko_component_files___";
export default function getComponentFiles({ hub: { file } }) {
const meta = file.metadata.marko;

View File

@ -0,0 +1,4 @@
import { register, init } from "marko/src/runtime/components/index.js";
import component_0 from "marko/src/runtime/helpers/empty-component.js";
register("packages/translator-default/test/fixtures/error-duplicate-event-handlers/template.marko", component_0);
init();

View File

@ -0,0 +1,3 @@
import { init } from "marko/src/runtime/components/index.js";
import "./template.marko";
init();

View File

@ -0,0 +1,4 @@
import { register, init } from "marko/src/runtime/components/index.js";
import component_0 from "marko/src/runtime/helpers/empty-component.js";
register("packages/translator-default/test/fixtures/error-event-handler-value/template.marko", component_0);
init();

View File

@ -27,6 +27,6 @@ _marko_template._ = (0, _renderer.default)(function (input, out, _componentDef,
(0, _renderTag.default)(_customTag2.default, {}, out, _componentDef, "5", [["camelcasedEvent", "handle", false]]);
}, {
t: _marko_componentType,
i: true,
s: true,
d: true
}, _marko_component);

View File

@ -22,6 +22,6 @@ _marko_template._ = _marko_renderer(function (input, out, _componentDef, _compon
_marko_tag(_customTag, {}, out, _componentDef, "5", [["camelcasedEvent", "handle", false]]);
}, {
t: _marko_componentType,
i: true,
s: true,
d: true
}, _marko_component);

View File

@ -20,5 +20,5 @@ _marko_template._ = _marko_renderer(function (input, out, _componentDef, _compon
_marko_tag(_customTag, {}, out, _componentDef, "5", [["camelcasedEvent", "handle", false]]);
}, {
t: _marko_componentType,
i: true
s: true
}, _marko_component);

View File

@ -0,0 +1,4 @@
import { register, init } from "marko/src/runtime/components/index.js";
import component_0 from "marko/src/runtime/helpers/empty-component.js";
register("packages/translator-default/test/fixtures/event-handlers/template.marko", component_0);
init();

View File

@ -6,7 +6,8 @@ import _customTag from "./components/custom-tag.marko";
import _marko_tag from "marko/src/runtime/helpers/render-tag.js";
import _marko_renderer from "marko/src/runtime/components/renderer.js";
import { r as _marko_registerComponent } from "marko/src/runtime/components/registry.js";
_marko_registerComponent(_marko_componentType, () => _marko_template);
import _marko_split_component from "marko/src/runtime/helpers/empty-component.js";
_marko_registerComponent(_marko_componentType, () => _marko_split_component);
const _marko_component = {};
_marko_template._ = _marko_renderer(function (input, out, _componentDef, _component, state, $global) {
out.e("div", null, "0", _component, 0, 0, {
@ -25,7 +26,7 @@ _marko_template._ = _marko_renderer(function (input, out, _componentDef, _compon
_marko_tag(_customTag, {}, out, _componentDef, "5", [["camelcasedEvent", "handle", false]]);
}, {
t: _marko_componentType,
i: true,
s: true,
d: true
}, _marko_component);
import _marko_defineComponent from "marko/src/runtime/components/defineComponent.js";

View File

@ -6,7 +6,8 @@ import _customTag from "./components/custom-tag.marko";
import _marko_tag from "marko/dist/runtime/helpers/render-tag.js";
import _marko_renderer from "marko/dist/runtime/components/renderer.js";
import { r as _marko_registerComponent } from "marko/dist/runtime/components/registry.js";
_marko_registerComponent(_marko_componentType, () => _marko_template);
import _marko_split_component from "marko/dist/runtime/helpers/empty-component.js";
_marko_registerComponent(_marko_componentType, () => _marko_split_component);
const _marko_component = {};
_marko_template._ = _marko_renderer(function (input, out, _componentDef, _component, state, $global) {
out.e("div", null, "0", _component, 0, 0, {
@ -25,7 +26,7 @@ _marko_template._ = _marko_renderer(function (input, out, _componentDef, _compon
_marko_tag(_customTag, {}, out, _componentDef, "5", [["camelcasedEvent", "handle", false]]);
}, {
t: _marko_componentType,
i: true
s: true
}, _marko_component);
import _marko_defineComponent from "marko/dist/runtime/components/defineComponent.js";
_marko_template.Component = _marko_defineComponent(_marko_component, _marko_template._);