Skip to content

Commit

Permalink
Added custom icon support for adding new and overriding existing icon…
Browse files Browse the repository at this point in the history
…s. (#366)

* Added custom icon support for adding new and overriding existing icons.

* Updated tests.

* Custom icons will set default icons on the first property retrieval.

* Reset library properties on build.

* Added doc for custom icon and small improvement
  • Loading branch information
alan-cole authored and tim-yao committed May 28, 2019
1 parent 074cb13 commit 2fba620
Show file tree
Hide file tree
Showing 9 changed files with 498 additions and 30 deletions.
4 changes: 4 additions & 0 deletions .storybook/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import Vue from 'vue'
import RplGlobal from './../packages/Atoms/Global'
import RplMarkupExamplePlugins from './../packages/Organisms/Markup/examplePlugins'

// Add custom icons to library.
import { addCustomIcons } from '../packages/Atoms/Icon'
addCustomIcons(require.context('../static/custom_icons/', true, /\.svg$/))

// Install Ripple Global plugin
Vue.use(RplGlobal, { rplMarkup: {plugins: RplMarkupExamplePlugins, options: { decodeEntities: false }}})

Expand Down
6 changes: 4 additions & 2 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ module.exports = {
test: /\.(jpe?g|png|woff|woff2|eot|ttf|svg)(\?[a-z0-9=.]+)?$/,
loader: 'url-loader',
exclude: [
resolve('packages/Atoms/Icon/')
resolve('packages/Atoms/Icon/'),
resolve('static/custom_icons/')
],
},
{
test: /\.svg$/,
include: [
resolve('packages/Atoms/Icon/')
resolve('packages/Atoms/Icon/'),
resolve('static/custom_icons/')
],
use: [
'svg-sprite-loader',
Expand Down
22 changes: 2 additions & 20 deletions packages/Atoms/Icon/Icon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,7 @@
</template>

<script>
// Require all SVG assets and calculate width based on view box.
let iconProps = {}
// In Jest there is no webpack require.context support, aslo we don't transform files.
// Let's skip this part in tests.
if (process.env.NODE_ENV !== 'test') {
const _require = require.context('./assets/img/', true, /\.svg$/)
_require.keys().forEach(key => {
let icon = _require(key)
if (icon.default) {
let viewBoxSplit = icon.default.viewBox.split(' ')
iconProps[icon.default.id] = {
width: parseFloat(viewBoxSplit[2]),
height: parseFloat(viewBoxSplit[3])
}
}
})
}
import { getIconProps } from './icon-library'
export default {
props: {
Expand All @@ -35,7 +17,7 @@ export default {
data: function () {
return {
iconPrefix: 'rpl_icon_',
iconProperties: iconProps,
iconProperties: getIconProps(),
sizes: {
's': 0.5,
'm': 1,
Expand Down
65 changes: 65 additions & 0 deletions packages/Atoms/Icon/icon-library.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
let iconProps = {}
let hasRunOnce = false

/**
* Add icon properties from a require.context() response to `iconProps`.
*
* Can be used as:
* addIconsToLibrary(require.context('./custom_assets/', true, /\.svg$/))
*
* @param {Function} webpackContext The function returned from a require.context() call.
*/
function addIconsToLibrary (webpackContext) {
webpackContext.keys().forEach(key => {
const icon = webpackContext(key)
if (icon.default) {
const viewBoxSplit = icon.default.viewBox.split(' ')
if (!iconProps[icon.default.id]) {
iconProps[icon.default.id] = {
width: parseFloat(viewBoxSplit[2]),
height: parseFloat(viewBoxSplit[3])
}
}
}
})
}

function getIconProps () {
// Add default icons on first call.
// For correct overrides; this must run after custom icons have been added.
if (!hasRunOnce) {
hasRunOnce = true
// In Jest there is no webpack require.context support, also we don't transform files.
// Let's skip this part in tests.
if (process.env.NODE_ENV !== 'test') {
addIconsToLibrary(require.context('./assets/img/', true, /\.svg$/))
}
}
return iconProps
}

/**
* Reset properties.
* Use before calling addIconsToLibrary() to allow property reset on dev mode hot reload.
*/
function resetLibrary () {
iconProps = {}
hasRunOnce = false
}

/**
* Add custom icon properties from a require.context() response.
* Custom icons should be added before the ripple-icon component is used.
*
* Can be used as:
* addCustomIcons(require.context('./custom_assets/', true, /\.svg$/))
*
* @param {Function} webpackContext The function returned from a require.context() call.
*/
function addCustomIcons (webpackContext) {
resetLibrary()
addIconsToLibrary(webpackContext)
}

export { addCustomIcons }
export { getIconProps }
2 changes: 2 additions & 0 deletions packages/Atoms/Icon/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import RplIcon from './Icon.vue'
import RplTextIcon from './TextIcon.vue'
import { addCustomIcons } from './icon-library'

export {RplIcon}
export {RplTextIcon}
export { addCustomIcons }
export default RplIcon
45 changes: 37 additions & 8 deletions packages/Atoms/Icon/stories.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { storiesOf } from '@storybook/vue'
import { withReadme } from 'storybook-readme'
import VueInfoAddon from 'storybook-addon-vue-info'
import VueInfoAddon, { withInfo } from 'storybook-addon-vue-info'

import {
withKnobs
Expand All @@ -14,13 +14,16 @@ import { demoData } from '../../../src/storybook-components/_data/demoData'
storiesOf('Atoms/Icon', module)
.addDecorator(VueInfoAddon)
.addDecorator(withKnobs)
.add('Icon Library', withReadme(readme, () => ({
components: { SIcons },
template: '<s-icons :icons="icons" :color="color" :size="size" />',
data () {
return demoData.iconLibrary()
}
})))
.add(
'Icon Library',
withReadme(readme, () => ({
components: { SIcons },
template: '<s-icons :icons="icons" :color="color" :size="size" />',
data () {
return demoData.iconLibrary()
}
}))
)
.add('Icon', withReadme(readme, () => ({
components: { RplIcon },
template: '<rpl-icon :symbol="icon" :color="color" :size="size" />',
Expand All @@ -41,3 +44,29 @@ storiesOf('Atoms/Icon', module)
return demoData.textIcon()
}
})))

storiesOf('Atoms/Icon', module)
.add(
'Icon Custom',
withInfo(`
### Add custom icons
To use your own svg icon, you need to name your own custom icon in the same format as Ripple does.
A example: \`rpl_icon_arrow\`. Always use \`rpl_icon_\` prefix.
You can put your custom icons in any directory in your project, e.g. "/assets/ripple-icons/".
To add icons, below code has to be added before you start your app by calling \`new Vue()\`:
~~~javascript
import { addCustomIcons } from '@dpc-sdp/ripple-icon'
addCustomIcons(require.context('./assets/ripple-icons/', true, /\\.svg$/))
~~~
Then you should able to use your own icon as others.
To use your own svg icon to replace the default icon, you must use the exact same file name as default.
You can find the default icons in [Icon/assets/img](https://github.com/dpc-sdp/ripple/tree/master/packages/Atoms/Icon/assets/img).
`)(() => ({
components: { RplIcon },
template: '<rpl-icon symbol="custom_icon" color="primary" size="m" />'
})))
4 changes: 4 additions & 0 deletions src/storybook-components/scss/story.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
padding-top: 1px;
padding-bottom: 1px;
}

.summary {
color: #000 !important;
}
}

.demo-content {
Expand Down
5 changes: 5 additions & 0 deletions static/custom_icons/rpl_icon_custom_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 2fba620

Please sign in to comment.