Skip to content

Commit

Permalink
chore: deprecate the Marko.RepeatableAttrTags type and update docs/gu…
Browse files Browse the repository at this point in the history
…idance
  • Loading branch information
DylanPiercey committed Oct 17, 2024
1 parent 7dbde59 commit 7b02780
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 36 deletions.
7 changes: 7 additions & 0 deletions .changeset/yellow-eagles-fail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"marko": patch
---

Deprecated the Marko.RepeatableAttrTag type (which is now an alias of Marko.AttrTag). This type was overcomplicating things and leading people to incorrectly handle the single item case. Update docs to avoid recommending relying on the array case since this behavior changes in Marko 6 to always be a single (iterable) item.

Updates the `Marko.Input` type to handle changes to the `Marko.Body` type from `@marko/language-tools`.
31 changes: 6 additions & 25 deletions packages/marko/docs/body-content.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ _components/layout.marko_

> **ProTip:** The `renderBody` property can be omitted. You could use `<${input.heading}/>`, for example.
### Repeatable attribute tags
### Repeated body content

Attribute tags can be repeated. Rendering the same attribute tag name multiple times will cause the input value for that attribute to become an array instead of an single object.
When an attribute tag is repeated, the child component can consume all instances using the [iterable protocol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol).

This allows us to, for example, build a custom table component which allows its user to specify any number of columns, while still giving the user control over how each column is rendered.

Expand All @@ -131,15 +131,11 @@ _Marko Source:_
```

> _Note_
> Attribute tags are _repeatable_.
>
> - Zero: if you don't pass any `@column` tags, the `fancy-table` receives `undefined`.
> - One: if you pass a single `@column` tag, the `fancy-table` receives a single attribute tag object. (For convenience this object is [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol) meaning it can be directly passed to the `<for>` tag.)
> - Many: if you pass multiple `@column` tags, the `fancy-table` receives an array of attribute tags.
> For TypeScript the [`Marko.AttrTag` or `Marko.RepeatableAttrTag` helpers](./typescript.md#built-in-marko-types) should be used here.
> For TypeScript the [`Marko.AttrTag` helper](./typescript.md#built-in-marko-types) should be used here.
> _Protip_
> To `.map`, `.filter` or otherwise work with attribute tags as an array:
> Since attribute tags are iterable you could pass `input.column` to a `for of` loop, or `[...spread]` it into an array.
> To `.map`, `.filter` or otherwise work with attribute tags as an array you can use the following pattern:
>
> ```marko
> $ const columns = [...input.column || []];
Expand Down Expand Up @@ -212,7 +208,7 @@ _Marko Source:_
</fancy-table>
```

Now, each object in the `input.column` array will contain a `heading` property in addition to its `renderBody`. We can use another `<for>` and render the headings in `<th>` tags:
Now, each attribute tag in `input.column` will contain a `heading` property in addition to its `renderBody`. We can use another `<for>` and render the headings in `<th>` tags:

_components/fancy-table/index.marko:_

Expand Down Expand Up @@ -256,21 +252,6 @@ _HTML Output:_
</table>
```

> _Note_
> You may also specify that the attribute tag can be repeated in a [`marko-tag.json`](./marko-json.md#single-component-definition) file.
> This will cause an array to _always_ be passed if there are any items, rather than working up from `undefined`, single object and then an array.
>
> _components/fancy-table/marko-tag.json:_
>
> ```js
> {
> "@data": "array",
> "<column>": {
> "is-repeated": true
> }
> }
> ```
### Nested attribute tags

Continuing to build on our example, what if we want to add some custom content or even components into the column headings? In this case, we can extend our `<fancy-table>` to use nested attribute tags. We'll now have `<@heading>` and `<@cell>` tags nested under `<@column>`. This gives users of our tag full control over how to render both column headings and the cells within the column!
Expand Down
5 changes: 2 additions & 3 deletions packages/marko/docs/typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,9 @@ Marko exposes [type definitions](https://github.com/marko-js/marko/blob/main/pac
- Helpers to extract the input and return types native tags (when a string is passed) or a custom tag.
- **`Marko.BodyParameters<Body>`** and **`Marko.BodyReturnType<Body>`**
- Helpers to extract the parameters and return types from the specified `Marko.Body`
- **`Marko.AttrTag<T>`** and **`Marko.RepeatableAttrTag<T>`**
- **`Marko.AttrTag<T>`**
- Used to represent types for [attributes tags](./body-content.md#named-body-content)
- `Marko.AttrTag<T>`: A single attribute tag
- `Marko.RepeatableAttrTag<T>`: One or more attribute tags
- A single attribute tag, with a `[Symbol.iterator]` to consume any repeated tags.

### Typing `renderBody`

Expand Down
18 changes: 11 additions & 7 deletions packages/marko/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,14 @@ declare global {
removeAllListeners(eventName?: PropertyKey): this;
}

export type AttrTag<T> = T & Iterable<AttrTag<T>>;
export type RepeatableAttrTag<T> =
| AttrTag<T>
| [AttrTag<T>, AttrTag<T>, ...AttrTag<T>[]];
export type AttrTag<T> = T & {
[Symbol.iterator](): T;
};

/**
* @deprecated Prefer to use AttrTag
*/
export type RepeatableAttrTag<T> = AttrTag<T>;

export interface NativeTag<
Input extends Record<string, any>,
Expand Down Expand Up @@ -341,10 +345,10 @@ declare global {
length: infer Length;
}
? number extends Length
? { value?: Args }
? Args[0] | undefined
: 0 extends Length
? { value?: [] }
: { value: Args }
? undefined
: Args[0]
: never
: never;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @template T
* @typedef {{
* data: T[],
* column: Marko.RepeatableAttrTag<{ renderBody: Marko.Body<[T]> }>
* column: Marko.AttrTag<{ renderBody: Marko.Body<[T]> }>
* }} Input
*/
<table class="fancy">
Expand Down

0 comments on commit 7b02780

Please sign in to comment.