├── .gitignore ├── .npmrc ├── .travis.yml ├── LICENSE ├── README.md ├── css └── Octicon.css ├── demo └── src │ ├── Demo.js │ ├── demo.css │ └── index.js ├── nwb.config.js ├── octicons.gif ├── package.json ├── src ├── Octicon.js └── index.js └── tests ├── .eslintrc └── Octicon-test.js /.gitignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /demo/dist 3 | /es 4 | /lib 5 | /node_modules 6 | /umd 7 | npm-debug.log* 8 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | node_js: 5 | - 4 6 | - 6 7 | - 8 8 | 9 | cache: 10 | directories: 11 | - node_modules 12 | 13 | before_install: 14 | - npm install codecov.io coveralls 15 | 16 | after_success: 17 | - cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js 18 | - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js 19 | 20 | branches: 21 | only: 22 | - master 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Jonny Buchanan 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | 20 | (No LICENSE file provided in webmodules/jsonp to include for attribution) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## react-octicon 2 | 3 | [![Travis][build-badge]][build] 4 | [![npm package][npm-badge]][npm] 5 | [![Coveralls][coveralls-badge]][coveralls] 6 | 7 | A [React](https://facebook.github.io/react/) component which renders an icon using the [GitHub Octicons](https://octicons.github.com/) icon font. 8 | 9 | ![All Octicons](octicons.gif) 10 | 11 | > **Note:** Github Octicons has switched from providing an icon font to being a library for generating SVG markup for string templating engines, so this component uses the last version which provided an icon font, version 4. 12 | > 13 | > As such, the available icons and their appearance may not match with what's on the Github Octicons documentation site. 14 | > 15 | > If you want to use the latest version of GitHub Octicons, try [react-octicons](https://github.com/philschatz/react-octicons) or [react-icons](https://github.com/gorangajic/react-icons) instead, both of which provide a React component for each icon which renders an SVG. 16 | 17 | ### Demo 18 | 19 | https://insin.github.io/react-octicon/ 20 | 21 | ### Usage 22 | 23 | **Note: [Webpack](https://webpack.js.org) is _required_ in order to use this component.** 24 | 25 | Install and use the Octicon component like so: 26 | 27 | ``` 28 | npm install --save react-octicon 29 | ``` 30 | 31 | ```js 32 | import React from 'react' 33 | import {render} from 'react-dom' 34 | import Octicon from 'react-octicon' 35 | 36 | let App = () =>
37 | 38 |
39 | 40 | render(, document.querySelector('#app')) 41 | ``` 42 | 43 | #### Usage with nwb 44 | 45 | If you use [nwb](https://github.com/insin/nwb) to build and serve the React app you're using this component in, it will automatically configure Webpack to handle CSS, image and font dependencies for you. 46 | 47 | #### Usage with Webpack 48 | 49 | This component handles the Octicons CSS dependency for you, but you must use Webpack and configure it to handle CSS and associated font and image files. 50 | 51 | For example, using the following webpack loaders: 52 | 53 | ``` 54 | npm install --save-dev css-loader file-loader style-loader 55 | ``` 56 | 57 | ```js 58 | module: { 59 | rules: [ 60 | { 61 | test: /\.css$/, 62 | use: [ 63 | 'style-loader', 64 | 'css-loader' 65 | ] 66 | }, 67 | { 68 | test: /\.(eot|otf|svg|ttf|woff|woff2)$/, 69 | use: 'file-loader' 70 | } 71 | ] 72 | } 73 | ``` 74 | 75 | See Webpack's [Loading CSS documentation](https://webpack.js.org/guides/asset-management/#loading-css) for more info. 76 | 77 | ### Required props 78 | 79 | Prop | Description 80 | ---- | ------------- 81 | `name` | The name of an icon in the Octicons set, e.g. `'trashcan'` 82 | 83 | ### Other props 84 | 85 | Prop | Description 86 | ---- | ------------- 87 | `className` | An additional class name for the element rendered by the component 88 | `mega` | If `true`, a double-size icon will be displayed 89 | `spin` | If `true`, the icon will spin 90 | 91 | Any additional props given, such as event handlers or `aria-*` attributes, will be passed to the element rendered by the component. 92 | 93 | ## MIT licensed 94 | 95 | [build-badge]: https://img.shields.io/travis/insin/react-octicon/master.svg?style=flat-square 96 | [build]: https://travis-ci.org/insin/react-octicon 97 | 98 | [npm-badge]: https://img.shields.io/npm/v/react-octicon.svg?style=flat-square 99 | [npm]: https://www.npmjs.org/package/react-octicon 100 | 101 | [coveralls-badge]: https://img.shields.io/coveralls/insin/react-octicon/master.svg?style=flat-square 102 | [coveralls]: https://coveralls.io/github/insin/react-octicon 103 | -------------------------------------------------------------------------------- /css/Octicon.css: -------------------------------------------------------------------------------- 1 | .spin-octicon { 2 | animation: spin-octicon 2s infinite linear; 3 | } 4 | @keyframes spin-octicon { 5 | 0% { 6 | transform: rotate(0deg); 7 | } 8 | 100% { 9 | transform: rotate(359deg); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /demo/src/Demo.js: -------------------------------------------------------------------------------- 1 | import './demo.css' 2 | 3 | import copy from 'copy-to-clipboard' 4 | import React from 'react' 5 | 6 | import Octicon from '../../src/index' 7 | 8 | const OCTICON_NAMES = 'alert arrow-down arrow-left arrow-right arrow-small-down arrow-small-left arrow-small-right arrow-small-up arrow-up beaker bell bold book bookmark briefcase broadcast browser bug calendar check checklist chevron-down chevron-left chevron-right chevron-up circle-slash circuit-board clippy clock cloud-download cloud-upload code comment-discussion comment credit-card dash dashboard database desktop-download device-camera-video device-camera device-desktop device-mobile diff-added diff-ignored diff-modified diff-removed diff-renamed diff ellipses ellipsis eye file-binary file-code file-directory file-media file-pdf file-submodule file-symlink-directory file-symlink-file file-text file-zip file flame fold gear gift gist-secret gist git-branch git-commit git-compare git-merge git-pull-request globe grabber graph heart history home horizontal-rule hubot inbox info issue-closed issue-opened issue-reopened italic jersey key keyboard law light-bulb link-external link list-ordered list-unordered location lock logo-gist logo-github mail-read mail-reply mail mark-github markdown megaphone mention milestone mirror mortar-board mute no-newline octoface organization package paintcan pencil person pin plug plus-small plus primitive-dot primitive-square pulse question quote radio-tower reply repo-clone repo-force-push repo-forked repo-pull repo-push repo rocket rss ruby search server settings shield sign-in sign-out smiley squirrel star stop sync tag tasklist telescope terminal text-size three-bars thumbsdown thumbsup tools trashcan triangle-down triangle-left triangle-right triangle-up unfold unmute unverified verified versions watch x zap'.split(' ').sort() 9 | const OCTICON_NAMES_LOOKUP = OCTICON_NAMES.reduce( 10 | (lookup, name) => (lookup[name] = true, lookup), {} // eslint-disable-line 11 | ) 12 | 13 | export default class Demo extends React.Component { 14 | state = {copied: false, mega: true, search: 'sync', name: 'sync', spin: false} 15 | 16 | copyCode = () => { 17 | copy(this.getCode()) 18 | this.setState({copied: true}) 19 | if (this._copyTimeout) { 20 | window.clearTimeout(this._copyTimeout) 21 | } 22 | this._copyTimeout = window.setTimeout(() => this.setState({copied: false}), 500) 23 | } 24 | getCode() { 25 | let {mega, name, spin} = this.state 26 | return `` 27 | } 28 | updateSearch(search) { 29 | this.setState({ 30 | search, 31 | name: search in OCTICON_NAMES_LOOKUP ? search : this.state.name 32 | }) 33 | } 34 | 35 | handleCheckedChange = (e) => { 36 | this.setState({[e.target.name]: e.target.checked}) 37 | } 38 | handleIconClick = (name) => { 39 | this.updateSearch(name) 40 | window.scrollTo(0, 0) 41 | } 42 | handleIconKeyPress = (e, name) => { 43 | if (e.key === 'Enter') { 44 | e.preventDefault() 45 | this.updateSearch(name) 46 | window.scrollTo(0, 0) 47 | } 48 | } 49 | handleNameChange = (e) => { 50 | let name = e.target.value 51 | this.setState({name, search: name}) 52 | } 53 | // 88 | 89 | {OCTICON_NAMES.map(name => {' '} 91 | {' '} 99 | {' '} 102 | 105 |

106 |
107 | {OCTICON_NAMES.map(name => 108 |
this.handleIconClick(name)} 112 | onKeyPress={(e) => this.handleIconKeyPress(e, name)} 113 | tabIndex="0" 114 | title={name} 115 | > 116 | 117 |
118 | )} 119 |
120 |

121 | 122 | me on 123 | 124 |

125 | 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /demo/src/demo.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; 3 | font-size: 16px; 4 | height: 100%; 5 | margin: 0; 6 | } 7 | a { 8 | text-decoration: none; 9 | color: #00f; 10 | } 11 | code { 12 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; 13 | } 14 | p { 15 | margin: 1.5em 0; 16 | } 17 | #app { 18 | height: 100%; 19 | } 20 | .Demo { 21 | display: flex; 22 | flex-direction: column; 23 | align-items: center; 24 | text-align: center; 25 | } 26 | .Demo__icons { 27 | display: flex; 28 | flex-wrap: wrap; 29 | max-width: 740px; 30 | } 31 | .Demo__icon { 32 | box-sizing: border-box; 33 | width: 64px; 34 | border: 1px solid #000; 35 | padding: 16px; 36 | margin-right: 10px; 37 | margin-bottom: 10px; 38 | } 39 | .Demo__icon:hover, .Demo__icon:focus { 40 | cursor: pointer; 41 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); 42 | background-color: #ffe; 43 | } 44 | -------------------------------------------------------------------------------- /demo/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render} from 'react-dom' 3 | 4 | import Demo from './Demo' 5 | 6 | render(, document.querySelector('#demo')) 7 | -------------------------------------------------------------------------------- /nwb.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | type: 'react-component', 3 | npm: { 4 | umd: false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /octicons.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insin/react-octicon/cefc4a523e6aedacb1a3170b306bc9b015d1d7f5/octicons.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-octicon", 3 | "version": "3.0.1", 4 | "description": "A GitHub Octicons icon React component", 5 | "main": "./lib/index.js", 6 | "scripts": { 7 | "build": "nwb build", 8 | "lint": "eslint src tests demo/src", 9 | "test": "npm run lint && nwb test", 10 | "start": "nwb serve" 11 | }, 12 | "files": [ 13 | "css", 14 | "lib" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/insin/react-octicon" 19 | }, 20 | "keywords": [ 21 | "react-component", 22 | "octicon", 23 | "icon" 24 | ], 25 | "author": "Jonny Buchanan ", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/insin/react-octicon/issues" 29 | }, 30 | "homepage": "https://github.com/insin/react-octicon", 31 | "dependencies": { 32 | "octicons": "4.x", 33 | "prop-types": "^15.5.7" 34 | }, 35 | "peerDependencies": { 36 | "react": ">=0.13.0" 37 | }, 38 | "devDependencies": { 39 | "copy-to-clipboard": "3.x", 40 | "eslint-config-jonnybuchanan": "5.x", 41 | "nwb": "0.20.x", 42 | "react": "16.x", 43 | "react-dom": "16.x" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Octicon.js: -------------------------------------------------------------------------------- 1 | import '../css/Octicon.css' 2 | 3 | import React from 'react' 4 | import t from 'prop-types' 5 | 6 | let iconNames = process.env.NODE_ENV !== 'production' ? ( 7 | 'alert arrow-down arrow-left arrow-right arrow-small-down arrow-small-left arrow-small-right arrow-small-up arrow-up beaker bell bold book bookmark briefcase broadcast browser bug calendar check checklist chevron-down chevron-left chevron-right chevron-up circle-slash circuit-board clippy clock cloud-download cloud-upload code comment-discussion comment credit-card dash dashboard database desktop-download device-camera-video device-camera device-desktop device-mobile diff-added diff-ignored diff-modified diff-removed diff-renamed diff ellipses ellipsis eye file-binary file-code file-directory file-media file-pdf file-submodule file-symlink-directory file-symlink-file file-text file-zip file flame fold gear gift gist-secret gist git-branch git-commit git-compare git-merge git-pull-request globe grabber graph heart history home horizontal-rule hubot inbox info issue-closed issue-opened issue-reopened italic jersey key keyboard law light-bulb link-external link list-ordered list-unordered location lock logo-gist logo-github mail-read mail-reply mail mark-github markdown megaphone mention milestone mirror mortar-board mute no-newline octoface organization package paintcan pencil person pin plug plus-small plus primitive-dot primitive-square pulse question quote radio-tower reply repo-clone repo-force-push repo-forked repo-pull repo-push repo rocket rss ruby search server settings shield sign-in sign-out smiley squirrel star stop sync tag tasklist telescope terminal text-size three-bars thumbsdown thumbsup tools trashcan triangle-down triangle-left triangle-right triangle-up unfold unmute unverified verified versions watch x zap'.split(' ') 8 | ) : ( 9 | [] 10 | ) 11 | 12 | export default class Octicon extends React.Component { 13 | static propTypes = { 14 | name: t.oneOf(iconNames).isRequired, 15 | className: t.string, 16 | mega: t.bool, 17 | spin: t.bool, 18 | } 19 | static defaultProps = { 20 | mega: false, 21 | spin: false, 22 | } 23 | render() { 24 | let {name, className, mega, spin, ...props} = this.props 25 | let classNames = [mega ? 'mega-octicon' : 'octicon', `octicon-${name}`] 26 | if (spin) { 27 | classNames.push('spin-octicon') 28 | } 29 | if (className) { 30 | classNames.push(className) 31 | } 32 | return 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import 'octicons/build/font/octicons.css' 2 | 3 | import Octicon from './Octicon' 4 | 5 | export default Octicon 6 | -------------------------------------------------------------------------------- /tests/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/Octicon-test.js: -------------------------------------------------------------------------------- 1 | import expect from 'expect' 2 | import React from 'react' 3 | import {render, unmountComponentAtNode} from 'react-dom' 4 | import {Simulate} from 'react-dom/test-utils' 5 | 6 | import Octicon from 'src/' 7 | 8 | let {click} = Simulate 9 | 10 | describe('Octicon', () => { 11 | let node 12 | 13 | beforeEach(() => { 14 | node = document.createElement('div') 15 | }) 16 | 17 | afterEach(() => { 18 | unmountComponentAtNode(node) 19 | }) 20 | 21 | let testClassName = (component, expectedClassName) => 22 | it('renders a suitable className', () => { 23 | render(component, node, () => { 24 | let span = node.querySelector('span') 25 | expect(span).toExist() 26 | expect(span.className).toEqual(expectedClassName) 27 | }) 28 | }) 29 | 30 | testClassName(, 'octicon octicon-sync') 31 | testClassName(, 'mega-octicon octicon-sync') 32 | testClassName(, 'octicon octicon-sync spin-octicon') 33 | testClassName(, 'mega-octicon octicon-sync spin-octicon') 34 | testClassName(, 'mega-octicon octicon-sync spin-octicon custom') 35 | 36 | it('passes additional props through', () => { 37 | var onClick = expect.createSpy() 38 | render(, node, () => { 39 | let span = node.querySelector('span') 40 | expect(span).toExist() 41 | expect(span.className).toEqual('octicon octicon-sync') 42 | expect(span.getAttribute('role')).toEqual('progressbar') 43 | click(span) 44 | expect(onClick).toHaveBeenCalled() 45 | }) 46 | }) 47 | }) 48 | --------------------------------------------------------------------------------