Skip to content

Commit

Permalink
Fixed React Invalid Hook Error by removing useFontObserver. Improved …
Browse files Browse the repository at this point in the history
…readme, and default values.
  • Loading branch information
scottcanoni committed Apr 23, 2023
1 parent c9c1aaa commit 51ba2e2
Show file tree
Hide file tree
Showing 14 changed files with 181 additions and 155 deletions.
65 changes: 29 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,60 +45,46 @@ To control the animation speed and timing, you can pass an object of `animationO
randomReverseMax: 6000,
loopAnimation: 20000,
waitToStart: 5000,
transitionDuration: 2000,
timingFunction: 'ease-in-out',
}} />
```

If you are using an embedded font and need to wait for it to load before animating,
then you should specify the `fontToObserve` object with the font family name and/or other font specifics.
then you should specify the `fontToObserve` property with the font family name.

```js
<Anagram fontToObserve={{ family: 'Open Sans' }} />
<Anagram fontToObserve="Open Sans" />
```
```js
<Anagram fontToObserve={{
family: 'Roboto',
weight: 600,
style: 'italic',
stretch: 'expanded',
}} />
<Anagram fontToObserve="Roboto" />
```

API
----

### Props

| Prop | Type | Default | Description |
| :----------------- | :----- | :------------------------------------------------------- | :------------------------------------------------------ |
| `words` | array | `['React Anagram Animation', 'Magenta Raincoat Airman']` | An array containing exactly 2 words which are an anagram of each other. |
| `animationOptions` | object | `AnimationOptions` | Timing options for when to start, how fast to animate forwards, backwards, and when to loop (optional). |
| `fontToObserve` | object | `FontToObserve` | A description of an embedded font to observe and wait until loaded. If not specified, animation will loaded immediately (optional). |
| Prop | Type | Default | Description |
| :----------------- |:-------|:---------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------|
| `words` | array | `['React Anagram Animation', 'Magenta Raincoat Airman']` | An array containing exactly 2 words which are an anagram of each other. |
| `animationOptions` | object | `AnimationOptions` | Timing options for when to start, how fast to animate forwards, backwards, and when to loop (optional). |
| `fontToObserve` | string | | The name of an embedded font to wait until loaded. If not specified, animation will loaded immediately (optional). |

#### AnimationOptions

All time values are in # of milliseconds.

| Property | Type | Default | Description |
| :------------------- | :----- | :------------ | :-------------------------------------------------------------------------------------------- |
| `randomStartMin` | number | `0` | The minimum amount of time to randomly wait before starting to animate each letter |
| `randomStartMax` | number | `3000` | The maximum amount of time to randomly wait before starting to animate each letter |
| `randomReverseMin` | number | `6000` | The minimum amount of time to randomly wait before starting to animate each letter in reverse |
| `randomReverseMax` | number | `9000` | The maximum amount of time to randomly wait before starting to animate each letter in reverse |
| `loopAnimation` | number | `12000` | The amount of time for each full loop of the animation |
| `waitToStart` | number | `0` | The amount of time to wait before beginning the animation on start up |
| `transitionDuration` | number | `2000` | How long should it take for a letter to move to its next position |
| `timingFunction` | string | `ease-in-out` | What timing function should be used for the animation |

#### FontToObserve

