font-picker-react
Advanced tools
Comparing version 1.3.0 to 2.0.0
@@ -7,3 +7,3 @@ 'use strict'; | ||
var React__default = _interopDefault(React); | ||
var FontPickerBase = _interopDefault(require('font-picker')); | ||
var fontPicker = require('font-picker'); | ||
@@ -59,19 +59,65 @@ var classCallCheck = function (instance, Constructor) { | ||
/** | ||
* Font picker presentational component | ||
* React interface for the font picker | ||
* @prop {string} apiKey (required) - Google API key | ||
* @prop {string} activeFont - Font that should be selected in the font picker and applied to the | ||
* text (default: 'Open Sans'). Must be stored in component state, and be updated using an onChange | ||
* listener. See README.md for an example. | ||
* @prop {Object} options - Object with additional (optional) parameters: | ||
* @prop {string} name - If you have multiple font pickers on your site, you need to give them | ||
* unique names (which may only consist of letters and digits). These names must also be appended | ||
* to the font picker's ID and the .apply-font class name. | ||
* Example: If { name: 'main' }, use #font-picker-main and .apply-font-main | ||
* @prop {string[]} families - If only specific fonts shall appear in the list, specify their | ||
* names in an array | ||
* @prop {string[]} categories - Array of font categories | ||
* Possible values: 'sans-serif', 'serif', 'display', 'handwriting', 'monospace' (default: all | ||
* categories) | ||
* @prop {string[]} variants - Array of variants which the fonts must include and which will be | ||
* downloaded; the first variant in the array will become the default variant (and will be used | ||
* in the font picker and the .apply-font class) | ||
* Example: ['regular', 'italic', '700', '700italic'] (default: ['regular']) | ||
* @prop {number} limit - Maximum number of fonts to be displayed in the list (the least popular | ||
* fonts will be omitted; default: 100) | ||
* @prop {string} sort - Sorting attribute for the font list | ||
* Possible values: 'alphabetical' (default), 'popularity' | ||
* @prop {function} onChange - Function which is executed whenever the user changes the active font | ||
* and its stylesheet finishes downloading | ||
*/ | ||
var FontPickerUI = function (_Component) { | ||
inherits(FontPickerUI, _Component); | ||
var FontPicker = function (_Component) { | ||
inherits(FontPicker, _Component); | ||
function FontPickerUI(props) { | ||
classCallCheck(this, FontPickerUI); | ||
function FontPicker(props) { | ||
classCallCheck(this, FontPicker); | ||
var _this = possibleConstructorReturn(this, (FontPickerUI.__proto__ || Object.getPrototypeOf(FontPickerUI)).call(this, props)); | ||
var _this = possibleConstructorReturn(this, (FontPicker.__proto__ || Object.getPrototypeOf(FontPicker)).call(this, props)); | ||
_this.state = { | ||
expanded: false | ||
activeFont: _this.props.activeFont, | ||
errorText: '', | ||
expanded: false, | ||
loadingStatus: 'loading' // possible values: 'loading', 'finished', 'error' | ||
}; | ||
// initialize FontManager object and generate the font list | ||
_this.fontManager = new fontPicker.FontManager(_this.props.apiKey, _this.props.activeFont, _this.props.options); | ||
_this.fontManager.init().then(function () { | ||
// font list has finished loading | ||
_this.setState({ | ||
errorText: '', | ||
loadingStatus: 'finished' | ||
}); | ||
}).catch(function (err) { | ||
// error while loading font list | ||
_this.setState({ | ||
errorText: 'Error trying to fetch the list of available fonts', | ||
loadingStatus: 'error' | ||
}); | ||
console.error(_this.state.errorText); | ||
console.error(err); | ||
}); | ||
// function bindings | ||
_this.closeEventListener = _this.closeEventListener.bind(_this); | ||
_this.setActiveFont = _this.setActiveFont.bind(_this); | ||
_this.onClose = _this.onClose.bind(_this); | ||
_this.onScroll = _this.onScroll.bind(_this); | ||
@@ -83,12 +129,13 @@ _this.toggleExpanded = _this.toggleExpanded.bind(_this); | ||
/** | ||
* Download the font previews for all visible font entries and the five after them | ||
* After every component update, check whether the activeFont prop has changed. If so, change the | ||
* font in the fontManager as well | ||
*/ | ||
createClass(FontPickerUI, [{ | ||
key: 'onScroll', | ||
value: function onScroll(e) { | ||
var elementHeight = e.target.scrollHeight / this.props.fontList.length; | ||
var downloadIndex = Math.ceil((e.target.scrollTop + e.target.clientHeight) / elementHeight); | ||
this.props.downloadPreviews(downloadIndex + 5); | ||
createClass(FontPicker, [{ | ||
key: 'componentDidUpdate', | ||
value: function componentDidUpdate() { | ||
if (this.state.activeFont !== this.props.activeFont) { | ||
this.setActiveFont(this.props.activeFont); | ||
} | ||
} | ||
@@ -101,4 +148,4 @@ | ||
}, { | ||
key: 'closeEventListener', | ||
value: function closeEventListener(e) { | ||
key: 'onClose', | ||
value: function onClose(e) { | ||
var targetElement = e.target; // clicked element | ||
@@ -120,2 +167,14 @@ | ||
/** | ||
* Download the font previews for all visible font entries and the five after them | ||
*/ | ||
}, { | ||
key: 'onScroll', | ||
value: function onScroll(e) { | ||
var elementHeight = e.target.scrollHeight / this.fontManager.fonts.length; | ||
var downloadIndex = Math.ceil((e.target.scrollTop + e.target.clientHeight) / elementHeight); | ||
this.fontManager.downloadPreviews(downloadIndex + 5); | ||
} | ||
/** | ||
* Set the font with the given font list index as the active one | ||
@@ -125,6 +184,21 @@ */ | ||
}, { | ||
key: 'selectFont', | ||
value: function selectFont(index) { | ||
this.toggleExpanded(); // collapse font list | ||
this.props.selectFont(index); | ||
key: 'setActiveFont', | ||
value: function setActiveFont(fontFamily) { | ||
var activeFontIndex = this.fontManager.setActiveFont(fontFamily); | ||
if (activeFontIndex === -1) { | ||
// error trying to change font | ||
this.setState({ | ||
activeFont: fontFamily, | ||
errorText: 'Cannot update activeFont: The font "' + fontFamily + '" is not in the font list', | ||
loadingStatus: 'error' | ||
}); | ||
console.error(this.state.errorText); | ||
} else { | ||
// font change successful | ||
this.setState({ | ||
activeFont: fontFamily, | ||
errorText: '', | ||
loadingStatus: 'finished' | ||
}); | ||
} | ||
} | ||
@@ -140,7 +214,11 @@ | ||
if (this.state.expanded) { | ||
this.setState({ expanded: false }); | ||
document.removeEventListener('click', this.closeEventListener); | ||
this.setState({ | ||
expanded: false | ||
}); | ||
document.removeEventListener('click', this.onClose); | ||
} else { | ||
this.setState({ expanded: true }); | ||
document.addEventListener('click', this.closeEventListener); | ||
this.setState({ | ||
expanded: true | ||
}); | ||
document.addEventListener('click', this.onClose); | ||
} | ||
@@ -153,45 +231,41 @@ } | ||
// generate <ul> with font names; fetch font previews on scroll | ||
var fontList = React__default.createElement( | ||
'ul', | ||
{ | ||
className: this.state.expanded ? 'expanded' : '', | ||
onScroll: this.onScroll | ||
}, | ||
this.props.fontList.map(function (font, index) { | ||
var fontId = font.family.replace(/\s+/g, '-').toLowerCase(); | ||
var isActive = font.family === _this2.props.activeFont.family; | ||
return React__default.createElement( | ||
'li', | ||
{ key: font.family }, | ||
React__default.createElement( | ||
'a', | ||
{ | ||
role: 'button', | ||
tabIndex: '0', | ||
onClick: function onClick() { | ||
return _this2.selectFont(index); | ||
// generate <ul> with font list; fetch font previews on scroll | ||
var fontList = void 0; | ||
if (this.state.loadingStatus === 'finished') { | ||
fontList = React__default.createElement( | ||
'ul', | ||
{ className: this.state.expanded ? 'expanded' : '', onScroll: this.onScroll }, | ||
this.fontManager.fonts.map(function (font) { | ||
var isActive = font.family === _this2.state.activeFont; | ||
var fontId = font.family.replace(/\s+/g, '-').toLowerCase(); | ||
return React__default.createElement( | ||
'li', | ||
{ key: font.family }, | ||
React__default.createElement( | ||
'button', | ||
{ | ||
className: 'font-' + fontId + ' ' + (isActive ? 'active-font' : ''), | ||
onClick: function onClick() { | ||
_this2.toggleExpanded(); | ||
_this2.props.onChange(font); | ||
}, | ||
onKeyPress: function onKeyPress() { | ||
_this2.toggleExpanded(); | ||
_this2.props.onChange(font); | ||
} | ||
}, | ||
onKeyPress: function onKeyPress() { | ||
return _this2.selectFont(index); | ||
}, | ||
className: 'font-' + fontId + ' ' + (isActive ? 'active-font' : '') | ||
}, | ||
font.family | ||
) | ||
); | ||
}) | ||
); | ||
font.family | ||
) | ||
); | ||
}) | ||
); | ||
} | ||
// render font picker button and attach font list to it | ||
return React__default.createElement( | ||
'div', | ||
{ | ||
id: 'font-picker' + this.props.name, | ||
title: this.props.loadingStatus === 'error' ? 'Error trying to fetch the list of available fonts' : '' | ||
}, | ||
{ id: 'font-picker' + this.fontManager.name, title: this.state.errorText }, | ||
React__default.createElement( | ||
'a', | ||
'button', | ||
{ | ||
role: 'button', | ||
tabIndex: '0', | ||
className: 'dropdown-button ' + (this.state.expanded ? 'expanded' : ''), | ||
@@ -204,121 +278,10 @@ onClick: this.toggleExpanded, | ||
null, | ||
this.props.activeFont.family | ||
this.state.activeFont | ||
), | ||
React__default.createElement('div', { className: 'dropdown-icon ' + this.props.loadingStatus }) | ||
React__default.createElement('div', { className: 'dropdown-icon ' + this.state.loadingStatus }) | ||
), | ||
this.props.loadingStatus === 'finished' && fontList | ||
this.state.loadingStatus === 'finished' && fontList | ||
); | ||
} | ||
}]); | ||
return FontPickerUI; | ||
}(React.Component); | ||
/** | ||
* Font picker container component | ||
* @prop {string} apiKey (required) - Google API key (can be generated at | ||
* https://developers.google.com/fonts/docs/developer_api) | ||
* @prop {string} defaultFont - Font that is selected on initialization (default: 'Open Sans') | ||
* @prop {Object} options - Object with additional (optional) parameters: | ||
* @prop {string} name - If you have multiple font pickers on your site, you need to give them | ||
* unique names (which may only consist of letters and digits). These names must also be | ||
* appended to the font picker's ID and the .apply-font class name. | ||
* Example: if { name: 'main' }, then use #font-picker-main and .apply-font-main | ||
* @prop {string[]} families - If only specific fonts shall appear in the list, specify their | ||
* names in an array | ||
* @prop {string[]} categories - Array of font categories | ||
* Possible values: 'sans-serif', 'serif', 'display', 'handwriting', 'monospace' (default: | ||
* all categories) | ||
* @prop {string[]} variants - Array of variants which the fonts must include and which will be | ||
* downloaded; the first variant in the array will become the default variant (and will be | ||
* used in the font picker and the .apply-font class) | ||
* Example: ['regular', 'italic', '700', '700italic'] (default: ['regular']) | ||
* @prop {number} limit - Maximum number of fonts to be displayed in the list (the least popular | ||
* fonts will be omitted; default: 100) | ||
* @prop {string} sort - Sorting attribute for the font list | ||
* Possible values: 'alphabetical' (default), 'popularity' | ||
* @prop {function} onChange - Function which is executed whenever the user changes the active | ||
* font and its stylesheet finishes downloading | ||
*/ | ||
var FontPicker = function (_Component) { | ||
inherits(FontPicker, _Component); | ||
function FontPicker(props) { | ||
classCallCheck(this, FontPicker); | ||
var _this = possibleConstructorReturn(this, (FontPicker.__proto__ || Object.getPrototypeOf(FontPicker)).call(this, props)); | ||
_this.state = { | ||
activeFont: { | ||
family: _this.props.defaultFont | ||
}, | ||
fontList: [], | ||
loadingStatus: 'loading' | ||
}; | ||
// initialize FontHandler object and generate the font list | ||
var fontPickerBase = new FontPickerBase(_this.props.apiKey, _this.props.defaultFont, _this.props.options, _this.props.onChange); | ||
_this.fontHandler = fontPickerBase.fontHandler; | ||
_this.fontHandler.init().then(function () { | ||
// on font list load: save it to component state | ||
_this.setState({ | ||
activeFont: _this.fontHandler.activeFont, | ||
fontList: _this.fontHandler.fonts, | ||
loadingStatus: 'finished' | ||
}); | ||
}).catch(function (err) { | ||
console.error('Error trying to fetch the list of available fonts'); | ||
console.error(err); | ||
_this.setState({ | ||
loadingStatus: 'error' | ||
}); | ||
}); | ||
// function bindings | ||
_this.selectFont = _this.selectFont.bind(_this); | ||
_this.update = _this.update.bind(_this); | ||
return _this; | ||
} | ||
/** | ||
* Set the font with the given font list index as the active one | ||
*/ | ||
createClass(FontPicker, [{ | ||
key: 'selectFont', | ||
value: function selectFont(index) { | ||
this.fontHandler.changeActiveFont(index); | ||
this.update(); | ||
} | ||
/** | ||
* Updates the component state with the changed information in fontHandler | ||
*/ | ||
}, { | ||
key: 'update', | ||
value: function update() { | ||
this.setState({ | ||
activeFont: this.fontHandler.activeFont, | ||
fontList: this.fontHandler.fonts | ||
}); | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var _this2 = this; | ||
return React__default.createElement(FontPickerUI, { | ||
activeFont: this.state.activeFont, | ||
downloadPreviews: function downloadPreviews(downloadIndex) { | ||
return _this2.fontHandler.downloadPreviews(downloadIndex); | ||
}, | ||
fontList: this.state.fontList, | ||
loadingStatus: this.state.loadingStatus, | ||
name: this.fontHandler.name, | ||
selectFont: this.selectFont | ||
}); | ||
} | ||
}]); | ||
return FontPicker; | ||
@@ -325,0 +288,0 @@ }(React.Component); |
{ | ||
"name": "font-picker-react", | ||
"version": "1.3.0", | ||
"description": "Font picker component for previewing, selecting, and downloading Google Fonts", | ||
"version": "2.0.0", | ||
"description": "Font selector component for Google Fonts", | ||
"keywords": [ | ||
@@ -9,5 +9,8 @@ "fonts", | ||
"selector", | ||
"picker", | ||
"component", | ||
"preview", | ||
"download", | ||
"react", | ||
"component" | ||
"react-component" | ||
], | ||
@@ -20,5 +23,6 @@ "main": "lib/FontPicker.js", | ||
"scripts": { | ||
"start": "rollup -c --watch", | ||
"start": "npm-run-all build --parallel start:*", | ||
"start:rollup": "rollup -c --watch", | ||
"start:storybook": "start-storybook -p 6006", | ||
"build": "rollup -c", | ||
"storybook": "start-storybook -p 6006", | ||
"lint": "eslint .", | ||
@@ -29,12 +33,12 @@ "precommit": "npm run lint", | ||
"dependencies": { | ||
"font-picker": "^1.3.0" | ||
"font-picker": "^2.0.0" | ||
}, | ||
"peerDependencies": { | ||
"react": "^16.0.0" | ||
"react": "^16.3.1" | ||
}, | ||
"devDependencies": { | ||
"@storybook/addon-actions": "^3.3.15", | ||
"@storybook/addon-links": "^3.3.15", | ||
"@storybook/addons": "^3.3.15", | ||
"@storybook/react": "^3.3.15", | ||
"@storybook/addon-actions": "^3.4.2", | ||
"@storybook/addon-links": "^3.4.2", | ||
"@storybook/addons": "^3.4.2", | ||
"@storybook/react": "^3.4.2", | ||
"babel-core": "^6.26.0", | ||
@@ -46,9 +50,10 @@ "babel-plugin-external-helpers": "^6.22.0", | ||
"eslint-config-airbnb": "^16.1.0", | ||
"eslint-plugin-import": "^2.9.0", | ||
"eslint-plugin-import": "^2.11.0", | ||
"eslint-plugin-jsx-a11y": "^6.0.2", | ||
"eslint-plugin-react": "^7.7.0", | ||
"husky": "^0.14.3", | ||
"react": "^16.0.0", | ||
"react-dom": "^16.0.0", | ||
"rollup": "^0.57.1", | ||
"npm-run-all": "^4.1.2", | ||
"react": "^16.3.2", | ||
"react-dom": "^16.3.2", | ||
"rollup": "^0.58.0", | ||
"rollup-plugin-babel": "^3.0.3" | ||
@@ -55,0 +60,0 @@ }, |
@@ -6,6 +6,6 @@ # Font Picker for React | ||
**A simple, customizable font selector allowing users to preview, choose, and use Google Fonts on your website.** | ||
**A simple, customizable font picker allowing users to preview, select, and use Google Fonts on your website.** | ||
* automatic font download and generation of the required CSS styles | ||
* efficient font previews (previews in the list are loaded dynamically; the full font is only downloaded on selection) | ||
* Automatic font download and generation of the required CSS styles | ||
* Efficient font previews (previews are loaded dynamically and full fonts are only downloaded on selection) | ||
@@ -17,3 +17,3 @@ → **[Demo](https://smeuli.github.io/font-picker)** | ||
<p align="center"> | ||
<img src=".github/demo.gif" width=700 alt="Demo"> | ||
<img src=".github/demo.gif" width=700 alt="Demo"> | ||
</p> | ||
@@ -24,28 +24,48 @@ | ||
### Setup | ||
### 1. Setup | ||
Add the package as a dependency using **NPM**: | ||
Install the package using **NPM**: | ||
``` | ||
```sh | ||
npm install font-picker-react | ||
``` | ||
Then add the **`<FontPicker />` component** somewhere in your React project: | ||
### 2. Displaying the font picker | ||
Add the **`<FontPicker />` component** to your React code: | ||
```jsx | ||
import React, { Component } from 'react'; | ||
import FontPicker from 'font-picker-react'; | ||
<FontPicker | ||
apiKey="YOUR_API_KEY" // Google API key | ||
defaultFont={'Open Sans'} | ||
options={{ limit: 50 }} | ||
/> | ||
export default class ExampleComponent extends Component { | ||
constructor() { | ||
super(); | ||
this.state = { activeFont: 'Open Sans' }; | ||
} | ||
render() { | ||
return ( | ||
<div> | ||
<FontPicker | ||
apiKey="YOUR_API_KEY" | ||
activeFont={this.state.activeFont} | ||
onChange={nextFont => this.setState({ activeFont: nextFont.family })} | ||
/> | ||
<p className="apply-font"> | ||
The font will be applied to this text. | ||
</p> | ||
</div> | ||
); | ||
} | ||
} | ||
``` | ||
### Applying the selected font | ||
### 3. Applying the selected font | ||
**Add `className="apply-font"` to all JSX elements you want to apply the selected font to.** | ||
When the user selects a font using the font picker, it will automatically be downloaded (added as a `<link>` to the document's head) and applied to all HTML elements of the `"apply-font"` class. | ||
When the user selects a font, it will automatically be downloaded and applied to all HTML elements of the `"apply-font"` class. | ||
@@ -55,10 +75,8 @@ | ||
### Props | ||
The following **props** can be passed to the `FontPicker` component: | ||
The following props can be passed to the `FontPicker` component: | ||
* **`apiKey` (required)**: Google API key (can be generated [here](https://developers.google.com/fonts/docs/developer_api#APIKey)) | ||
* **`defaultFont`**: Font that is selected on initialization (default: `'Open Sans'`) | ||
* **`activeFont`**: Font that should be selected in the font picker and applied to the text (default: `'Open Sans'`). Must be stored in component state, and be updated using an `onChange` listener | ||
* **`options`**: Object with additional (optional) parameters: | ||
* **`name`**: If you have multiple font pickers on your site, you need to give them unique names (which may only consist of letters and digits). These names must also be appended to the font picker's ID and the `.apply-font` class name; e.g. if `{ name: 'main' }`, then use `#font-picker-main` and `.apply-font-main` | ||
* **`name`**: If you have multiple font pickers on your site, you need to give them unique names (which may only consist of letters and digits). These names must also be appended to the font picker's ID and the `.apply-font` class name; e.g. if `{ name: 'main' }`, use `#font-picker-main` and `.apply-font-main` | ||
* **`families`**: If only specific fonts shall appear in the list, specify their names in an array (default: all font families) | ||
@@ -72,7 +90,8 @@ * **`categories`**: Array of font categories – possible values: `'sans-serif', 'serif', 'display', handwriting', 'monospace'` (default: all categories) | ||
## Build Process | ||
## Contributing | ||
To build the project locally, do the following: | ||
* `git clone` | ||
* `npm install` | ||
* `npm start` to generate the library bundle using [Rollup](https://github.com/rollup/rollup) (in the `lib` directory) | ||
* See the font picker in action using [Storybook](https://github.com/storybooks/storybook): `npm run storybook` | ||
* `npm start` to generate the library bundle using [Rollup](https://github.com/rollup/rollup) and and start the [Storybook](https://github.com/storybooks/storybook) for testing the component interactively |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
93
15640
19
249
1
+ Addedfont-picker@2.2.1(transitive)
+ Addedlodash.throttle@4.1.1(transitive)
- Removedfont-picker@1.3.0(transitive)
Updatedfont-picker@^2.0.0