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

Commit 5ae7190

Browse files
committed
feat(icon): add internal and external library icon support
1 parent ef822d9 commit 5ae7190

File tree

11 files changed

+124
-13
lines changed

11 files changed

+124
-13
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<template>
2+
<div>
3+
<c-icon color="red.400" size="10" name="activity" />
4+
</div>
5+
</template>
6+
7+
<script lang="ts">
8+
import { CIcon } from '@chakra-ui/c-icon/src'
9+
import { defineComponent } from 'vue'
10+
11+
export default defineComponent({
12+
components: { CIcon },
13+
})
14+
</script>

packages/c-icon/src/icon.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { h, defineComponent, PropType, computed } from 'vue'
1+
import { h, defineComponent, PropType, computed, inject } from 'vue'
22
import {
33
chakra,
44
DOMElements,
@@ -41,18 +41,24 @@ export const CIcon = defineComponent({
4141
},
4242
},
4343
setup(props, { slots, attrs }) {
44+
const icons = inject<Record<string, any>>('$chakraIcons')
45+
const icon = computed(() => icons?.[props?.name as string] || fallbackIcon)
4446
const vnodeProps = computed<StyleAndHTMLAttibutes>(() => ({
4547
w: props.size,
4648
h: props.size,
4749
display: 'inline-block',
4850
lineHeight: '1em',
4951
flexShrink: 0,
5052
color: 'currentColor',
51-
innerHTML:
52-
internalIcons[props?.name as string]?.path || fallbackIcon.path,
53+
innerHTML: icon.value.path,
5354
viewBox: fallbackIcon.viewBox,
5455
}))
5556

56-
return () => h(chakra(props.as), { ...vnodeProps.value, ...attrs }, slots)
57+
return () =>
58+
h(
59+
chakra(props.as),
60+
{ ...vnodeProps.value, ...(icon.value.attrs || {}), ...attrs },
61+
slots
62+
)
5763
},
5864
})

packages/c-icon/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
export * from './icon'
2+
export { default as internalIcons } from './icon.internals'
3+
export * from './icon.internals'

packages/core/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"watch:types": "tsc --emitDeclarationOnly --declaration --declarationDir dist/types --watch"
2424
},
2525
"dependencies": {
26-
"@chakra-ui/vue-theme": "^1.0.0",
27-
"@chakra-ui/vue-utils": "^1.0.0"
26+
"@chakra-ui/vue-theme": "*",
27+
"@chakra-ui/vue-utils": "*",
28+
"@chakra-ui/c-icon": "*"
2829
}
2930
}

packages/core/src/index.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Plugin } from 'vue'
22
import defaultTheme, { ColorMode } from '@chakra-ui/vue-theme'
3+
import { internalIcons } from '@chakra-ui/c-icon'
34
import { extendTheme, ThemeOverride } from './extend-theme'
5+
import { MergedIcons, parseIcons } from './parse-icons'
46