This object is passed along to [Font Face Observer](https://github.com/iamskok/use-font-face-observer)
All time values are in # of milliseconds. The randomness allows a nice jumble effect. You can use any values you want to create some fascinating animations.

| Property | Type | Description |
| :---------| :--------------- | :------------------------------------------------------- |
| `family` | string | The font-family: `Roboto`, `Inter`, `Open Sans`, etc |
| `weight` | string or number | The font-weight: `normal`, `bold`, `800`, etc |
| `style` | string | The font-style: `normal`, `italic`, `oblique` |
| `stretch` | string | The font stretch: `normal`, `condensed`, `expanded`, etc |
| Property | Type | Default | Description |
| :------------------- | :----- |:--------------|:--------------------------------------------------------------------------------------------------------------------------------------|
| `randomStartMin` | number | `0` | The minimum amount of time to randomly wait before starting to animate each letter. |
| `randomStartMax` | number | `3000` | The maximum amount of time to randomly wait before starting to animate each letter. Should be `>= randomStartMin`. |
| `randomReverseMin` | number | `6000` | The minimum amount of time to randomly wait before starting to animate each letter in reverse. |
| `randomReverseMax` | number | `9000` | The maximum amount of time to randomly wait before starting to animate each letter in reverse. Should be `>= randomReverseMin`. |
| `loopAnimation` | number | `12000` | The amount of time to wait before starting the next full loop of the animation. Should be `>= randomReverseMax + transitionDuration`. |
| `waitToStart` | number | `0` | The amount of time to wait before beginning the animation on start up the first time. |
| `transitionDuration` | number | `1000` | How long should it take for a letter to move to its next position. Should be `<= randomReverseMin - randomStartMax`. |
| `timingFunction` | string | `ease-in-out` | What [timing function](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function) should be used for the animation. |

Run Locally
----
Expand All @@ -110,11 +96,18 @@ To run demo locally:

and a browser will open to the demo.

If you receive `Invalid hook call` errors because you are linking this module, you may need to point this library's React to your app's installed React so there is only one copy.

```
npm link ../my-app/node_modules/react
npm link ../my-app/node_modules/react-dom
```

Future Ideas
----

- Animate between more than 2 words.
- Animate non-anagram words.
- Animate non-anagram words. [Done](https://www.npmjs.com/package/react-text-swap-animation).


License
Expand Down
9 changes: 2 additions & 7 deletions dist/components/Anagram.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use strict";

require("core-js/modules/es.symbol.description.js");
require("core-js/modules/es.weak-map.js");
Object.defineProperty(exports, "__esModule", {
value: true
});
Expand Down Expand Up @@ -76,19 +77,15 @@ function Anagram(_ref) {
element: lettersRefs1.current[i].current,
offsetLeft: lettersRefs1.current[i].current.offsetLeft,
offsetTop: lettersRefs1.current[i].current.offsetTop
// rect: lettersRefs1.current[i].current.getBoundingClientRect(),
},

// the destination location and letter
dest: {
letter: words[1][destLetterIndex],
element: lettersRefs2.current[destLetterIndex].current,
offsetLeft: lettersRefs2.current[destLetterIndex].current.offsetLeft,
offsetTop: lettersRefs2.current[destLetterIndex].current.offsetTop
// rect: lettersRefs2.current[destLetterIndex].current.getBoundingClientRect(),
}
};

swaps.push(swap);
});
setAnimations(swaps);
Expand Down Expand Up @@ -127,7 +124,6 @@ function Anagram(_ref) {
}, /*#__PURE__*/_react.default.createElement("div", {
className: "word word-1 hidden"
}, [...words[0]].map((letter, i) => {
// eslint-disable-next-line react/no-array-index-key
return /*#__PURE__*/_react.default.createElement("span", {
ref: lettersRefs1.current[i],
className: "letter",
Expand All @@ -136,15 +132,14 @@ function Anagram(_ref) {
})), /*#__PURE__*/_react.default.createElement("div", {
className: "word word-2 hidden"
}, [...words[1]].map((letter, i) => {
// eslint-disable-next-line react/no-array-index-key
return /*#__PURE__*/_react.default.createElement("span", {
ref: lettersRefs2.current[i],
className: "letter",
key: "".concat(i).concat(letter)
}, letter);
})), /*#__PURE__*/_react.default.createElement("div", {
className: "word word-animation"
}, swapAnimations.map((renderedLetter, i) => {
}, swapAnimations.map(renderedLetter => {
const {
id,
letter,
Expand Down
16 changes: 9 additions & 7 deletions dist/components/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ const DEFAULT_WORDS = ['React Anagram Animation', 'Magenta Raincoat Airman'];

/**
* @typedef AnimationOptions Timing options for when to start, how fast to animate forwards, backwards, and when to loop.
* @property {number} randomStartMin The minimum amount of time to randomly wait before starting to animate each letter
* @property {number} randomStartMax The maximum amount of time to randomly wait before starting to animate each letter
* @property {number} randomReverseMin The minimum amount of time to randomly wait before starting to animate each letter in reverse
* @property {number} randomReverseMax The maximum amount of time to randomly wait before starting to animate each letter in reverse
* @property {number} loopAnimation The amount of time for each full loop of the animation
* @property {number} waitToStart The amount of time to wait before beginning the animation on start up
* @property {number} randomStartMin The minimum amount of time to randomly wait before starting to animate each letter.
* @property {number} randomStartMax The maximum amount of time to randomly wait before starting to animate each letter. Should be `>= randomStartMin`.
* @property {number} randomReverseMin The minimum amount of time to randomly wait before starting to animate each letter in reverse.
* @property {number} randomReverseMax The maximum amount of time to randomly wait before starting to animate each letter in reverse. Should be `>= randomReverseMin`.
* @property {number} loopAnimation The amount of time to wait before starting the next full loop of the animation. Should be `>= randomReverseMax + transitionDuration`.
* @property {number} waitToStart The amount of time to wait before beginning the animation on start up the first time.
* @property {number} transitionDuration How long should it take for a letter to move to its next position. Should be `<= randomReverseMin - randomStartMax`.
* @property {string} timingFunction What [timing function](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function) should be used for the animation.
*/

/** @type AnimationOptions */
Expand All @@ -25,7 +27,7 @@ const DEFAULT_ANIMATION_OPTIONS = {
randomReverseMax: 9000,
loopAnimation: 12000,
waitToStart: 0,
transitionDuration: 2000,
transitionDuration: 1000,
timingFunction: 'ease-in-out'
};
exports.DEFAULT_ANIMATION_OPTIONS = DEFAULT_ANIMATION_OPTIONS;
17 changes: 4 additions & 13 deletions dist/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
exports.default = Loader;
require("core-js/modules/es.symbol.description.js");
var _react = _interopRequireDefault(require("react"));
var _useFontFaceObserver = _interopRequireDefault(require("use-font-face-observer"));
var _useFonts = _interopRequireDefault(require("./useFonts"));
var _Anagram = _interopRequireDefault(require("./Anagram"));
var _constants = require("./constants");
require("./index.css");
Expand All @@ -16,19 +16,11 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
/**
* @typedef FontToObserve A description of an embedded font to observe and wait until loaded.
* @property {string} [family] The font-family: Roboto, Inter, Open Sans, etc
* @property {string|number} [weight] The font-weight: normal, bold, 800, etc
* @property {string} [style] The font-style: normal, italic, oblique
* @property {string} [stretch] The font stretch: normal, condensed, expanded, etc
*/

/**
* Render and animate from one word to another word and back again.
* @param {[string]} [words] The 2 words to animate between.
* @param {AnimationOptions} [animationOptions] Timing options for when to start, how fast to animate forwards, backwards, and when to loop.
* @param {FontToObserve} [fontToObserve] A description of an embedded font to observe and wait until loaded.
* @param {string} [fontToObserve] A description of an embedded font to observe and wait until loaded.
* @returns {JSX.Element|null}
*/
function Loader(_ref) {
Expand All @@ -37,10 +29,9 @@ function Loader(_ref) {
animationOptions = {},
fontToObserve
} = _ref;
const animOptions = _objectSpread(_objectSpread({}, _constants.DEFAULT_ANIMATION_OPTIONS), animationOptions);
const isFontLoaded = (0, _useFontFaceObserver.default)(fontToObserve ? [fontToObserve] : []);
const isFontLoaded = (0, _useFonts.default)(fontToObserve);
return isFontLoaded ? /*#__PURE__*/_react.default.createElement(_Anagram.default, {
words: words,
animationOptions: animOptions
animationOptions: _objectSpread(_objectSpread({}, _constants.DEFAULT_ANIMATION_OPTIONS), animationOptions)
}) : null;
}
29 changes: 29 additions & 0 deletions dist/components/useFonts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"use strict";

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = useFonts;
require("core-js/modules/web.dom-collections.iterator.js");
require("core-js/modules/es.promise.js");
var _react = require("react");
function useFonts() {
for (var _len = arguments.length, fontNames = new Array(_len), _key = 0; _key < _len; _key++) {
fontNames[_key] = arguments[_key];
}
const [isLoaded, setIsLoaded] = (0, _react.useState)(false);
(0, _react.useEffect)(() => {
// Inspired by https://stackoverflow.com/a/60138011
if (!document || !document.fonts) {
// eslint-disable-next-line no-console
console.warn('Browser does not support document.fonts API');
setIsLoaded(true);
return;
}
Promise.all(fontNames.map(fontName => document.fonts.load("16px \"".concat(fontName, "\"")))).then(() => {
setIsLoaded(true);
});
}, [fontNames]);
return isLoaded;
}
;
1 change: 0 additions & 1 deletion dist/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ exports.uuidv4 = uuidv4;
require("core-js/modules/es.regexp.exec.js");
require("core-js/modules/es.string.replace.js");
require("core-js/modules/es.array.sort.js");
require("core-js/modules/es.string.split.js");
require("core-js/modules/es.regexp.to-string.js");
function isAnagram(stringA, stringB) {
// Sanitizing
Expand Down

0 comments on commit 51ba2e2

Please sign in to comment.