Skip to content

Commit

Permalink
feat: useHead accepts more types of argument (vueuse#6)
Browse files Browse the repository at this point in the history
Co-authored-by: Kevin Hazy <[email protected]>
  • Loading branch information
antfu and egoist authored Jan 19, 2021
1 parent 769775a commit 76cdda7
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 34 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions

name: Node.js CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [14.x]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: yarn
- run: npm run test --if-present
42 changes: 27 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ import { useHead } from '@vueuse/head'
export default defineComponent({
setup() {
useHead(() => ({
useHead({
title: `Website title`,
meta: [
{
name: `description`,
content: `Website description`,
},
],
}))
})
},
})
</script>
Expand Down Expand Up @@ -85,18 +85,18 @@ const finalHTML = `

Create the head manager instance.

### `useHead(() => HeadObject)`
### `useHead(head: HeadObject | Ref<HeadObject> | (() => HeadObject))`

```ts
interface HeadObject {
title?: string
base?: HeadAttrs
meta?: HeadAttrs[]
link?: HeadAttrs[]
style?: HeadAttrs[]
script?: HeadAttrs[]
htmlAttrs?: HeadAttrs
bodyAttrs?: HeadAttrs
title?: MaybeRef<string>
meta?: MaybeRef<HeadAttrs[]>
link?: MaybeRef<HeadAttrs[]>
base?: MaybeRef<HeadAttrs>
style?: MaybeRef<HeadAttrs[]>
script?: MaybeRef<HeadAttrs[]>
htmlAttrs?: MaybeRef<HeadAttrs>
bodyAttrs?: MaybeRef<HeadAttrs>
}

interface HeadAttrs {
Expand All @@ -107,7 +107,7 @@ interface HeadAttrs {
For `meta` tags, we use `name` and `property` to prevent duplicated tags, you can instead use the `key` attribute if the same `name` or `property` is allowed:

```ts
useHead(() => ({
useHead({
meta: [
{
property: 'og:locale:alternate',
Expand All @@ -120,19 +120,31 @@ useHead(() => ({
key: 'en',
},
],
}))
})
```

To set the `textContent` of an element, use the `children` attribute:

```ts
useHead(() => ({
useHead({
style: [
{
children: `body {color: red}`,
},
],
}))
})
```

`useHead` also takes reactive object or ref as the argument, for example:

```ts
const head = reactive({ title: 'Website Title' })
useHead(head)
```

```ts
const title = ref('Website Title')
useHead({ title })
```

### `renderHeadToString(head: Head)`
Expand Down
52 changes: 33 additions & 19 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
import { App, inject, onBeforeUnmount, watchEffect } from 'vue'
import {
App,
computed,
inject,
onBeforeUnmount,
ref,
Ref,
UnwrapRef,
watchEffect,
} from 'vue'
import { PROVIDE_KEY, HEAD_COUNT_KEY, HEAD_ATTRS_KEY } from './constants'
import { createElement } from './create-element'
import { stringifyAttrs } from './stringify-attrs'

type MaybeRef<T> = T | Ref<T>

export type HeadAttrs = { [k: string]: any }

export type HeadObject = {
title?: string
meta?: HeadAttrs[]
link?: HeadAttrs[]
base?: HeadAttrs
style?: HeadAttrs[]
script?: HeadAttrs[]
htmlAttrs?: HeadAttrs
bodyAttrs?: HeadAttrs
title?: MaybeRef<string>
meta?: MaybeRef<HeadAttrs[]>
link?: MaybeRef<HeadAttrs[]>
base?: MaybeRef<HeadAttrs>
style?: MaybeRef<HeadAttrs[]>
script?: MaybeRef<HeadAttrs[]>
htmlAttrs?: MaybeRef<HeadAttrs>
bodyAttrs?: MaybeRef<HeadAttrs>
}

export type HeadObjectPlain = UnwrapRef<HeadObject>

export type HeadTag = {
tag: string
props: {
Expand Down Expand Up @@ -69,10 +82,10 @@ const injectHead = () => {
return head
}

const headObjToTags = (obj: HeadObject) => {
const headObjToTags = (obj: HeadObjectPlain) => {
const tags: HeadTag[] = []

for (const key of Object.keys(obj) as Array<keyof HeadObject>) {
for (const key of Object.keys(obj) as Array<keyof HeadObjectPlain>) {
if (key === 'title') {
tags.push({ tag: key, props: { children: obj[key] } })
} else if (key === 'base') {
Expand Down Expand Up @@ -230,7 +243,12 @@ export const createHead = () => {

const IS_BROWSER = typeof window !== 'undefined'

export const useHead = (fn: () => HeadObject) => {
export const useHead = (
obj: HeadObject | Ref<HeadObject> | (() => HeadObject),
) => {
const headObj = (typeof obj === 'function'
? computed(obj)
: ref(obj)) as Ref<HeadObjectPlain>
const head = injectHead()

if (IS_BROWSER) {
Expand All @@ -240,8 +258,7 @@ export const useHead = (fn: () => HeadObject) => {
if (tags) {
head.removeHeadTags(tags)
}
const headObj = fn()
tags = headObjToTags(headObj)
tags = headObjToTags(headObj.value)
head.addHeadTags(tags)
head.updateDOM()
})
Expand All @@ -252,12 +269,9 @@ export const useHead = (fn: () => HeadObject) => {
head.updateDOM()
}
})

return
} else {
head.addHeadTags(headObjToTags(headObj.value))
}

const headObj = fn()
head.addHeadTags(headObjToTags(headObj))
}

const tagToString = (tag: HeadTag) => {
Expand Down

0 comments on commit 76cdda7

Please sign in to comment.