Last active
September 21, 2018 00:27
-
-
Save uriannrima/1f0ab3bcb59943638dde014d49c3bcf3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="Sandbox"> | |
<div> | |
<span>Default:</span> | |
<themed-button>Main</themed-button> | |
<themed-button primary>Primary</themed-button> | |
<span>Themed:</span> | |
<theme-provider :theme="coloredTheme"> | |
<themed-button @click="$emit('main-button')">Main</themed-button> | |
<themed-button primary | |
@click="$emit('primary-button')">Primary</themed-button> | |
</theme-provider> | |
<input v-model="coloredTheme.main"> | |
<input v-model="coloredTheme.primary"> | |
</div> | |
</div> | |
</template> | |
<script lang="ts"> | |
import Vue from 'vue'; | |
import { ThemeProvider } from './ThemeProvider'; | |
import ThemedButton from './TButton.vue'; | |
export default Vue.extend({ | |
components: { ThemeProvider, ThemedButton }, | |
data() { | |
return { | |
coloredTheme: { | |
main: 'purple', | |
primary: 'gray' | |
} | |
}; | |
} | |
}); | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Vue, { PropOptions } from 'vue' | |
/** | |
* Generate a theme provider. | |
* @param themeProps Property validation for the Theme. Must follow the "default" Vue property declaration. | |
* For example, the default value is { type:Object, required: true }. | |
* But an VueType validation can also be used for a better props validation. | |
*/ | |
export const createThemeProvider = (themeProps: PropOptions = { type: Object, required: true }) => { | |
return Vue.extend({ | |
/** | |
* Receive theme as props. | |
*/ | |
props: { | |
theme: themeProps | |
}, | |
/** | |
* Inject 'Theme' to lower components. | |
*/ | |
provide() { | |
return { | |
theme: this.theme | |
}; | |
}, | |
/** | |
* Render slots. | |
*/ | |
render() { | |
return <div>{this.$slots.default}</div>; | |
} | |
}); | |
} | |
/** | |
* Generate a default theme provider. | |
*/ | |
export const ThemeProvider = createThemeProvider(); | |
/** | |
* Theme Injector Base. | |
*/ | |
const ThemeInjectorBase = { | |
/** | |
* Inject the theme | |
*/ | |
inject: { | |
theme: { | |
default: undefined | |
} | |
} | |
}; | |
/** | |
* High-Order-Component that injects theme as a property of the component passed as paramenter. | |
* @param Component Component that will be wrapped. | |
*/ | |
export const withTheme = (Component: any) => { | |
return Vue.extend({ | |
name: `Themed${Component.name}`, | |
props: Component.props, | |
...ThemeInjectorBase, | |
render(h) { | |
var componentProperties: any = { | |
attrs: this.$attrs, | |
on: this.$listeners, | |
props: this.$props | |
}; | |
const { theme } = this as any; | |
if (theme) { | |
componentProperties = { | |
...componentProperties, | |
props: { ...this.$props, theme } | |
} | |
} | |
console.log(componentProperties); | |
return h(Component, componentProperties, this.$slots.default); | |
} | |
}) | |
}; | |
/** | |
* Slot-scope version of the theme injector. | |
* Theme will be passed as "theme" inside of the slot-scope. | |
*/ | |
export const ThemeInjector = Vue.extend({ | |
...ThemeInjectorBase, | |
render() { | |
const { theme } = this as any; | |
return <div>{this.$scopedSlots.default({ theme })}</div>; | |
} | |
}); | |
export default ThemeProvider; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment