rimmel icon indicating copy to clipboard operation
rimmel copied to clipboard

Custom Events

Open dariomannu opened this issue 3 months ago • 5 comments

Custom Events in templates: a potential new feature being considered.

const onenter = /* impl TBD */
const stream = new Subject<string>();

target.innerHTML = rml`
  <button ${onenter}="${stream}">
`;

This might facilitate, abstract away or offer an alternative to some of the work currently performed by Event Adapters:

const OnEnterValue = inputPipe(
  filter(e=>e.key == 'Enter'),
  map(e=>e.target.value),
);

const stream = new Subject<string>();

target.innerHTML = rml`
  <button oninput="${ OnEnterValue( stream )}">
`;

More analysis required.

dariomannu avatar Sep 24 '25 16:09 dariomannu

Hi, I’d like to contribute to this issue. Could you please assign it to me?

AadityaBansal01 avatar Oct 01 '25 21:10 AadityaBansal01

Hi @AadityaBansal01, welcome to the Stream-Oriented Club!

We first need to understand if this is a good idea at all.

The change would require at least one extra regex test in the parser plus a few lines of implementation. Maybe not a big deal, but would it be worth it? Can we think of use cases? Do we think a form of Custom Events like above is a good alternative to Event Adapters in semantic and/or ergonomics?

dariomannu avatar Oct 02 '25 06:10 dariomannu

@dariomannu It's probably not a good idea to add this new "Custom Event" feature.

The current "Event Adapter" pattern (using inputPipe) is a better way to go. While the proposed <button ${onenter}="${stream}"> syntax looks a little cleaner, it's a bit "magical." cause it hides what's actually happening and makes the template harder to understand.

The current way, oninput="${OnEnterValue(stream)}", is very clear: you're just transforming the standard oninput event.

Plus, implementing this new syntax would be surprisingly tricky. It would make the HTML parser more complex than it's worth.

So, the existing Event Adapters are already the best solution. They handle all the same use cases, are more powerful, and are easier for everyone to understand.

Pls tell me ur thoughts. I’d be happy to take this issue.

yashraj4 avatar Nov 05 '25 06:11 yashraj4

That's a very good perspective @yashraj4. I probably agree with you with regards to the inputPipe being a better choice to implement event adapters.

With regards to clarity, I don't know for sure. OnEnterValue( stream ) This is an expression that may not immediately make it clear that it returns an Observer which will map its input to feed the Observer or event handler that's supplied as its parameter 😓, unless someone already understands this pattern and knows how to interpret it and work with it.

What I'd really like to know is if there is any other use case besides the event adapter. Maybe there is and we don't know yet, or maybe there isn't at all. We have this space to think about it in the meantime, raise ideas and discuss them.

dariomannu avatar Nov 05 '25 12:11 dariomannu

You're right to question the clarity of OnEnterValue(stream).

This is the main ergonomic hurdle of the inputPipe pattern: the data flow feels backward. It looks like you're passing stream into a function, but in reality, OnEnterValue is a function (created by inputPipe) that returns a new Observer. That new observer takes the event, pipes it through the operators, and then feeds the stream.

It's a powerful pattern, but I agree it's not immediately intuitive and has to be learned.

Talking about the use cases, the difficulty is that the syntax (<tag ${partialName}="${value}">) implies two separate expressions (${...}) need to work together to form one logical binding.

The parser, as it's written in parser.ts, isn't built for that. It processes one expression at a time and decides its context (is it an attribute? a mixin? content?) based on the static string that comes just before it.

For example: Event Source: It sees onclick=" and knows the next ${...} is the listener. Attribute Sink: It sees class="foo and knows the next ${...} is part of the class attribute's value. Mixin Sink: It sees <div and knows the next ${...} is a mixin object.

The new syntax would break this. The parser would see <button ${onenter} and likely treat it as a mixin sink. It would then have no way to connect that to the subsequent ="...${stream}" part.

Because of this parsing limitation, it feels like this syntax can't be used for anything else. It would require a fundamental, and very complex, rewrite of the parser to look ahead and pair expressions.

So, this might be a case where the event adapter was the only conceivable use case, and as we've discussed, the inputPipe pattern already solves that (even if its own ergonomics are debatable).

And yeah, can this issue be assigned to me?

yashraj4 avatar Nov 06 '25 06:11 yashraj4