diff --git a/README.md b/README.md
index 1622d89..6a92199 100644
--- a/README.md
+++ b/README.md
@@ -45,22 +45,19 @@ 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
-
+
```
```js
-
+
```
API
@@ -68,37 +65,26 @@ 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
----
@@ -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
diff --git a/dist/components/Anagram.js b/dist/components/Anagram.js
index 7b79a67..4f0b340 100644
--- a/dist/components/Anagram.js
+++ b/dist/components/Anagram.js
@@ -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
});
@@ -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);
@@ -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",
@@ -136,7 +132,6 @@ 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",
@@ -144,7 +139,7 @@ function Anagram(_ref) {
}, letter);
})), /*#__PURE__*/_react.default.createElement("div", {
className: "word word-animation"
- }, swapAnimations.map((renderedLetter, i) => {
+ }, swapAnimations.map(renderedLetter => {
const {
id,
letter,
diff --git a/dist/components/constants.js b/dist/components/constants.js
index 7f1d7eb..04d1977 100644
--- a/dist/components/constants.js
+++ b/dist/components/constants.js
@@ -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 */
@@ -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;
\ No newline at end of file
diff --git a/dist/components/index.js b/dist/components/index.js
index a0aae80..502f0b1 100644
--- a/dist/components/index.js
+++ b/dist/components/index.js
@@ -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");
@@ -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) {
@@ -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;
}
\ No newline at end of file
diff --git a/dist/components/useFonts.js b/dist/components/useFonts.js
new file mode 100644
index 0000000..e231c37
--- /dev/null
+++ b/dist/components/useFonts.js
@@ -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;
+}
+;
\ No newline at end of file
diff --git a/dist/utils.js b/dist/utils.js
index 5e9679c..7d37df2 100644
--- a/dist/utils.js
+++ b/dist/utils.js
@@ -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
diff --git a/package-lock.json b/package-lock.json
index 621e61e..e3e8257 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "react-anagram-animation",
- "version": "1.3.1",
+ "version": "1.4.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -6293,11 +6293,6 @@
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"dev": true
},
- "fontfaceobserver": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.1.0.tgz",
- "integrity": "sha512-ReOsO2F66jUa0jmv2nlM/s1MiutJx/srhAe2+TE8dJCMi02ZZOcCTxTCQFr3Yet+uODUtnr4Mewg+tNQ+4V1Ng=="
- },
"for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@@ -9186,7 +9181,8 @@
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
},
"js-yaml": {
"version": "3.14.1",
@@ -9448,6 +9444,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
@@ -9844,7 +9841,8 @@
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "dev": true
},
"object-hash": {
"version": "3.0.0",
@@ -11284,6 +11282,23 @@
"dev": true,
"requires": {
"loose-envify": "^1.1.0"
+ },
+ "dependencies": {
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ }
}
},
"react-app-polyfill": {
@@ -11444,6 +11459,32 @@
"requires": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.0"
+ },
+ "dependencies": {
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "requires": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ }
+ },
+ "scheduler": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
+ "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.1.0"
+ }
+ }
}
},
"react-error-overlay": {
@@ -12018,15 +12059,6 @@
"xmlchars": "^2.2.0"
}
},
- "scheduler": {
- "version": "0.23.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
- "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.1.0"
- }
- },
"schema-utils": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
@@ -13075,26 +13107,6 @@
"requires-port": "^1.0.0"
}
},
- "use-font-face-observer": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/use-font-face-observer/-/use-font-face-observer-1.2.1.tgz",
- "integrity": "sha512-5ieKTMvtUux0l7YoOEz842djfgMH3oVg+tO13E/kyS+gGRLDyfAMmRv0D3fzM7UdFag1kz+3AQIFLkkfEF3TUg==",
- "requires": {
- "fontfaceobserver": "2.1.0",
- "react": "17.0.2"
- },
- "dependencies": {
- "react": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
- "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1"
- }
- }
- }
- },
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
diff --git a/package.json b/package.json
index e32ae94..856d4f2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-anagram-animation",
- "version": "1.3.2",
+ "version": "1.4.0",
"author": "Scott Canoni",
"description": "A React component to use CSS animations to swap letters in 2 words which are an anagram of each other. The text is animated in position after calculating initial and final positions of each letter.",
"license": "WTFPL",
@@ -30,8 +30,7 @@
"rearrange"
],
"dependencies": {
- "core-js": "^3.27.2",
- "use-font-face-observer": "^1.2.1"
+ "core-js": "^3.27.2"
},
"peerDependencies": {
"react": "^17.0.2 || ^18.2.0",
diff --git a/src/index.js b/src/index.js
index c6fb886..03cd494 100644
--- a/src/index.js
+++ b/src/index.js
@@ -10,14 +10,14 @@ root.render(
React Anagram Animation
Demo
-
+
-
+ }} fontToObserve="Open Sans" />
-
+
+
+
+
+
+
+
,
);
diff --git a/src/lib/components/Anagram.jsx b/src/lib/components/Anagram.jsx
index f06a5a7..22b4c53 100644
--- a/src/lib/components/Anagram.jsx
+++ b/src/lib/components/Anagram.jsx
@@ -21,7 +21,7 @@ export default function Anagram({ words, animationOptions }) {
newState[i] = {
...prevState[i],
...update,
- }
+ };
return newState;
});
@@ -46,7 +46,7 @@ export default function Anagram({ words, animationOptions }) {
// Find a matching dest character to execute the swap with
const destLetterIndex = [...words[1]].findIndex((destLetter, srcIndex) => {
return destLetter.toLowerCase() === letter.toLowerCase()
- && destLettersPairedByIndex[srcIndex] !== true;
+ && destLettersPairedByIndex[srcIndex] !== true;
});
destLettersPairedByIndex[destLetterIndex] = true; // mark this source paired/used
@@ -65,7 +65,6 @@ export default function Anagram({ words, animationOptions }) {
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: {
@@ -73,7 +72,6 @@ export default function Anagram({ words, animationOptions }) {
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);
@@ -114,7 +112,6 @@ export default function Anagram({ words, animationOptions }) {
{
[...words[0]].map((letter, i) => {
- // eslint-disable-next-line react/no-array-index-key
return
{letter};
})
}
@@ -122,14 +119,13 @@ export default function Anagram({ words, animationOptions }) {
{
[...words[1]].map((letter, i) => {
- // eslint-disable-next-line react/no-array-index-key
return {letter};
})
}
{
- swapAnimations.map((renderedLetter, i) => {
+ swapAnimations.map((renderedLetter) => {
const { id, letter, playing, src, dest } = renderedLetter;
const letterStyles = { transition: `left ${transitionDuration}ms ${timingFunction}, top ${transitionDuration}ms ${timingFunction}` };
diff --git a/src/lib/components/constants.js b/src/lib/components/constants.js
index a0569e4..63da884 100644
--- a/src/lib/components/constants.js
+++ b/src/lib/components/constants.js
@@ -2,12 +2,14 @@ export const DEFAULT_WORDS = ['React Anagram Animation', 'Magenta Raincoat Airma
/**
* @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 */
@@ -18,6 +20,6 @@ export const DEFAULT_ANIMATION_OPTIONS = {
randomReverseMax: 9000,
loopAnimation: 12000,
waitToStart: 0,
- transitionDuration: 2000,
+ transitionDuration: 1000,
timingFunction: 'ease-in-out',
};
diff --git a/src/lib/components/index.jsx b/src/lib/components/index.jsx
index 5695ffc..458aaff 100644
--- a/src/lib/components/index.jsx
+++ b/src/lib/components/index.jsx
@@ -1,27 +1,19 @@
import React from 'react';
-import useFontFaceObserver from 'use-font-face-observer';
+import useFonts from './useFonts';
import Anagram from './Anagram';
import { DEFAULT_ANIMATION_OPTIONS, DEFAULT_WORDS } from './constants';
import './index.css';
-/**
- * @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}
*/
-export default function Loader ({ words = DEFAULT_WORDS, animationOptions = {}, fontToObserve }) {
- const isFontLoaded = useFontFaceObserver(fontToObserve ? [fontToObserve] : []);
+export default function Loader({ words = DEFAULT_WORDS, animationOptions = {}, fontToObserve }) {
+ const isFontLoaded = useFonts(fontToObserve);
return isFontLoaded ?
{
+ // 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 "${fontName}"`))).then(() => {
+ setIsLoaded(true);
+ });
+ }, [fontNames]);
+
+ return isLoaded;
+};
diff --git a/yarn.lock b/yarn.lock
index abf67dc..a44a5c2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5347,11 +5347,6 @@ follow-redirects@^1.0.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379"
integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==
-fontfaceobserver@2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/fontfaceobserver/-/fontfaceobserver-2.1.0.tgz#e2705d293e2c585a6531c2a722905657317a2991"
- integrity sha512-ReOsO2F66jUa0jmv2nlM/s1MiutJx/srhAe2+TE8dJCMi02ZZOcCTxTCQFr3Yet+uODUtnr4Mewg+tNQ+4V1Ng==
-
for-each@^0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
@@ -8655,14 +8650,6 @@ react-scripts@5.0.1:
optionalDependencies:
fsevents "^2.3.2"
-react@17.0.2:
- version "17.0.2"
- resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
- integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
- dependencies:
- loose-envify "^1.1.0"
- object-assign "^4.1.1"
-
react@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
@@ -9971,14 +9958,6 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
-use-font-face-observer@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/use-font-face-observer/-/use-font-face-observer-1.2.1.tgz#2b33a389b82b48e2744f439abc1d5d6201fc099d"
- integrity sha512-5ieKTMvtUux0l7YoOEz842djfgMH3oVg+tO13E/kyS+gGRLDyfAMmRv0D3fzM7UdFag1kz+3AQIFLkkfEF3TUg==
- dependencies:
- fontfaceobserver "2.1.0"
- react "17.0.2"
-
util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"