mavo icon indicating copy to clipboard operation
mavo copied to clipboard

Allow for multiple properties per element

Open LeaVerou opened this issue 4 years ago • 5 comments

Allowing multiple properties per element is a common ask.

One idea for syntax is to replace property and mv-attribute with:

Instead of I'd have
<E property="foo"> (default) <E mv-name="foo"> OR <E mv-data="as foo">
<E property="foo" mv-attribute="none"> <E mv-name="foo" mv-data="content"> OR <E mv-data="content as foo">
<E property="foo" mv-attribute="bar"> <E mv-name="foo" mv-data="@bar"> OR <E mv-data="@bar as foo">
<E property="foo" mv-attribute="jsProp"> <E mv-name="foo" mv-data=".jsProp"> OR <E mv-data=".jsProp as foo">

The benefit of this syntax, besides being more explicit and not having any weird property attributes, is that it can generalize to holding multiple bits of data per element, a common need: <a mv-data="content as name, @href as url"></a>

Alternatively, we could introduce a microsyntax like expressions, that goes right in the place where data will go, akin to templating languages:

Instead of Maybe
<E property="foo"> (default) <E mv-value="{{foo}}">
<E property="foo" mv-attribute="none"></E> <E>{{foo}}</E>
<E property="foo" mv-attribute="bar"></E> <E bar="{{ bar }}">
<E property="foo" mv-attribute="jsProp"></E> <E .jsProp="{{ bar }}">

Note that both syntaxes also allow for JS properties to be observed (and there should be a way to optionally specify how to observe changes to them).

Both of these syntaxes have the same problem: how do you specify other metadata about each property (e.g. mv-default, mv-edit, mv-edit-* etc)? Currently we use attributes on the element. When there are multiple properties on it, how will that work?

  • The attributes could only specify metadata for the first property, which will be seen as a "main" one
  • The attributes can extend to comma-separated lists, akin to how CSS properties become list-ified.
  • Dmitry’s proposal: <a mv-data="content as name, @href as URL" mv-edit="#foo for URL"></a>
  • Something else?

LeaVerou avatar Oct 19 '20 17:10 LeaVerou

As for me, I would stick to the first variant: the code looks much more like native HTML, and if an author decides to integrate Mavo with other third-party libraries that already use similar templating language (e.g., 11ty), they will not conflict with each other. However, we can always provide something similar to mv-expressions for such cases.

The attributes can extend to comma-separated lists, akin to how CSS properties become list-ified

I vote for letting an author control each property of a multi-properties-elements. One thought. Suppose I have an element with 3 properties. I wonder, what if I want to set metadata for the last property? Should I explicitly specify two commas before the value for the third property? What if we have something similar to the destructuring assignment in JS? I am not sure about the easy to follow syntax, though. Or we can use the idea implemented in CSS Grid for areas that need to be skipped in the grid-template-areas: use some special character for properties that must be skipped?

DmitrySharabin avatar Oct 24 '20 14:10 DmitrySharabin

Suddenly I came up with this: <a mv-data="content as name, @href as URL" mv-edit="#foo for URL"></a>.

I suppose, in that case, we won't have to invent special symbols for “gaps” and a new syntax for destructuring, and we won't be limited by specifying metadata only for a “main” property.

DmitrySharabin avatar Oct 25 '20 08:10 DmitrySharabin

I like that idea, though it can get repetitive. Perhaps a combination would be best.

LeaVerou avatar Oct 26 '20 18:10 LeaVerou

A while ago, we had a discussion with @karger where I explored the idea of whether it would be possible to somehow merge expressions and property definitions. Many Mavo novices confuse the two, and things like <a href="[foo]" property="foo"> are also quite common. I also don't like the indirectness of mv-attribute="foo" instead of being able to directly put something in the attribute to say "here, my data goes here!".

Here's what @karger said, including it here for posterity:

I was thinking more about your interesting ideas for mavo data. Lots of complex facets but here are thoughts on a couple.

We discussed the tension that in the location of a property you sometimes want to name the property but other times you want to specify its value. So let's allow both. Consider using colon as a "property definition" syntax. Any place that allows a mavo expression will also allow x:foo where x is a symbol and foo is an expression. The expression evaluates to the value of foo but it also defines x as a property of the current object with initial value foo. So I can write

<div property="a">  <a href="[x: 3+12]"> ...

which defines x as a property of object a with initial value 15

Note this is also consistent with your current group(x: 17, y: 10) syntax if you just think of group as specifying the creation of a new object/scope . It's also consistent with json.

I can also just use the syntax [x:] to define a property with no (default) value.

Turning to the idea of being able to edit a property in multiple places. We already have the ability to refer to an entity in multiple places. E.g. if I write [a.b.c] it refers to the c entity in the a.b scope. c might be an object or a primitive (but we've talked about unifying primitives with objects). So the only issue is enriching the syntax to specify whether (i) what is here is a reference to the original object or a copy (or a deep copy) and (ii) whether it is editable. Of course if the object (and its parts) is not editable then it doesn't matter whether it is the same object or a copy. But if it editable I need to know whether I'm editing the original or a copy. We already have mv-mode to specify edit vs. read. If we want the default to be a copy then I can use e.g. xref(x) to indicate a cross-reference to x. Alternatively if I want to default to a reference I can use copy(x) to indicate a copy.

One issue with that syntax is that it's unclear whether the expression after the colon declares a default value or a computed property. I suppose the actual difference between the two is editability: computed properties are not editable, whereas properties with a computed default value are. So perhaps we should just decouple editability.

A few more issues:

  • we currently we have two bits of data that make sense to go in the data attribute: property name, default/computed value. In the future however we may have more e.g. #260
  • A pattern like this would force us to have different syntax for groups, when we are hoping to merge them (#590)

LeaVerou avatar Dec 24 '20 14:12 LeaVerou

It also needs to be unambiguous. Can I use it where there are other colons, like <div property="a"> <a href="http://domain/[x: 3+12]">

joyously avatar Dec 24 '20 16:12 joyously