Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ export default ({ mode }: { mode: string }) => defineConfigWithTheme({
}, {
text: 'Other helpers',
link: '/guide/other-helpers.html'
}, {
text: 'With meta',
link: '/guide/with-meta.html'
}
]
}, {
Expand Down
1 change: 1 addition & 0 deletions packages/docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ The [`options`](#iterationoptions) object can be used to decide which node types
### See also

* [Guide - Other helpers](/guide/other-helpers.html)
* [Guide - With meta](/guide/with-meta.html)

## eachChild()

Expand Down
16 changes: 16 additions & 0 deletions packages/docs/src/guide/iterators.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,19 @@ For the specific case of counting children, the dedicated [`countChildren()`](./
While these examples need to display the count, a more common scenario involves only needing to know whether the count is 0. The [`isEmpty()`](./other-helpers#checking-for-an-empty-slot) helper can be used in that case.

It is worth noting that the count here is just a count of the VNodes. It is not necessarily an accurate count of the number of `<li>` elements. If any of the children had been a component it would have added 1 to the count, even though a component wouldn't necessarily render exactly one `<li>` element.

The iteration index and total node count aren't passed to the callback by default. It's relatively easy to implement that yourself:

```js
const children = slots.default?.() ?? []
const count = countChildren(children)
let index = -1

eachChild(children, (vnode) => {
index++

// ...
})
```

But if you'd like the index and length to be passed to the callback you can use the [`with-meta`](./with-meta) iterators instead.
2 changes: 2 additions & 0 deletions packages/docs/src/guide/other-helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ function ChildComponent(_, { slots }) {

See it on the SFC Playground: [Composition API](https://play.vuejs.org/#eNp9VGtv0zAU/StXAamtaJPykJDCxoBp4v0Qm8QHgiBLnNara0e20xVV/e8c22nWdBvaPjS+55577vU93kSv6zpeNSxKoyNTaF5bMsw29ctM8mWttKUNaZYXlq8YbanSakkD4Add/BM39ge38wtlc9EC4qR3Gl8Z4DNZKGksccuWho472uHPTBLKWLa2KQ2+s3IwJjNX1ylZ3aDquBd/qxmTHaLKhbkFeSMgsM+RyV+jGwku8loIiBiO6PglbVx6pTQNbySSqoLUUQiT/4pdKvIcqzsFMf6PkjA7TA0fgNUitwxfREeXjbVK0qtC8GJxnEVt7SzyYaJzR5jjwIGTgA6ZAjOcXGOIE+um2OI7elpNIBmMXi2XQW3H6wmA4VUL8dL3whjYJvTkxkZb9LEL3BK937ofOXje8ZL1BPvMRPCd0KQ/CEQO++lBonEUVmqyzGusjJJYSj961PcBNJfuLiOLXpkF11awBOs4WUlVskljufCgLJpbW5s0SRpZL2ZxoZbJffikhK7Dw5iZ5eRSq2vDdFyyFfRk0e7CofRwvyG188v8bqNsqFCNtKdzLkrN5JjOP77/9vv06+fPZ18uzruc+2R6B7G1pypZlTfCUtVIWAgX5UlPFQpJJu3w9xjVjFDW0LZd37DYRVsc1+jDaM0zncQwwskJ/fy1h3VqAeypHu4YDuR7cxE8bRstaT4clHwFC3pr0833H88TKFN6uPE/tn9G3r+usCt54vCNAHxXbEQpySZ4xPkYl4A7MPavYCYujJt+u7GPCIVCx5dKl0yn9Lhek1GCl/RgOp2+cKFlrmdcYg1rhKf1uj1cYztLO0/pyXR3WOdlyeWsg6FyBiVthbxYzDQ0lyk9qJ67P590R+WiKPYqBzqakpPjKWFVT9mrF8Lo1BpcScVnB67AVtdcMP21dkvQdwdeFHX9wZ+5t6odMHLmrFjccX5l1sE43zTDzq/g8C5mIZrZED47/4LXYi+4VGUjgP5P8DvDFLDESgbYG0wMsvdwXu177xN0f2HO1pZJs2uqe2w9PovgDLfr97V+I/dp/Kzz7PYf9mdPuQ==) | [Options API](https://play.vuejs.org/#eNp9Vftv0zAQ/ldOAamdaJPykJDCYMA08X6ITeIHgiCLncara0f2pSuq+r9zfiRry4Y2qfXdd9/d+e5zN8mrtk1XHU/y5NhWRrT4olBi2WqD8FFY/C6wudBYSqiNXsIozfas6ZUdFQqgUHztYxivy04ibJy10kSkuEKbBwPsczrTdhLiAViJ5fioBxqOnVH9CUAgXxLNj/4MsAHka8xh9I2z0QRso69zQNPxyHmAemM4VwOuLqW9A/hadvyAr0f9DF/82cW6zyXHRrObDl3cKyn7TgossNYGxpVWFn0boGvARtjU9zR03HeZOgZ47lP3nlhBSFwo+j/OhnHRgcJaWSKnE8DxZYeoFbyspKgWz4skllQk3g1w7hKUZHDgLKBDpKTxTK9pPlN0A4r4gR5WU+qFGH0bQoWpDLyegDCijhDfyo6bbnkTenR3DdvhYm8pevcq/LSI561gfK9gH5lJ0Rea7V8EeQ772YMkkyTs+nRZtrTLWpEOwtiig5obJlskL+1CGJQ8I8VMV0ozPu1QSA8qkgaxtXmWdapdzFNa/uwufMaorkNjyu1yemn0teUmZXxF9RRJP3Cq9FB4VGoU6gYa2EaBEikpcnBUulN42gjJDFcTOP/w7uuv0y+fPp19vjgfYu4qk4j+EXbdqQoFDcqTnvYKH/+aUDYrNVrYxpUOG1/F5DRG76bWPNNJShI5OYEfXlQR66ol4F7V457hoPyjoL/4UDTjERMr0m18IYbzb88TKHO4v/Fftr+PovRDyhOH7yTB+2RHkIPqgkZ+UioaAs3A4h/JbVpZd/txYx8AJQodX2rDuMnhYbsGq6VgcG82mz3zz0Rp5kLRGrbknrXraFzTdjJscng0641tyZhQ8wFGmQuqJGYoq8XcUM0sh3v1U/fng27JXFXVTuZABzNw5XhKkqqn3MsX3NQpWhpJLeYHqnBPupDcfGndEuyrg14Uff3e29zbFS+YYhpeLW6xX9l1EM5Xw2nnV6TwwYdUNMfgPjv/TK/FjnOpWScJ/R/nN063QEusVYC9phujsndwvtp3XifU/YU9WyNXtm+qf3zjz1NCynC7flfrN+U+Tp8Mmt3+Bfk4a4M=)

If you need the child count inside the callback of an iterator then you might prefer to use [`with-meta`](./with-meta) instead, which will pass the count to the iteration callback.

If you need more fine-grained control over the counting you can use [`eachChild()` or `reduceChildren()`](./iterators) instead.

## Extracting a single child
Expand Down
97 changes: 97 additions & 0 deletions packages/docs/src/guide/with-meta.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
# Updated automatically in production builds: see the VitePress config.
packageVersions:
vue: 3.5.34
'@skirtle/vue-vnode-utils': 0.3.0
---
# With meta <Badge text="0.3+" />

There are alternative versions of the iterator functions, with added support for accessing extra metadata for the current node.

Currently, this metadata just includes the iteration index and length.

To use this metadata you'll need to import the functions from `@skirtle/vue-vnode-utils/with-meta` rather than `@skirtle/vue-vnode-utils`.

## Accessing meta from callbacks

The meta is passed in an object as the final argument of the callback for each iterator.

The `length` property is a number and should be equivalent to calling [`countChildren()`](./other-helpers#counting-children). It will use the same iteration options as the iterator, so if you're skipping nodes then those nodes won't be included in the `length`. For most iterators, the `length` is the number of times the callback will be called during the iteration.

The `index` is zero-based, counting up to `length - 1`.

The `length` is calculated lazily, so if it isn't accessed the nodes won't be counted.

[`betweenChildren()`](./inserting-new-nodes) behaves a little differently. The `index` will still start at zero, but it will only count up to `length - 2`. The `length` will still reflect the number of nodes, like it would for the other iterators, but that won't match the number of calls to the callback.

## Example

```js
import { h } from 'vue'
import { addProps } from '@skirtle/vue-vnode-utils/with-meta'

export default function AddStripes(_, { slots }) {
const children = addProps(slots.default(), (vnode, { index, length }) => {
return {
class: [
index % 2 ? 'odd' : 'even',
{
first: index === 0,
last: index === length - 1
}
]
}
})

return h('div', children)
}
```

See it on the SFC Playground: [Composition API](https://play.vuejs.org/#eNqFVFtr2zAU/isHw4gDid3u8uI1u9KHDbaVdW/zGG504qiVJSPJaUrIf98n2bm0tJ0JROf26Vy+o03ysW2zVcdJkZy5uZWtJ8e+a9+VWjatsZ42ZHkxoblp2s6zoC0trGlohKDR3umjEJce0ewGa5YfVNm1g2ep50Y7D6BOe5oF1PTNeKeVnhsH7e6aNB3T7B19q/wya6p1ejIZzlKnESFbVarjCZ2ejMdAOcv77JE3BIC1qvIMiehMakDSatoYwWpWJjG+TMjftQxRd80VW8jAhngSTtUap1Mce4RDLVGGRsgVEBfGBgCS+IUCBv/wbTakabsd3HP491BHfYHiLN+nmkySvpnTpmrRMqMxk02IKQcD4AuKmqD74G6k9YpzDGK60qht2nmpXH4r/XLasK+Ce5ksvW9dkeedbm/qDP3Nn4wU0vlD+ENzxq6ZXllz69hmglfIsUxCNihyi+zvDRy57/mzfJwzG6qEuLCmdXv7/2uKROJ1BBC8qDrladHpuZdGH7Ew/TsBvlPGA3zcN22g31IqYVmDa7vr0+iHkiJcOp5QGu8OEFILXk9Isa496oikHEZgsSdW7yTgq8q5gn7vZOqD6QW9pPc0MkKMqKARr1iPJgenfXz4FtI6XwyBs9mMTo48iXDDPeuQ1pROD14D5Yj+9Icob7Ei4X/IeZmOQMgRtnroBszwwxC9Q5sWsn5AwLCWUrH90YZG3ydipZS5/Rp13mIld/r5kuc3vX5RKXcwXLt1T80Ly+DSistkb/OVrRnLGcznl995jfPeiAXuFLyfMf5kZxQ4Y3Tv9qnTAnkf+cV0v0QKSl3/cudrz9rtqgoVxIZF/zIBET8/U/sh3VfZ66NdcP5OYQ/mLixC1laiD8FB4NICr1a7fht7XuosDn3HUWVsgTEJWAnvkK2lnnrTPggJRLgXUVtmvTeDa731qprf1BbvnShIyXrp7ziUH8EfTybQ84nYKzy4j0cm238hNxSj) | [Options API](https://play.vuejs.org/#eNqFVNtu2zAM/RXCwBAH8CXd5SVLunVDHzZgW7HubR4Gx2JsNbJkSHLqIsi/j/ItTtF2gYGIInl4O9TBu6qqaF+jt/RWJtO8speJ5GWltIUrxm4tXaGBrVYlzKL4dBXdmVkiE4lNa8twm9bCwiGRAJkiAInSmmV3ARMsJx8D5wrAUpv688FGo621HCQHU0u7hHedfJw6ugi1RTbic4ulOUGNYN9SW0Rl2viLoD9z6duCm6hFD+BiMZ9PAySSvlU89oIEgq5EapEkgBWXFBn2YakYinXitTiJB/ahQhJlXW5Qk0yBSFy4U9rQ6YKOHcKpF61MN4zvCXGrtAMATp8rp7d3v8MBJBzbDMk8JvsOajIQuljFk1S9wOvmGJZpRdNSkmbctifpFRRg7F/ifTQ7rq3AmNgQ7iVVF9aWCxPfc1uEJdrUmSdeYW1llnFcy2qXUxfL+FlPxo09uT9WR2jKcKPVvUEdMdxTjok3zICyP+Ma5d6z8gAFHHtCEiKRcFSkjN1oVZlR//+anuLwtpaZ5UpOSOv/DQjfCGUJvGdZpqSxkBVcMI0S1mN4v7Wjklo4fx6A38Z2EFwybAIQKHNLdcxhffks/UVqaIF+DzKR3DnDK3gNH2CmGJvBEma4RzmjtRiMRn/323JtaIU6x/V6DYuJJQBFONP2aYVwcbLqSQfwZ7omtDPuv8+58GdEyVkwdoPUZEdDtIbatOX5IwK6/eUC9Y/KNfqciKkQ6v5re2d1jX3C5FNgtuvut6kwJ8WdaTpq3mgkLu0x8UadTXWOtJ5OfX37HRs6j0pa4VqQ9QvKn2iUIM4o2Zl9qiWjvCd2bbpfWgpymf8y141FaYaqXAXDw+WsiYifX6j9lO6b6O1kF4x9ELQHmXGLEFUp61zowCjokl6xqnnf9jyRUTv0gaNC6SWNiZEW6CXSOZehVdUjF0eEM49cI8pRTVzrtJs02+WaXjx6eQXPC/uArvwW/OlkHD2f8d2IGp/29I7/AH7AK5M=)

## Accessing the `with-meta` iterators

Metadata isn't included in the default iterators, to avoid the added overhead. You'll need to use alternative versions of the iterators to get the metadata.

### With a bundler

If you're using a bundler then you just need to change `@skirtle/vue-vnode-utils` to `@skirtle/vue-vnode-utils/with-meta` in your imports to get access to the metadata:

```js
import { addProps } from '@skirtle/vue-vnode-utils/with-meta'
```

All exports from `@skirtle/vue-vnode-utils` are re-exported by `@skirtle/vue-vnode-utils/with-meta`, even those that don't include meta. You can also mix `@skirtle/vue-vnode-utils` and `@skirtle/vue-vnode-utils/with-meta` and functions will be tree-shaken across the two packages.

### CDN - global build

To use meta with a global build, add `with-meta` to the path:

```html-vue
<script src="https://unpkg.com/@skirtle/vue-vnode-utils@{{ $frontmatter.packageVersions['@skirtle/vue-vnode-utils'] }}/dist/with-meta/vue-vnode-utils.global.dev.js"></script>
```

The global variable is called `VueVNodeUtils`, the same as with the normal build. You wouldn't load both in the same project.

### CDN - ES module build

Similar to the global build, you need to add `with-meta` to the path:

```html-vue
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue@{{ $frontmatter.packageVersions.vue }}/dist/vue.esm-browser.js",
"@skirtle/vue-vnode-utils/with-meta": "https://unpkg.com/@skirtle/vue-vnode-utils@{{ $frontmatter.packageVersions['@skirtle/vue-vnode-utils'] }}/dist/with-meta/vue-vnode-utils.esm-browser.dev.js"
}
}
</script>
<script type="module">
import { addProps } from '@skirtle/vue-vnode-utils/with-meta'
// ...
</script>
```

The `with-meta` module includes a copy of everything it needs, you don't need to include `@skirtle/vue-vnode-utils` in the import map.

The package name is usually arbitrary, though using `@skirtle/vue-vnode-utils/with-meta` is recommended unless you have a good reason to use an alternative.
5 changes: 5 additions & 0 deletions packages/vue-vnode-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
"import": "./dist/vue-vnode-utils.esm-bundler.js",
"require": "./dist/vue-vnode-utils.cjs"
},
"./with-meta": {
"types": "./dist/with-meta/vue-vnode-utils.d.ts",
"import": "./dist/with-meta/vue-vnode-utils.esm-bundler.js",
"require": "./dist/with-meta/vue-vnode-utils.cjs"
},
"./dist/*": "./dist/*",
"./package.json": "./package.json"
},
Expand Down
Loading
Loading