57
interface ExtendIconsPath {
68
path: string
@@ -11,19 +13,36 @@ interface IconsOptions {
1113
library?: {}
1214
extend?: Record<string, ExtendIconsPath>
1315
}
14-
interface ChakraUIVuePluginOptions {
16+
export interface ChakraUIVuePluginOptions {
1517
extendTheme?: ThemeOverride
1618
icons?: IconsOptions
1719
defaultColorMode?: ColorMode
1820
}
1921

2022
const ChakraUIVuePlugin: Plugin = {
2123
install(app, options: ChakraUIVuePluginOptions = {}) {
24+
// Get theme value
2225
const theme = options.extendTheme || defaultTheme
26+
let libraryIcons = options.icons?.library || {}
27+
28+
// Initialize colormode
2329
const colorMode = theme.config?.initialColorMode || 'light'
30+
31+
// Bind theme to application global properties and provide to application
2432
app.config.globalProperties.$chakraTheme = theme
2533
app.provide('$chakraTheme', theme as ThemeOverride)
34+
35+
// Provide initial colormode
2636
app.provide('$chakraColorMode', colorMode as ColorMode)
37+
38+
libraryIcons = parseIcons(libraryIcons)
39+
40+
// Merge internal icons and library icons
41+
const mergedIcons: MergedIcons = {
42+
...internalIcons,
43+
...libraryIcons,
44+
}
45+
app.provide('$chakraIcons', mergedIcons)
2746
},
2847
}
2948

packages/core/src/parse-icons.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { mergeWith } from '@chakra-ui/vue-utils'
2+
3+
interface InternalIcon {
4+
[key: string]:
5+
| {
6+
path: string
7+
viewBox?: string
8+
attrs?: string
9+
}
10+
| any
11+
}
12+
13+
export type MergedIcons = {
14+
[key in keyof InternalIcon]: InternalIcon
15+
}
16+
17+
/**
18+
* Currently the parseIcon function only supports icon parsing
19+
* from the following libraries:
20+
* - Feather icons: feathericons.com (feather-icons-paths)
21+
* - FontAwesome: fontawesome.com (@fortawesome/free-solid-icons)
22+
*
23+
* The reason for this is that the above packages follow a given signature/convention.
24+
* Any ideas around how to improve this are welcome. Please send in a PR or open an issue
25+
*/
26+
27+
const parseIcon = (iconObject: any): InternalIcon => {
28+
const { icon } = iconObject
29+
if (icon) {
30+
const [w, h, content, svg, path, , attrs] = icon
31+
return {
32+
[`${iconObject.iconName}`]: {
33+
path: iconObject.prefix.startsWith('fa')
34+
? `<path d="${path}" fill="currentColor" />`
35+
: iconObject.prefix.startsWith('fe')
36+
? content
37+
: svg,
38+
viewBox: `0 0 ${w} ${h}`,
39+
attrs,
40+
},
41+
}
42+
} else {
43+
return {}
44+
}
45+
}
46+
47+
export const parseIcons = (iconSet = {}): MergedIcons => {
48+
const result = Object.values(iconSet)
49+
.map((value) => parseIcon(value))
50+
.reduce((target, source) => mergeWith(target, source), {})
51+
52+
return result
53+
}

playground/src/.generated/imports.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import Component_6 from '@chakra-ui/c-alert/examples/with-title.vue'
77
import Component_7 from '@chakra-ui/c-button/examples/base-button.vue'
88
import Component_8 from '@chakra-ui/c-icon/examples/base-icon.vue'
99
import Component_9 from '@chakra-ui/c-icon/examples/with-color.vue'
10-
import Component_10 from '@chakra-ui/c-icon/examples/with-size.vue'
11-
import Component_11 from "../components/Home.vue";
10+
import Component_10 from '@chakra-ui/c-icon/examples/with-icon-library.vue'
11+
import Component_11 from '@chakra-ui/c-icon/examples/with-size.vue'
12+
import Component_12 from "../components/Home.vue";
1213

1314
export default {
14-
"../components/Home.vue": Component_11,
15+
"../components/Home.vue": Component_12,
1516
"@chakra-ui/c-alert/examples/base-alert.vue": Component_2,
1617
"@chakra-ui/c-alert/examples/fix-hover.vue": Component_3,
1718
"@chakra-ui/c-alert/examples/with-accent.vue": Component_4,
@@ -20,5 +21,6 @@ export default {
2021
"@chakra-ui/c-button/examples/base-button.vue": Component_7,
2122
"@chakra-ui/c-icon/examples/base-icon.vue": Component_8,
2223
"@chakra-ui/c-icon/examples/with-color.vue": Component_9,
23-
"@chakra-ui/c-icon/examples/with-size.vue": Component_10
24+
"@chakra-ui/c-icon/examples/with-icon-library.vue": Component_10,
25+
"@chakra-ui/c-icon/examples/with-size.vue": Component_11
2426
}

playground/src/.generated/routes.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@
6060
"path": "/c-icon/with-color",
6161
"component": "@chakra-ui/c-icon/examples/with-color.vue"
6262
},
63+
{
64+
"name": "With icon library",
65+
"path": "/c-icon/with-icon-library",
66+
"component": "@chakra-ui/c-icon/examples/with-icon-library.vue"
67+
},
6368
{
6469
"name": "With size",
6570
"path": "/c-icon/with-size",

playground/src/components/Sidebar.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export default Stories
4646

4747
<style>
4848
.router-link-active {
49-
color: #4299e1;
49+
color: #4299e1 !important;
5050
font-weight: bold;
5151
text-decoration: underline;
5252
}

playground/src/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ declare module '*.vue' {
33
const component: Component
44
export default component
55
}
6+
7+
declare module 'feather-icons-paths';

0 commit comments

Comments
 (0)