Skip to content
This repository was archived by the owner on Sep 20, 2024. It is now read-only.

Commit 282e448

Browse files
committed
feat(v-chakra): add support for Nuxt.js
1 parent 6640f20 commit 282e448

File tree

10 files changed

+191
-18
lines changed

10 files changed

+191
-18
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"color": "^3.1.2",
9797
"copy-to-clipboard": "^3.3.1",
9898
"core-js": "^3.6.4",
99+
"defu": "^2.0.4",
99100
"dotenv-defaults": "^1.1.1",
100101
"emotion": "^10.0.27",
101102
"eslint": "^5.16.0",

packages/chakra-ui-core/src/Chakra/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import VScrollLock from 'v-scroll-lock'
22
import { merge } from 'lodash-es'
33
import { parsePackIcons } from '../utils/icons'
44
import internalIcons from '../lib/internal-icons'
5-
import { createCharkaDirective } from '../directives'
5+
import { createClientDirective } from '../directives'
66
import defaultTheme from '../../../chakra-ui-theme/src'
77
import useToast from '../CToast'
88

@@ -63,7 +63,7 @@ const Chakra = {
6363
// Recursively merge extended theme variables
6464
const mergedTheme = merge(defaultTheme, options.extendTheme)
6565

66-
Vue.directive('chakra', createCharkaDirective(mergedTheme))
66+
Vue.directive('chakra', createClientDirective(mergedTheme))
6767

6868
// Bind theme and icons to prototype
6969
Vue.prototype.$chakra = {

packages/chakra-ui-core/src/directives/chakra.directive.js

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { css } from 'emotion'
22
import Css from '../Css'
33
import styleProps from '../config/props'
4-
import { camelize } from '../utils'
4+
import { camelize, kebabify } from '../utils'
55

66
/** Filter attrs and return object of chakra props */
77
function filterChakraProps (attrs) {
88
const pure = {}
99
for (const prop in attrs) {
1010
if (styleProps[camelize(prop)]) {
11-
pure[prop] = attrs[prop]
11+
pure[camelize(prop)] = attrs[prop]
1212
}
1313
}
1414
return pure
@@ -21,6 +21,15 @@ function purifyAttrs (el, props) {
2121
}
2222
}
2323

24+
/** Purify's Chakra Attributes from VNode object */
25+
function purifyVNodeAttrs (vnode, props) {
26+
if (props && vnode.data.attrs) {
27+
for (const attr in props) {
28+
delete vnode.data.attrs[kebabify(attr)]
29+
}
30+
}
31+
}
32+
2433
/** Creates className from styles object */
2534
function createClassName (styleObject, theme, hasBindingValue = false) {
2635
const pure = filterChakraProps(styleObject)
@@ -32,11 +41,46 @@ function createClassName (styleObject, theme, hasBindingValue = false) {
3241
return [className, pure]
3342
}
3443

35-
/** Creates Chakra Directive */
36-
export default function createCharkaDirective (theme) {
44+
/** Creates SSR `v-chakra` directive for Nuxt */
45+
export function createServerDirective (theme) {
46+
return (vnode, directive) => {
47+
const [className, pure] = createClassName(vnode.data.attrs, theme)
48+
if (vnode.data.class) {
49+
vnode.data.class += ` ${className}`
50+
} else {
51+
vnode.data.class = className
52+
}
53+
purifyVNodeAttrs(vnode, pure)
54+
55+
if (directive.value) {
56+
if (typeof directive.value === 'object') {
57+
const [className, pure] = createClassName(directive.value, theme, true)
58+
if (vnode.data.class) {
59+
vnode.data.class += ` ${className}`
60+
} else {
61+
vnode.data.class = className
62+
}
63+
purifyVNodeAttrs(vnode, pure)
64+
}
65+
66+
if (typeof directive.value === 'function') {
67+
const styles = directive.value(theme)
68+
const [className, pure] = createClassName(styles, theme, true)
69+
if (vnode.data.class) {
70+
vnode.data.class += ` ${className}`
71+
} else {
72+
vnode.data.class = className
73+
}
74+
purifyVNodeAttrs(vnode, pure)
75+
}
76+
}
77+
}
78+
};
79+
80+
/** Creates Client `v-chakra` Directive */
81+
export function createClientDirective (theme) {
3782
return {
3883
bind (el, binding, vnode) {
39-
console.log(vnode)
4084
const [className, pure] = createClassName(vnode.data.attrs, theme)
4185
el.classList.add(className)
4286
purifyAttrs(el, pure)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export { default as ClickOutsideDirective } from './clickoutside.directive'
2-
export { default as createCharkaDirective } from './chakra.directive'
2+
export * from './chakra.directive'

packages/nuxt-chakra/example/nuxt.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ module.exports = {
66
buildDir: resolve(__dirname, '.nuxt'),
77
srcDir: __dirname,
88
modules: [
9-
{ handler: require('../') }
9+
{ handler: require('../') },
10+
'@nuxtjs/emotion'
1011
],
1112
build: {
1213
transpile: [
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<template>
2+
<div>
3+
<div
4+
v-chakra
5+
p="3"
6+
bg="red.100"
7+
rounded="md"
8+
color="red.500"
9+
font-weight="bold"
10+
>
11+
Welcome to Chakra directive
12+
</div>
13+
<div>
14+
<div
15+
v-chakra="{
16+
p: 3,
17+
shadow: 'sm',
18+
h1: {
19+
bg: 'blue.100'
20+
},
21+
}"
22+
>
23+
<h1>Title</h1>
24+
<p>Text</p>
25+
</div>
26+
</div>
27+
<div
28+
v-chakra="theme => ({
29+
shadow: 'sm',
30+
bg: theme.colors.blue[800],
31+
color: theme.colors.yellow[300],
32+
p: {
33+
fontWeight: 'bold',
34+
p: 3
35+
}
36+
})"
37+
>
38+
<p>Computed styles</p>
39+
</div>
40+
<div>
41+
<button
42+
v-chakra="{
43+
':hover': { bg: 'green.400' },
44+
':focus': { shadow: 'outline' }
45+
}"
46+
font-weight="bold"
47+
px="4"
48+
py="3"
49+
color="white"
50+
rounded="md"
51+
bg="blue.400"
52+
outline="none"
53+
>
54+
Button
55+
</button>
56+
</div>
57+
</div>
58+
</template>
59+
60+
<script>
61+
export default {
62+
name: 'Directive'
63+
}
64+
</script>

packages/nuxt-chakra/example/pages/index.vue

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
<c-heading text-align="center" mb="4">
1212
⚡️ Hello chakra-ui/vue
1313
</c-heading>
14+
<c-link as="nuxt-link" to="/directive">
15+
Go to directive ->
16+
</c-link>
1417
<c-flex justify="center" direction="column" align="center">
1518
<c-box mb="3">
1619
<c-icon-button
@@ -98,7 +101,8 @@ import {
98101
CIconButton,
99102
CFlex,
100103
CHeading,
101-
CText
104+
CText,
105+
CLink
102106
} from '@chakra-ui/vue'
103107
104108
export default {
@@ -120,7 +124,8 @@ export default {
120124
CIconButton,
121125
CFlex,
122126
CHeading,
123-
CText
127+
CText,
128+
CLink
124129
},
125130
data () {
126131
return {

packages/nuxt-chakra/lib/module.js

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,56 @@
11
const { resolve } = require('path')
2+
const defu = require('defu')
3+
const { defaultTheme } = require('@chakra-ui/vue')
4+
const { parsePackIcons } = require('@chakra-ui/vue/src/utils/icons')
5+
const internalIcons = require('@chakra-ui/vue/src/lib/internal-icons')
6+
const { createServerDirective } = require('@chakra-ui/vue/src/directives/chakra.directive')
27

38
module.exports = function (moduleOptions) {
4-
/**
5-
* Merge defaults from Nuxt config
6-
*/
7-
const options = Object.assign({}, this.options.chakra, moduleOptions)
9+
const { nuxt } = this
810

11+
const options = {
12+
...this.options.chakra,
13+
...moduleOptions
14+
}
15+
16+
// Recursively merge extended theme variables
17+
const theme = defu(defaultTheme, options.extendTheme)
18+
19+
// Resolve icons
20+
let packIcons = {}
21+
if (options.icons && options.icons.iconPack) {
22+
packIcons = parsePackIcons(options.icons.iconPack, options.icons.iconSet)
23+
}
24+
25+
// Transpile lodash-es
26+
nuxt.options.build.transpile.push('lodash-es')
27+
28+
// Transpile @chakra-ui.
29+
nuxt.options.build.transpile.push('@chakra-ui')
30+
31+
if (nuxt.options.render.bundleRenderer.directives) {
32+
nuxt.options.render.bundleRenderer.directives.chakra = createServerDirective(theme)
33+
} else {
34+
nuxt.options.render.bundleRenderer.directives = {
35+
chakra: createServerDirective(theme)
36+
}
37+
}
38+
39+
// Icons
40+
const icons = {
41+
...internalIcons,
42+
...packIcons,
43+
...(options.icons && options.icons.extend)
44+
}
45+
46+
// Global bindings and plugins
947
this.addPlugin({
1048
src: resolve(__dirname, 'plugin.js'),
1149
fileName: 'chakra.js',
12-
options
50+
options: {
51+
theme,
52+
icons
53+
}
1354
})
1455
}
1556

packages/nuxt-chakra/lib/plugin.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
import Vue from 'vue'
2-
import Chakra from '@chakra-ui/vue'
32

4-
Vue.use(Chakra, <%= JSON.stringify(options, null, 2) %>)
3+
Vue.prototype.$chakra = {
4+
theme: <%= JSON.stringify(options.theme, null, 2) %>,
5+
icons: <%= JSON.stringify(options.icons, null, 2) %>
6+
}
7+
8+
if (process.client) {
9+
// Toast
10+
const useToast = require('@chakra-ui/vue/src/CToast').default
11+
Vue.prototype.$toast = useToast()
12+
13+
// VScrollLock
14+
const VScrollLock = require('v-scroll-lock').default
15+
Vue.use(VScrollLock)
16+
}

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9210,6 +9210,11 @@ defu@^1.0.0:
92109210
resolved "https://registry.yarnpkg.com/defu/-/defu-1.0.0.tgz#43acb09dfcf81866fa3b0fc047ece18e5c30df71"
92119211
integrity sha512-1Y1KRFxiiq+LYsZ3iP7xYSR8bHfmHFOUpDunZCN1ld1fGfDJWJIvkUBtjl3apnBwPuJtL/H7cwwlLYX8xPkraQ==
92129212

9213+
defu@^2.0.4:
9214+
version "2.0.4"
9215+
resolved "https://registry.yarnpkg.com/defu/-/defu-2.0.4.tgz#09659a6e87a8fd7178be13bd43e9357ebf6d1c46"
9216+
integrity sha512-G9pEH1UUMxShy6syWk01VQSRVs3CDWtlxtZu7A+NyqjxaCA4gSlWAKDBx6QiUEKezqS8+DUlXLI14Fp05Hmpwg==
9217+
92139218
del@^5.0.0:
92149219
version "5.1.0"
92159220
resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7"

0 commit comments

Comments
 (0)