feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
357
skills/vueuse-functions/references/createReusableTemplate.md
Normal file
357
skills/vueuse-functions/references/createReusableTemplate.md
Normal file
@@ -0,0 +1,357 @@
|
||||
---
|
||||
category: Component
|
||||
outline: deep
|
||||
---
|
||||
|
||||
# createReusableTemplate
|
||||
|
||||
Define and reuse template inside the component scope.
|
||||
|
||||
## Motivation
|
||||
|
||||
It's common to have the need to reuse some part of the template. For example:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<dialog v-if="showInDialog">
|
||||
<!-- something complex -->
|
||||
</dialog>
|
||||
<div v-else>
|
||||
<!-- something complex -->
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
We'd like to reuse our code as much as possible. So normally we might need to extract those duplicated parts into a component. However, in a separated component you lose the ability to access the local bindings. Defining props and emits for them can be tedious sometimes.
|
||||
|
||||
So this function is made to provide a way for defining and reusing templates inside the component scope.
|
||||
|
||||
## Usage
|
||||
|
||||
In the previous example, we could refactor it to:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { createReusableTemplate } from '@vueuse/core'
|
||||
|
||||
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefineTemplate>
|
||||
<!-- something complex -->
|
||||
</DefineTemplate>
|
||||
|
||||
<dialog v-if="showInDialog">
|
||||
<ReuseTemplate />
|
||||
</dialog>
|
||||
<div v-else>
|
||||
<ReuseTemplate />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
- `<DefineTemplate>` will register the template and renders nothing.
|
||||
- `<ReuseTemplate>` will render the template provided by `<DefineTemplate>`.
|
||||
- `<DefineTemplate>` must be used before `<ReuseTemplate>`.
|
||||
|
||||
> **Note**: It's recommended to extract as separate components whenever possible. Abusing this function might lead to bad practices for your codebase.
|
||||
|
||||
### Options API
|
||||
|
||||
When using with [Options API](https://vuejs.org/guide/introduction.html#api-styles), you will need to define `createReusableTemplate` outside of the component setup and pass to the `components` option in order to use them in the template.
|
||||
|
||||
```vue
|
||||
<script>
|
||||
import { createReusableTemplate } from '@vueuse/core'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
DefineTemplate,
|
||||
ReuseTemplate,
|
||||
},
|
||||
setup() {
|
||||
// ...
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefineTemplate v-slot="{ data, msg, anything }">
|
||||
<div>{{ data }} passed from usage</div>
|
||||
</DefineTemplate>
|
||||
|
||||
<ReuseTemplate :data="data" msg="The first usage" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### Passing Data
|
||||
|
||||
You can also pass data to the template using slots:
|
||||
|
||||
- Use `v-slot="..."` to access the data on `<DefineTemplate>`
|
||||
- Directly bind the data on `<ReuseTemplate>` to pass them to the template
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { createReusableTemplate } from '@vueuse/core'
|
||||
|
||||
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefineTemplate v-slot="{ data, msg, anything }">
|
||||
<div>{{ data }} passed from usage</div>
|
||||
</DefineTemplate>
|
||||
|
||||
<ReuseTemplate :data="data" msg="The first usage" />
|
||||
<ReuseTemplate :data="anotherData" msg="The second usage" />
|
||||
<ReuseTemplate v-bind="{ data: something, msg: 'The third' }" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### TypeScript Support
|
||||
|
||||
`createReusableTemplate` accepts a generic type to provide type support for the data passed to the template:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { createReusableTemplate } from '@vueuse/core'
|
||||
|
||||
// Comes with pair of `DefineTemplate` and `ReuseTemplate`
|
||||
const [DefineFoo, ReuseFoo] = createReusableTemplate<{ msg: string }>()
|
||||
|
||||
// You can create multiple reusable templates
|
||||
const [DefineBar, ReuseBar] = createReusableTemplate<{ items: string[] }>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefineFoo v-slot="{ msg }">
|
||||
<!-- `msg` is typed as `string` -->
|
||||
<div>Hello {{ msg.toUpperCase() }}</div>
|
||||
</DefineFoo>
|
||||
|
||||
<ReuseFoo msg="World" />
|
||||
|
||||
<!-- @ts-expect-error Type Error! -->
|
||||
<ReuseFoo :msg="1" />
|
||||
</template>
|
||||
```
|
||||
|
||||
Optionally, if you are not a fan of array destructuring, the following usages are also legal:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { createReusableTemplate } from '@vueuse/core'
|
||||
|
||||
const { define: DefineFoo, reuse: ReuseFoo } = createReusableTemplate<{
|
||||
msg: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefineFoo v-slot="{ msg }">
|
||||
<div>Hello {{ msg.toUpperCase() }}</div>
|
||||
</DefineFoo>
|
||||
|
||||
<ReuseFoo msg="World" />
|
||||
</template>
|
||||
```
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { createReusableTemplate } from '@vueuse/core'
|
||||
|
||||
const TemplateFoo = createReusableTemplate<{ msg: string }>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TemplateFoo.define v-slot="{ msg }">
|
||||
<div>Hello {{ msg.toUpperCase() }}</div>
|
||||
</TemplateFoo.define>
|
||||
|
||||
<TemplateFoo.reuse msg="World" />
|
||||
</template>
|
||||
```
|
||||
|
||||
::: warning
|
||||
Passing boolean props without `v-bind` is not supported. See the [Caveats](#boolean-props) section for more details.
|
||||
:::
|
||||
|
||||
### Props and Attributes
|
||||
|
||||
By default, all props and attributes passed to `<ReuseTemplate>` will be passed to the template. If you don't want certain props to be passed to the DOM, you need to define the runtime props:
|
||||
|
||||
```ts
|
||||
import { createReusableTemplate } from '@vueuse/core'
|
||||
|
||||
const [DefineTemplate, ReuseTemplate] = createReusableTemplate({
|
||||
props: {
|
||||
msg: String,
|
||||
enable: Boolean,
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
If you don't want to pass any props to the template, you can pass the `inheritAttrs` option:
|
||||
|
||||
```ts
|
||||
import { createReusableTemplate } from '@vueuse/core'
|
||||
|
||||
const [DefineTemplate, ReuseTemplate] = createReusableTemplate({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
```
|
||||
|
||||
### Passing Slots
|
||||
|
||||
It's also possible to pass slots back from `<ReuseTemplate>`. You can access the slots on `<DefineTemplate>` from `$slots`:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { createReusableTemplate } from '@vueuse/core'
|
||||
|
||||
const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefineTemplate v-slot="{ $slots, otherProp }">
|
||||
<div some-layout>
|
||||
<!-- To render the slot -->
|
||||
<component :is="$slots.default" />
|
||||
</div>
|
||||
</DefineTemplate>
|
||||
|
||||
<ReuseTemplate>
|
||||
<div>Some content</div>
|
||||
</ReuseTemplate>
|
||||
<ReuseTemplate>
|
||||
<div>Another content</div>
|
||||
</ReuseTemplate>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Caveats
|
||||
|
||||
### Boolean props
|
||||
|
||||
As opposed to Vue's behavior, props defined as `boolean` that were passed without `v-bind` or absent will be resolved into an empty string or `undefined` respectively:
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { createReusableTemplate } from '@vueuse/core'
|
||||
|
||||
const [DefineTemplate, ReuseTemplate] = createReusableTemplate<{
|
||||
value?: boolean
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DefineTemplate v-slot="{ value }">
|
||||
{{ typeof value }}: {{ value }}
|
||||
</DefineTemplate>
|
||||
|
||||
<ReuseTemplate :value="true" />
|
||||
<!-- boolean: true -->
|
||||
|
||||
<ReuseTemplate :value="false" />
|
||||
<!-- boolean: false -->
|
||||
|
||||
<ReuseTemplate value />
|
||||
<!-- string: -->
|
||||
|
||||
<ReuseTemplate />
|
||||
<!-- undefined: -->
|
||||
</template>
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
This function is migrated from [vue-reuse-template](https://github.com/antfu/vue-reuse-template).
|
||||
|
||||
Existing Vue discussions/issues about reusing template:
|
||||
|
||||
- [Discussion on Reusing Templates](https://github.com/vuejs/core/discussions/6898)
|
||||
|
||||
Alternative Approaches:
|
||||
|
||||
- [Vue Macros - `namedTemplate`](https://vue-macros.sxzz.moe/features/named-template.html)
|
||||
- [`unplugin-vue-reuse-template`](https://github.com/liulinboyi/unplugin-vue-reuse-template)
|
||||
|
||||
## Type Declarations
|
||||
|
||||
```ts
|
||||
type ObjectLiteralWithPotentialObjectLiterals = Record<
|
||||
string,
|
||||
Record<string, any> | undefined
|
||||
>
|
||||
type GenerateSlotsFromSlotMap<
|
||||
T extends ObjectLiteralWithPotentialObjectLiterals,
|
||||
> = {
|
||||
[K in keyof T]: Slot<T[K]>
|
||||
}
|
||||
export type DefineTemplateComponent<
|
||||
Bindings extends Record<string, any>,
|
||||
MapSlotNameToSlotProps extends ObjectLiteralWithPotentialObjectLiterals,
|
||||
> = DefineComponent & {
|
||||
new (): {
|
||||
$slots: {
|
||||
default: (
|
||||
_: Bindings & {
|
||||
$slots: GenerateSlotsFromSlotMap<MapSlotNameToSlotProps>
|
||||
},
|
||||
) => any
|
||||
}
|
||||
}
|
||||
}
|
||||
export type ReuseTemplateComponent<
|
||||
Bindings extends Record<string, any>,
|
||||
MapSlotNameToSlotProps extends ObjectLiteralWithPotentialObjectLiterals,
|
||||
> = DefineComponent<Bindings> & {
|
||||
new (): {
|
||||
$slots: GenerateSlotsFromSlotMap<MapSlotNameToSlotProps>
|
||||
}
|
||||
}
|
||||
export type ReusableTemplatePair<
|
||||
Bindings extends Record<string, any>,
|
||||
MapSlotNameToSlotProps extends ObjectLiteralWithPotentialObjectLiterals,
|
||||
> = [
|
||||
DefineTemplateComponent<Bindings, MapSlotNameToSlotProps>,
|
||||
ReuseTemplateComponent<Bindings, MapSlotNameToSlotProps>,
|
||||
] & {
|
||||
define: DefineTemplateComponent<Bindings, MapSlotNameToSlotProps>
|
||||
reuse: ReuseTemplateComponent<Bindings, MapSlotNameToSlotProps>
|
||||
}
|
||||
export interface CreateReusableTemplateOptions<
|
||||
Props extends Record<string, any>,
|
||||
> {
|
||||
/**
|
||||
* Inherit attrs from reuse component.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
inheritAttrs?: boolean
|
||||
/**
|
||||
* Props definition for reuse component.
|
||||
*/
|
||||
props?: ComponentObjectPropsOptions<Props>
|
||||
}
|
||||
/**
|
||||
* This function creates `define` and `reuse` components in pair,
|
||||
* It also allow to pass a generic to bind with type.
|
||||
*
|
||||
* @see https://vueuse.org/createReusableTemplate
|
||||
*
|
||||
* @__NO_SIDE_EFFECTS__
|
||||
*/
|
||||
export declare function createReusableTemplate<
|
||||
Bindings extends Record<string, any>,
|
||||
MapSlotNameToSlotProps extends
|
||||
ObjectLiteralWithPotentialObjectLiterals = Record<"default", undefined>,
|
||||
>(
|
||||
options?: CreateReusableTemplateOptions<Bindings>,
|
||||
): ReusableTemplatePair<Bindings, MapSlotNameToSlotProps>
|
||||
```
|
||||
Reference in New Issue
Block a user