react-text-swap-animation 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -65,26 +65,26 @@ API
65
65
 
66
66
  ### Props
67
67
 
68
- | Prop | Type | Default | Description |
69
- | :----------------- | :----- |:-------------------------------------------------| :------------------------------------------------------ |
70
- | `words` | array | `['Text Swap Animation', 'Antitoxin Swamp Tea']` | An array containing exactly 2 words which are an anagram of each other. |
71
- | `animationOptions` | object | `AnimationOptions` | Timing options for when to start, how fast to animate forwards, backwards, and when to loop (optional). |
72
- | `fontToObserve` | string | | The name of an embedded font to wait until loaded. If not specified, animation will loaded immediately (optional). |
68
+ | Prop | Type | Default | Description |
69
+ | :----------------- | :----- |:-------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------|
70
+ | `words` | array | `['Text Swap Animation', 'Antitoxin Swamp Tea']` | An array containing exactly 2 words which are an anagram of each other. |
71
+ | `animationOptions` | object | `AnimationOptions` | Timing options for when to start, how fast to animate forwards, backwards, and when to loop (optional). |
72
+ | `fontToObserve` | string | | The name of an embedded font to wait until loaded. If not specified, animation will be loaded immediately (optional). |
73
73
 
74
74
  #### AnimationOptions
75
75
 
76
76
  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.
77
77
 
78
- | Property | Type | Default | Description |
79
- | :------------------- | :----- | :------------ |:--------------------------------------------------------------------------------------------------------------------------------------|
80
- | `randomStartMin` | number | `0` | The minimum amount of time to randomly wait before starting to animate each letter. |
81
- | `randomStartMax` | number | `3000` | The maximum amount of time to randomly wait before starting to animate each letter. Should be `>= randomStartMin`. |
82
- | `randomReverseMin` | number | `6000` | The minimum amount of time to randomly wait before starting to animate each letter in reverse. |
83
- | `randomReverseMax` | number | `9000` | The maximum amount of time to randomly wait before starting to animate each letter in reverse. Should be `>= randomReverseMin`. |
84
- | `loopAnimation` | number | `12000` | The amount of time to wait before starting the next full loop of the animation. Should be `>= randomReverseMax + transitionDuration`. |
85
- | `waitToStart` | number | `0` | The amount of time to wait before beginning the animation on start up the first time. |
86
- | `transitionDuration` | number | `1000` | How long should it take for a letter to move to its next position. Should be `<= randomReverseMin - randomStartMax`. |
87
- | `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. |
78
+ | Property | Type | Default | Description |
79
+ | :------------------- | :----- | :------------ |:---------------------------------------------------------------------------------------------------------------------------------------|
80
+ | `randomStartMin` | number | `0` | The minimum amount of time to randomly wait before starting to animate each letter. |
81
+ | `randomStartMax` | number | `3000` | The maximum amount of time to randomly wait before starting to animate each letter. Should be `>= randomStartMin`. |
82
+ | `randomReverseMin` | number | `6000` | The minimum amount of time to randomly wait before starting to animate each letter in reverse. |
83
+ | `randomReverseMax` | number | `9000` | The maximum amount of time to randomly wait before starting to animate each letter in reverse. Should be `>= randomReverseMin`. |
84
+ | `loopAnimation` | number | `12000` | The amount of time to wait before starting the next full loop of the animation. Should be `>= randomReverseMax + transitionDuration`. |
85
+ | `waitToStart` | number | `0` | The amount of time to wait before beginning the animation on start up the first time. |
86
+ | `transitionDuration` | number | `1000` | How long should it take for a letter to move to its next position. Should be `<= randomReverseMin - randomStartMax`. |
87
+ | `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. |
88
88
 
89
89
  Run Locally
90
90
  ----
@@ -1,21 +1,24 @@
1
1
  "use strict";
2
2
 
3
- require("core-js/modules/es.symbol.description.js");
3
+ require("core-js/modules/es.iterator.filter.js");
4
+ require("core-js/modules/es.iterator.for-each.js");
4
5
  Object.defineProperty(exports, "__esModule", {
5
6
  value: true
6
7
  });
7
8
  exports.default = TextSwap;
9
+ require("core-js/modules/es.error.cause.js");
10
+ require("core-js/modules/es.array.push.js");
11
+ require("core-js/modules/es.iterator.constructor.js");
12
+ require("core-js/modules/es.iterator.map.js");
8
13
  require("core-js/modules/web.dom-collections.iterator.js");
9
- var _react = _interopRequireWildcard(require("react"));
14
+ var _react = require("react");
10
15
  var _utils = require("../utils");
11
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
12
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
13
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
14
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
15
- 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; }
16
- function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
17
- 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); }
18
- /**
16
+ var _jsxRuntime = require("react/jsx-runtime");
17
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
18
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
19
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
20
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
21
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /* eslint-disable react/no-array-index-key */ /**
19
22
  * Render and animate from one word to another word and back again.
20
23
  *
21
24
  * @param {[{string}]} words The 2 words to animate between.
@@ -170,56 +173,60 @@ function TextSwap(_ref) {
170
173
  animateFunc();
171
174
  }, waitToStart);
172
175
  }, [lettersRefs1, lettersRefs2, loopAnimation, updateAnimation, randomReverseMax, randomReverseMin, randomStartMax, randomStartMin, waitToStart, transitionDuration, timingFunction, words]);
173
- return /*#__PURE__*/_react.default.createElement("div", {
174
- className: "text-swap"
175
- }, /*#__PURE__*/_react.default.createElement("div", {
176
- className: "word word-1 hidden"
177
- }, [...words[0]].map((letter, i) => {
178
- return /*#__PURE__*/_react.default.createElement("span", {
179
- ref: lettersRefs1.current[i],
180
- className: "letter",
181
- key: "".concat(i).concat(letter)
182
- }, letter);
183
- })), /*#__PURE__*/_react.default.createElement("div", {
184
- className: "word word-2 hidden"
185
- }, [...words[1]].map((letter, i) => {
186
- return /*#__PURE__*/_react.default.createElement("span", {
187
- ref: lettersRefs2.current[i],
188
- className: "letter",
189
- key: "".concat(i).concat(letter)
190
- }, letter);
191
- })), /*#__PURE__*/_react.default.createElement("div", {
192
- className: "word word-animation"
193
- }, swapAnimations.map(renderedLetter => {
194
- const {
195
- id,
196
- letter,
197
- playing,
198
- disappear,
199
- src,
200
- dest
201
- } = renderedLetter;
202
- let letterStyles = {
203
- transition: "left ".concat(transitionDuration, "ms ").concat(timingFunction, ", top ").concat(transitionDuration, "ms ").concat(timingFunction)
204
- };
205
- if (playing) {
206
- const left = "".concat(dest.rect.x, "px");
207
- letterStyles = _objectSpread(_objectSpread({}, letterStyles), {}, {
208
- left
209
- });
210
- } else {
211
- const left = "".concat(src.rect.x, "px");
212
- letterStyles = _objectSpread(_objectSpread({}, letterStyles), {}, {
213
- left
214
- });
215
- }
216
- if (disappear) {
217
- letterStyles.opacity = 0;
218
- }
219
- return /*#__PURE__*/_react.default.createElement("span", {
220
- key: id,
221
- className: "letter",
222
- style: letterStyles
223
- }, letter);
224
- })));
176
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
177
+ className: "text-swap",
178
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
179
+ className: "word word-1 hidden",
180
+ children: [...words[0]].map((letter, i) => {
181
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
182
+ ref: lettersRefs1.current[i],
183
+ className: "letter",
184
+ children: letter
185
+ }, "".concat(i).concat(letter));
186
+ })
187
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
188
+ className: "word word-2 hidden",
189
+ children: [...words[1]].map((letter, i) => {
190
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
191
+ ref: lettersRefs2.current[i],
192
+ className: "letter",
193
+ children: letter
194
+ }, "".concat(i).concat(letter));
195
+ })
196
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
197
+ className: "word word-animation",
198
+ children: swapAnimations.map(renderedLetter => {
199
+ const {
200
+ id,
201
+ letter,
202
+ playing,
203
+ disappear,
204
+ src,
205
+ dest
206
+ } = renderedLetter;
207
+ let letterStyles = {
208
+ transition: "left ".concat(transitionDuration, "ms ").concat(timingFunction, ", top ").concat(transitionDuration, "ms ").concat(timingFunction)
209
+ };
210
+ if (playing) {
211
+ const left = "".concat(dest.rect.x, "px");
212
+ letterStyles = _objectSpread(_objectSpread({}, letterStyles), {}, {
213
+ left
214
+ });
215
+ } else {
216
+ const left = "".concat(src.rect.x, "px");
217
+ letterStyles = _objectSpread(_objectSpread({}, letterStyles), {}, {
218
+ left
219
+ });
220
+ }
221
+ if (disappear) {
222
+ letterStyles.opacity = 0;
223
+ }
224
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
225
+ className: "letter",
226
+ style: letterStyles,
227
+ children: letter
228
+ }, id);
229
+ })
230
+ })]
231
+ });
225
232
  }
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.DEFAULT_WORDS = exports.DEFAULT_ANIMATION_OPTIONS = void 0;
7
- const DEFAULT_WORDS = ['Text Swap Animation', 'Antitoxin Swamp Tea'];
7
+ const DEFAULT_WORDS = exports.DEFAULT_WORDS = ['Text Swap Animation', 'Antitoxin Swamp Tea'];
8
8
 
9
9
  /**
10
10
  * @typedef AnimationOptions Timing options for when to start, how fast to animate forwards, backwards, and when to loop.
@@ -19,8 +19,7 @@ const DEFAULT_WORDS = ['Text Swap Animation', 'Antitoxin Swamp Tea'];
19
19
  */
20
20
 
21
21
  /** @type AnimationOptions */
22
- exports.DEFAULT_WORDS = DEFAULT_WORDS;
23
- const DEFAULT_ANIMATION_OPTIONS = {
22
+ const DEFAULT_ANIMATION_OPTIONS = exports.DEFAULT_ANIMATION_OPTIONS = {
24
23
  randomStartMin: 0,
25
24
  randomStartMax: 3000,
26
25
  randomReverseMin: 6000,
@@ -29,5 +28,4 @@ const DEFAULT_ANIMATION_OPTIONS = {
29
28
  waitToStart: 0,
30
29
  transitionDuration: 1000,
31
30
  timingFunction: 'ease-in-out'
32
- };
33
- exports.DEFAULT_ANIMATION_OPTIONS = DEFAULT_ANIMATION_OPTIONS;
31
+ };
@@ -1,32 +1,34 @@
1
- .text-swap {
2
- color: #fff;
3
- flex: 0 0 auto;
4
- align-self: center;
5
- width: 100%;
6
- height: 100%;
7
- margin: 0 auto;
8
- text-align: left;
9
- text-transform: uppercase;
10
- display: flex;
11
- flex-direction: column;
12
- padding: 0;
13
- position: relative; }
14
-
15
- .text-swap .word {
16
- position: relative; }
17
-
18
- .text-swap .word.hidden {
19
- position: absolute;
20
- visibility: hidden;
21
- z-index: -9000; }
22
-
23
- .text-swap .word .letter {
24
- white-space: pre;
25
- z-index: 10;
26
- display: inline-block; }
27
-
28
- .text-swap .word-animation .letter {
29
- z-index: 10;
30
- position: absolute;
31
- /*transition: all, 2s, cubic-bezier(0.1, 0.7, 1.0, 0.1), 2s;*/
32
- transition: all, 2s, ease-in-out, 2s; }
1
+ .text-swap {
2
+ color: #fff;
3
+ flex: 0 0 auto;
4
+ align-self: center;
5
+ width: 100%;
6
+ height: 100%;
7
+ margin: 0 auto;
8
+ text-align: left;
9
+ text-transform: uppercase;
10
+ display: flex;
11
+ flex-direction: column;
12
+ padding: 0;
13
+ position: relative;
14
+ }
15
+ .text-swap .word {
16
+ position: relative;
17
+ }
18
+ .text-swap .word.hidden {
19
+ position: absolute;
20
+ visibility: hidden;
21
+ z-index: -9000;
22
+ }
23
+ .text-swap .word .letter {
24
+ white-space: pre;
25
+ z-index: 10;
26
+ display: inline-block;
27
+ }
28
+ .text-swap .word-animation .letter {
29
+ z-index: 10;
30
+ position: absolute;
31
+ transition: left 2s ease-in-out, top 2s ease-in-out;
32
+ }
33
+
34
+ /*# sourceMappingURL=index.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sourceRoot":"","sources":["index.scss"],"names":[],"mappings":"AAAA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAEA;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;;AAKJ;EACI;EACA;EACA","file":"index.css"}
@@ -1,22 +1,25 @@
1
1
  "use strict";
2
2
 
3
+ require("core-js/modules/es.array.push.js");
4
+ require("core-js/modules/es.iterator.constructor.js");
5
+ require("core-js/modules/es.iterator.filter.js");
6
+ require("core-js/modules/es.iterator.for-each.js");
3
7
  Object.defineProperty(exports, "__esModule", {
4
8
  value: true
5
9
  });
6
10
  exports.default = Loader;
7
- require("core-js/modules/es.symbol.description.js");
8
- var _react = _interopRequireDefault(require("react"));
11
+ require("core-js/modules/es.error.cause.js");
9
12
  var _useFonts = _interopRequireDefault(require("./useFonts"));
10
13
  var _TextSwap = _interopRequireDefault(require("./TextSwap"));
11
14
  var _constants = require("./constants");
12
15
  require("./index.css");
13
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
15
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
16
- 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; }
17
- function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
18
- 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); }
19
- /**
16
+ var _jsxRuntime = require("react/jsx-runtime");
17
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
18
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
19
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
20
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
21
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
22
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /**
20
23
  * Render and animate from one word to another word and back again.
21
24
  * @param {[string]} [words] The 2 words to animate between.
22
25
  * @param {AnimationOptions} [animationOptions] Timing options for when to start, how fast to animate forwards, backwards, and when to loop.
@@ -36,7 +39,7 @@ function Loader(_ref) {
36
39
  const maxLength = Math.max(word1.length, word2.length);
37
40
  word1 = word1.padEnd(maxLength, ' ');
38
41
  word2 = word2.padEnd(maxLength, ' ');
39
- return isFontLoaded ? /*#__PURE__*/_react.default.createElement(_TextSwap.default, {
42
+ return isFontLoaded ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_TextSwap.default, {
40
43
  words: [word1, word2],
41
44
  animationOptions: animOptions
42
45
  }) : null;
@@ -4,8 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = useFonts;
7
- require("core-js/modules/web.dom-collections.iterator.js");
8
7
  require("core-js/modules/es.promise.js");
8
+ require("core-js/modules/web.dom-collections.iterator.js");
9
9
  var _react = require("react");
10
10
  function useFonts() {
11
11
  for (var _len = arguments.length, fontNames = new Array(_len), _key = 0; _key < _len; _key++) {
package/dist/index.js CHANGED
@@ -5,6 +5,5 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _index = _interopRequireDefault(require("./components/index"));
8
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
- var _default = _index.default;
10
- exports.default = _default;
8
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
+ var _default = exports.default = _index.default;
package/dist/utils.js CHANGED
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.randomMinMax = randomMinMax;
7
7
  exports.uuidv4 = uuidv4;
8
8
  require("core-js/modules/es.regexp.exec.js");
9
- require("core-js/modules/es.string.replace.js");
10
9
  require("core-js/modules/es.regexp.to-string.js");
10
+ require("core-js/modules/es.string.replace.js");
11
11
  /**
12
12
  * Get a random number between `min` and `max`
13
13
  * @param {number} min The minimum number you want to include in the random output
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "react-text-swap-animation",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "author": "Scott Canoni",
5
5
  "description": "A React component to use CSS animations to swap letters in 2 words. The text is animated in position after calculating initial and final positions of each letter. Words which are anagrams will animate well, but you can use any words or phrases.",
6
6
  "license": "WTFPL",
7
7
  "main": "dist/index.js",
8
+ "files": [
9
+ "dist"
10
+ ],
8
11
  "private": false,
9
12
  "scripts": {
10
- "analyze": "source-map-explorer 'build/static/js/*.js'",
11
- "start-js": "react-scripts start",
12
- "start": "npm-run-all -p watch-css start-js",
13
- "build": "del /Q dist\\* && NODE_ENV=production babel src/lib --out-dir dist --copy-files",
14
- "build-fresh": "NODE_ENV=production babel src/lib --out-dir dist --copy-files",
15
- "build-css": "sass src/:src/",
16
- "watch-css": "sass --watch src/:src/",
17
- "eject": "react-scripts eject"
13
+ "start": "vite",
14
+ "build-demo": "vite build --outDir demo-build",
15
+ "preview": "vite preview --outDir demo-build",
16
+ "build": "rimraf dist && cross-env NODE_ENV=production babel src/lib --out-dir dist --copy-files",
17
+ "build-css": "sass src/:src/"
18
18
  },
19
19
  "repository": {
20
20
  "type": "git",
@@ -29,26 +29,30 @@
29
29
  "rearrange"
30
30
  ],
31
31
  "dependencies": {
32
- "core-js": "^3.18.3"
32
+ "core-js": "^3.49.0"
33
33
  },
34
34
  "peerDependencies": {
35
- "react": "^17.0.2 || ^18.2.0",
36
- "react-dom": "^17.0.2 || ^18.2.0"
35
+ "react": "^17.0.0 || ^18.0.0 || >=19.0.0",
36
+ "react-dom": "^17.0.0 || ^18.0.0 || >=19.0.0"
37
37
  },
38
38
  "devDependencies": {
39
- "@babel/cli": "^7.20.7",
40
- "@babel/core": "^7.20.12",
41
- "@babel/polyfill": "^7.12.1",
42
- "@babel/preset-env": "^7.15.6",
43
- "@babel/preset-react": "^7.14.5",
44
- "npm-run-all": "^4.1.5",
45
- "react": "^17.0.2",
46
- "react-dom": "^17.0.2",
47
- "react-scripts": "4.0.3",
48
- "sass": "^1.57.1"
49
- },
50
- "eslintConfig": {
51
- "extends": "react-app"
39
+ "@babel/cli": "^7.28.6",
40
+ "@babel/core": "^7.29.0",
41
+ "@babel/eslint-parser": "^7.28.6",
42
+ "@babel/preset-env": "^7.29.2",
43
+ "@babel/preset-react": "^7.28.5",
44
+ "@vitejs/plugin-react": "^6.0.1",
45
+ "cross-env": "^10.1.0",
46
+ "eslint": "^8.57.1",
47
+ "eslint-plugin-import": "^2.32.0",
48
+ "eslint-plugin-jsx-a11y": "^6.10.2",
49
+ "eslint-plugin-react": "^7.37.5",
50
+ "eslint-plugin-react-hooks": "^4.6.2",
51
+ "react": "^19.2.4",
52
+ "react-dom": "^19.2.4",
53
+ "rimraf": "^6.1.3",
54
+ "sass": "^1.98.0",
55
+ "vite": "^8.0.3"
52
56
  },
53
57
  "browserslist": {
54
58
  "production": [
package/.eslintrc.js DELETED
@@ -1,74 +0,0 @@
1
- module.exports = {
2
- extends: [
3
- 'react-app',
4
- 'react-app/jest',
5
- ],
6
- rules: {
7
- indent: ['warn', 4],
8
- 'react/jsx-indent': ['warn', 4],
9
- 'react/jsx-indent-props': ['warn', 4],
10
- quotes: [0, 'double', { avoidEscape: true }],
11
- 'quote-props': ['error', 'as-needed'],
12
- 'jsx-quotes': [2, 'prefer-double'],
13
- 'no-undef': 2,
14
- 'id-length': 0,
15
- 'max-len': 0,
16
- 'brace-style': [
17
- 1,
18
- 'stroustrup',
19
- { allowSingleLine: true },
20
- ],
21
- curly: 2,
22
- 'no-use-before-define': [
23
- 1,
24
- 'nofunc',
25
- ],
26
- 'no-unused-vars': [
27
- 1,
28
- {
29
- args: 'none',
30
- ignoreRestSiblings: true,
31
- },
32
- ],
33
- 'arrow-body-style': 0,
34
- 'no-unused-expressions': [
35
- 2,
36
- { allowShortCircuit: true },
37
- ],
38
- 'object-curly-spacing': ['warn', 'always', { objectsInObjects: true }],
39
- 'object-curly-newline': ['warn', { multiline: true }],
40
- 'prefer-const': 'warn',
41
- 'no-restricted-syntax': [
42
- 1,
43
- 'WithStatement',
44
- 'DebuggerStatement',
45
- ],
46
- 'no-underscore-dangle': 0,
47
- 'react/jsx-boolean-value': 0,
48
- 'react/jsx-first-prop-new-line': 0,
49
- 'react/jsx-no-bind': 0,
50
- 'react/no-did-mount-set-state': 0,
51
- 'react/prefer-stateless-function': 0,
52
- 'react/jsx-one-expression-per-line': [0],
53
- // Allow jsx tags inside .js files.
54
- 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
55
- // Disable props spreading (<App {...props} />) warning.
56
- 'react/jsx-props-no-spreading': 0,
57
- // Throw warning instead of error when using array index as a key.
58
- 'react/no-array-index-key': 1,
59
- // Allow using (props) => <Component /> and ({propName}) => <Component /> syntax.
60
- 'react/destructuring-assignment': 'off',
61
- // Disable <Fragment> => <> replacement. Feel free to change
62
- 'react/jsx-fragments': 'off',
63
- // Allow modules with named exports only.
64
- 'import/prefer-default-export': 0,
65
- // Throw warning when <a href="#"> or <a href="javascript:void(0)"> are used. Use <button> instead.
66
- 'jsx-a11y/anchor-is-valid': ['off', { aspects: ['invalidHref'] }],
67
- },
68
- // DeprecationWarning: The 'ecmaFeatures' config file property is deprecated and has no effect. (found in ".eslintrc.js")
69
- // ecmaFeatures: {
70
- // jsx: true,
71
- // modules: true,
72
- // },
73
- parser: 'babel-eslint',
74
- };
@@ -1,16 +0,0 @@
1
- name: Greetings
2
-
3
- on: [pull_request, issues]
4
-
5
- jobs:
6
- greeting:
7
- runs-on: ubuntu-latest
8
- permissions:
9
- issues: write
10
- pull-requests: write
11
- steps:
12
- - uses: actions/first-interaction@v1
13
- with:
14
- repo-token: ${{ secrets.GITHUB_TOKEN }}
15
- issue-message: 'Hey, thanks for raising this issue!'
16
- pr-message: 'You are so AWESOME for chipping in and helping out. Thanks! Keep up the GOOD WORK!'
@@ -1,46 +0,0 @@
1
- # This is a basic workflow to help you get started with Actions
2
-
3
- name: CI
4
-
5
- # Controls when the workflow will run
6
- on:
7
- # Triggers the workflow on push or pull request events but only for the main branch
8
- push:
9
- branches: [ main ]
10
- pull_request:
11
- branches: [ main ]
12
-
13
- # Allows you to run this workflow manually from the Actions tab
14
- workflow_dispatch:
15
-
16
- # A workflow run is made up of one or more jobs that can run sequentially or in parallel
17
- jobs:
18
- # This workflow contains a single job called "build"
19
- build:
20
- # The type of runner that the job will run on
21
- runs-on: ubuntu-latest
22
-
23
- strategy:
24
- matrix:
25
- node-version: [ 14.x, 16.x, 18.x ]
26
- # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
27
-
28
- # Steps represent a sequence of tasks that will be executed as part of the job
29
- steps:
30
- - uses: actions/checkout@v3
31
- - name: Use Node.js ${{ matrix.node-version }}
32
- uses: actions/setup-node@v3
33
- with:
34
- node-version: ${{ matrix.node-version }}
35
- cache: 'npm'
36
- # Runs a single command using the runners shell
37
- - name: Run a one-line script
38
- run: echo Building now...
39
-
40
- # - name: Install python2
41
- # run: apt update && DEBIAN_FRONTEND=noninteractive apt install -y python2 make g++
42
- # - name: Test python2
43
- # run: python2 --version
44
- # - run: npm install sass node-sass@4.14.1
45
- - run: npm i
46
- - run: npm run build-fresh --if-present
package/babel.config.json DELETED
@@ -1,18 +0,0 @@
1
- {
2
- "presets": [
3
- [
4
- "@babel/env",
5
- {
6
- "targets": {
7
- "edge": "17",
8
- "firefox": "60",
9
- "chrome": "67",
10
- "safari": "11.1"
11
- },
12
- "useBuiltIns": "usage",
13
- "corejs": "3.6.5"
14
- }
15
- ],
16
- "@babel/preset-react"
17
- ]
18
- }
@@ -1,156 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = Anagram;
7
-
8
- require("core-js/modules/web.dom-collections.iterator.js");
9
-
10
- var _react = _interopRequireWildcard(require("react"));
11
-
12
- var _utils = require("../utils");
13
-
14
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
15
-
16
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
17
-
18
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
19
-
20
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
21
-
22
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
23
-
24
- /**
25
- * Render and animate from one word to another word and back again.
26
- *
27
- * @param {[{string}]} words The 2 words to animate between.
28
- * @param {AnimationOptions} animationOptions Timing options for when to start, how fast forward/backwards, and when to loop.
29
- * @returns {JSX.Element}
30
- */
31
- function Anagram(_ref) {
32
- let {
33
- words,
34
- animationOptions
35
- } = _ref;
36
- const lettersRefs1 = (0, _react.useRef)([...words[0]].map(() => /*#__PURE__*/(0, _react.createRef)()));
37
- const lettersRefs2 = (0, _react.useRef)([...words[1]].map(() => /*#__PURE__*/(0, _react.createRef)()));
38
- const [swapAnimations, setSwapAnimations] = (0, _react.useState)({});
39
- const playAnimation = (0, _react.useCallback)(function (i) {
40
- let playing = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
41
- setSwapAnimations(prevState => {
42
- return _objectSpread(_objectSpread({}, prevState), {}, {
43
- [i]: _objectSpread(_objectSpread({}, prevState[i]), {}, {
44
- playing
45
- })
46
- });
47
- });
48
- }, [setSwapAnimations]);
49
- const {
50
- randomStartMin,
51
- randomStartMax,
52
- randomReverseMin,
53
- randomReverseMax,
54
- loopAnimation,
55
- waitToStart
56
- } = animationOptions;
57
- (0, _react.useEffect)(() => {
58
- const swaps = [];
59
- const destLettersPairedByIndex = [];
60
- [...words[0]].forEach((letter, i) => {
61
- // Find a matching dest character to execute the swap with
62
- const destLetterIndex = [...words[1]].findIndex((destLetter, srcIndex) => {
63
- return destLetter.toLowerCase() === letter.toLowerCase() && destLettersPairedByIndex[srcIndex] !== true;
64
- });
65
- destLettersPairedByIndex[destLetterIndex] = true; // mark this source paired/used
66
-
67
- if (destLetterIndex === -1) {
68
- throw new Error("Not sure how to animate since all source letters were paired already, disappear maybe?");
69
- } // If the text wraps then the offset left isn't correct.
70
-
71
-
72
- const swap = {
73
- src: {
74
- letter,
75
- element: lettersRefs1.current[i].current,
76
- offsetLeft: lettersRefs1.current[i].current.offsetLeft,
77
- offsetTop: lettersRefs1.current[i].current.offsetTop // rect: lettersRefs1.current[i].current.getBoundingClientRect(),
78
-
79
- },
80
- dest: {
81
- letter: words[1][destLetterIndex],
82
- element: lettersRefs2.current[destLetterIndex].current,
83
- offsetLeft: lettersRefs2.current[destLetterIndex].current.offsetLeft,
84
- offsetTop: lettersRefs2.current[destLetterIndex].current.offsetTop // rect: lettersRefs2.current[destLetterIndex].current.getBoundingClientRect(),
85
-
86
- }
87
- };
88
- swaps.push(swap);
89
- });
90
- setSwapAnimations(swaps);
91
-
92
- const animateFunc = () => {
93
- swaps.forEach((swap, i) => {
94
- // Animate each character towards the destination
95
- setTimeout(() => {
96
- playAnimation(i);
97
- }, (0, _utils.randomMinMax)(randomStartMin, randomStartMax)); // Animate each character back to their original location
98
-
99
- setTimeout(() => {
100
- playAnimation(i, false);
101
- }, (0, _utils.randomMinMax)(randomReverseMin, randomReverseMax));
102
- }); // Repeat forever
103
-
104
- setTimeout(() => {
105
- animateFunc();
106
- }, loopAnimation);
107
- }; // Start the process
108
-
109
-
110
- setTimeout(() => {
111
- animateFunc();
112
- }, waitToStart);
113
- }, [lettersRefs1, lettersRefs2, loopAnimation, playAnimation, randomReverseMax, randomReverseMin, randomStartMax, randomStartMin, waitToStart, words]);
114
- return /*#__PURE__*/_react.default.createElement("div", {
115
- className: "anagram-swap"
116
- }, /*#__PURE__*/_react.default.createElement("div", {
117
- className: "word word-1 hidden"
118
- }, [...words[0]].map((letter, i) => {
119
- return /*#__PURE__*/_react.default.createElement("span", {
120
- ref: lettersRefs1.current[i],
121
- className: "letter",
122
- key: "".concat(i).concat(letter)
123
- }, letter);
124
- })), /*#__PURE__*/_react.default.createElement("div", {
125
- className: "word word-2 hidden"
126
- }, [...words[1]].map((letter, i) => {
127
- return /*#__PURE__*/_react.default.createElement("span", {
128
- ref: lettersRefs2.current[i],
129
- className: "letter",
130
- key: "".concat(i).concat(letter)
131
- }, letter);
132
- })), /*#__PURE__*/_react.default.createElement("div", {
133
- className: "word word-animation"
134
- }, [...words[0]].map((letter, i) => {
135
- let letterStyles = {};
136
- const swap = swapAnimations[i];
137
-
138
- if (swap && swap.playing) {
139
- const left = "".concat(swap.dest.offsetLeft - swap.src.offsetLeft, "px");
140
- const top = "".concat(swap.dest.offsetTop - swap.src.offsetTop, "px"); // Trying to fix issue with wrapped text
141
- // const left = `${swap.dest.rect.x - swap.src.rect.x}px`;
142
- // const top = `${swap.dest.rect.y - swap.src.rect.y}px`;
143
-
144
- letterStyles = {
145
- left,
146
- top
147
- };
148
- }
149
-
150
- return /*#__PURE__*/_react.default.createElement("span", {
151
- key: "".concat(i).concat(letter),
152
- className: "letter",
153
- style: letterStyles
154
- }, letter);
155
- })));
156
- }
package/public/index.html DELETED
@@ -1,19 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <meta name="theme-color" content="#000000" />
8
- <meta name="description"
9
- content="A React component to use CSS animations to swap letters in 2 words. The text is animated in position after calculating initial and final positions of each letter. Words which are anagrams will animate well, but you can use any words or phrases." />
10
- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
11
- <title>React Text Swap Animation</title>
12
- <link rel="preconnect" href="https://fonts.googleapis.com">
13
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
14
- <link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&display=swap" rel="stylesheet">
15
- </head>
16
- <body>
17
- <div id="root"></div>
18
- </body>
19
- </html>
package/src/App.css DELETED
@@ -1,12 +0,0 @@
1
- body {
2
- background-color: #1c3d65;
3
- color: #fff;
4
- font-family: 'Open Sans', sans-serif;
5
-
6
- font-size: 42px;
7
- font-weight: bold;
8
- }
9
-
10
- .text-swap .word {
11
- white-space: pre;
12
- }
package/src/index.js DELETED
@@ -1,44 +0,0 @@
1
- import React from 'react';
2
- import ReactDOM from 'react-dom';
3
- import TextSwap from './lib/components';
4
- import './App.css';
5
-
6
- ReactDOM.render(
7
- <React.StrictMode>
8
- <div>
9
- <h1>React Text Swap Animation</h1>
10
- <h2>Demo</h2>
11
-
12
- <TextSwap fontToObserve="Open Sans" />
13
-
14
- <br />
15
- <br />
16
-
17
- <TextSwap fontToObserve="Open Sans" words={['a witty saying', 'proves nothing']} />
18
-
19
- <br />
20
- <br />
21
-
22
- <TextSwap fontToObserve="Open Sans" words={['don\'t be sad it\'s over', 'be happy that it happened']} />
23
-
24
- <br />
25
- <br />
26
-
27
- <TextSwap fontToObserve="Open Sans" words={['debit card', 'bad credit']} />
28
- <br />
29
- <br />
30
-
31
- <TextSwap fontToObserve="Open Sans" words={['debit card', 'bad credit']} animationOptions={{
32
- randomStartMin: 0,
33
- randomStartMax: 3000,
34
- randomReverseMin: 12000,
35
- randomReverseMax: 12000,
36
- loopAnimation: 20000,
37
- waitToStart: 0,
38
- transitionDuration: 4000,
39
- timingFunction: 'cubic-bezier(0.2,-2,0.8,2)'
40
- }} />
41
- </div>
42
- </React.StrictMode>,
43
- document.getElementById('root'),
44
- );
@@ -1,201 +0,0 @@
1
- /* eslint-disable react/no-array-index-key */
2
- import React, { createRef, useCallback, useEffect, useRef, useState } from 'react';
3
- import { randomMinMax, uuidv4 } from '../utils';
4
-
5
- /**
6
- * Render and animate from one word to another word and back again.
7
- *
8
- * @param {[{string}]} words The 2 words to animate between.
9
- * @param {AnimationOptions} animationOptions Timing options for when to start, how fast forward/backwards, and when to loop.
10
- * @returns {JSX.Element}
11
- */
12
- export default function TextSwap({ words, animationOptions }) {
13
- const [swapAnimations, setAnimations] = useState([]);
14
- const lettersRefs1 = useRef([...words[0]].map(() => createRef()));
15
- const lettersRefs2 = useRef([...words[1]].map(() => createRef()));
16
- const updateAnimation = useCallback((i, update = {}) => {
17
- setAnimations((prevState) => {
18
- const newState = [
19
- ...prevState,
20
- ];
21
- newState[i] = {
22
- ...prevState[i],
23
- ...update,
24
- };
25
-
26
- return newState;
27
- });
28
- }, [setAnimations]);
29
-
30
- const {
31
- randomStartMin,
32
- randomStartMax,
33
- randomReverseMin,
34
- randomReverseMax,
35
- loopAnimation,
36
- waitToStart,
37
- transitionDuration,
38
- timingFunction,
39
- } = animationOptions;
40
-
41
- useEffect(() => {
42
- const swaps = [];
43
- const destLettersPairedByIndex = [];
44
-
45
- [...words[0]].forEach((letter, i) => {
46
- // Find a matching destination character to execute the swap with
47
- let destLetterIndex = [...words[1]].findIndex((destLetter, srcIndex) => {
48
- return destLetter.toLowerCase() === letter.toLowerCase()
49
- && destLettersPairedByIndex[srcIndex] !== true;
50
- });
51
-
52
- // If no matching character
53
- if (destLetterIndex === -1) {
54
- // Find a space to swap with
55
- destLetterIndex = [...words[1]].findIndex((destLetter, srcIndex) => {
56
- return destLetter === ' ' && destLettersPairedByIndex[srcIndex] !== true;
57
- });
58
-
59
- // If there was no space, find first non-used space
60
- if (destLetterIndex === -1) {
61
- destLetterIndex = [...words[1]].findIndex((destLetter, srcIndex) => {
62
- return destLettersPairedByIndex[srcIndex] !== true;
63
- });
64
- }
65
- }
66
-
67
- if (destLetterIndex === -1) {
68
- throw new Error(`Not sure how to animate since all source letters were paired already, disappear maybe?`);
69
- }
70
-
71
- destLettersPairedByIndex[destLetterIndex] = true; // mark this source paired/used
72
-
73
- // If the text wraps then the offset left isn't correct.
74
- const swap = {
75
- id: uuidv4(), // for a unique key
76
- letter, // the displayed letter
77
- playing: false, // if this letter is animating to the destination
78
- disappear: false, // if this letter should disappear (temporarily)
79
- // the source location, starting place and letter
80
- src: {
81
- letter: words[0][i],
82
- element: lettersRefs1.current[i].current,
83
- offsetLeft: lettersRefs1.current[i].current.offsetLeft,
84
- offsetTop: lettersRefs1.current[i].current.offsetTop,
85
- rect: lettersRefs1.current[i].current.getBoundingClientRect(),
86
- },
87
- // the destination location and letter
88
- dest: {
89
- letter: words[1][destLetterIndex],
90
- element: lettersRefs2.current[destLetterIndex].current,
91
- offsetLeft: lettersRefs2.current[destLetterIndex].current.offsetLeft,
92
- offsetTop: lettersRefs2.current[destLetterIndex].current.offsetTop,
93
- rect: lettersRefs2.current[destLetterIndex].current.getBoundingClientRect(),
94
- },
95
- };
96
- swaps.push(swap);
97
- });
98
-
99
- setAnimations(swaps);
100
-
101
- const animateFunc = () => {
102
- swaps.forEach((swap, i) => {
103
- // Animate each character towards the destination
104
- const forwardStartTime = randomMinMax(randomStartMin, randomStartMax);
105
- setTimeout(() => {
106
- updateAnimation(i, { playing: true, disappear: false });
107
- if (swap.src.letter !== ' ' && swap.dest.letter === ' ') {
108
- updateAnimation(i, { disappear: true });
109
- }
110
- }, forwardStartTime);
111
-
112
- // Halfway towards the destination, switch to the destination letter
113
- setTimeout(() => {
114
- if (swap.src.letter !== ' ' && swap.dest.letter === ' ') {
115
- // do nothing
116
- }
117
- else {
118
- updateAnimation(i, { letter: swap.dest.letter });
119
- }
120
- }, forwardStartTime + 500);
121
-
122
-
123
- // Animate each character back to their original location
124
- const reverseStartTime = randomMinMax(randomReverseMin, randomReverseMax);
125
- setTimeout(() => {
126
- updateAnimation(i, { playing: false, disappear: false });
127
- if (swap.dest.letter !== ' ' && swap.src.letter === ' ') {
128
- updateAnimation(i, { disappear: true });
129
- }
130
- }, reverseStartTime);
131
-
132
- // Half way back to the initial location, switch to the initial letter
133
- setTimeout(() => {
134
- if (swap.dest.letter !== ' ' && swap.src.letter === ' ') {
135
- // do nothing
136
- }
137
- else {
138
- updateAnimation(i, { letter: swap.src.letter });
139
- }
140
- }, reverseStartTime + 500);
141
- });
142
-
143
- // Repeat forever
144
- setTimeout(() => {
145
- animateFunc();
146
- }, loopAnimation);
147
- };
148
-
149
- // Start the process
150
- setTimeout(() => {
151
- animateFunc();
152
- }, waitToStart);
153
-
154
- }, [lettersRefs1, lettersRefs2, loopAnimation, updateAnimation, randomReverseMax, randomReverseMin, randomStartMax, randomStartMin, waitToStart, transitionDuration, timingFunction, words]);
155
-
156
- return (
157
- <div className="text-swap">
158
- <div className="word word-1 hidden">
159
- {
160
- [...words[0]].map((letter, i) => {
161
- return <span ref={lettersRefs1.current[i]} className="letter" key={`${i}${letter}`}>{letter}</span>;
162
- })
163
- }
164
- </div>
165
- <div className="word word-2 hidden">
166
- {
167
- [...words[1]].map((letter, i) => {
168
- return <span ref={lettersRefs2.current[i]} className="letter" key={`${i}${letter}`}>{letter}</span>;
169
- })
170
- }
171
- </div>
172
- <div className="word word-animation">
173
- {
174
- swapAnimations.map((renderedLetter) => {
175
- const { id, letter, playing, disappear, src, dest } = renderedLetter;
176
-
177
- let letterStyles = { transition: `left ${transitionDuration}ms ${timingFunction}, top ${transitionDuration}ms ${timingFunction}` };
178
- if (playing) {
179
- const left = `${dest.rect.x}px`;
180
- letterStyles = { ...letterStyles, left };
181
- }
182
- else {
183
- const left = `${src.rect.x}px`;
184
- letterStyles = { ...letterStyles, left };
185
- }
186
-
187
- if (disappear) {
188
- letterStyles.opacity = 0;
189
- }
190
-
191
- return (
192
- <span key={id} className="letter" style={letterStyles}>
193
- {letter}
194
- </span>
195
- );
196
- })
197
- }
198
- </div>
199
- </div>
200
- );
201
- }
@@ -1,25 +0,0 @@
1
- export const DEFAULT_WORDS = ['Text Swap Animation', 'Antitoxin Swamp Tea'];
2
-
3
- /**
4
- * @typedef AnimationOptions Timing options for when to start, how fast to animate forwards, backwards, and when to loop.
5
- * @property {number} randomStartMin The minimum amount of time to randomly wait before starting to animate each letter.
6
- * @property {number} randomStartMax The maximum amount of time to randomly wait before starting to animate each letter. Should be `>= randomStartMin`.
7
- * @property {number} randomReverseMin The minimum amount of time to randomly wait before starting to animate each letter in reverse.
8
- * @property {number} randomReverseMax The maximum amount of time to randomly wait before starting to animate each letter in reverse. Should be `>= randomReverseMin`.
9
- * @property {number} loopAnimation The amount of time to wait before starting the next full loop of the animation. Should be `>= randomReverseMax + transitionDuration`.
10
- * @property {number} waitToStart The amount of time to wait before beginning the animation on start up the first time.
11
- * @property {number} transitionDuration How long should it take for a letter to move to its next position. Should be `<= randomReverseMin - randomStartMax`.
12
- * @property {string} timingFunction What [timing function](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function) should be used for the animation.
13
- */
14
-
15
- /** @type AnimationOptions */
16
- export const DEFAULT_ANIMATION_OPTIONS = {
17
- randomStartMin: 0,
18
- randomStartMax: 3000,
19
- randomReverseMin: 6000,
20
- randomReverseMax: 9000,
21
- loopAnimation: 12000,
22
- waitToStart: 0,
23
- transitionDuration: 1000,
24
- timingFunction: 'ease-in-out',
25
- };
@@ -1,32 +0,0 @@
1
- .text-swap {
2
- color: #fff;
3
- flex: 0 0 auto;
4
- align-self: center;
5
- width: 100%;
6
- height: 100%;
7
- margin: 0 auto;
8
- text-align: left;
9
- text-transform: uppercase;
10
- display: flex;
11
- flex-direction: column;
12
- padding: 0;
13
- position: relative; }
14
-
15
- .text-swap .word {
16
- position: relative; }
17
-
18
- .text-swap .word.hidden {
19
- position: absolute;
20
- visibility: hidden;
21
- z-index: -9000; }
22
-
23
- .text-swap .word .letter {
24
- white-space: pre;
25
- z-index: 10;
26
- display: inline-block; }
27
-
28
- .text-swap .word-animation .letter {
29
- z-index: 10;
30
- position: absolute;
31
- /*transition: all, 2s, cubic-bezier(0.1, 0.7, 1.0, 0.1), 2s;*/
32
- transition: all, 2s, ease-in-out, 2s; }
@@ -1,29 +0,0 @@
1
- import React from 'react';
2
- import useFonts from './useFonts';
3
- import TextSwap from './TextSwap';
4
- import { DEFAULT_ANIMATION_OPTIONS, DEFAULT_WORDS } from './constants';
5
-
6
- import './index.css';
7
-
8
- /**
9
- * Render and animate from one word to another word and back again.
10
- * @param {[string]} [words] The 2 words to animate between.
11
- * @param {AnimationOptions} [animationOptions] Timing options for when to start, how fast to animate forwards, backwards, and when to loop.
12
- * @param {string} [fontToObserve] A description of an embedded font to observe and wait until loaded.
13
- * @returns {JSX.Element|null}
14
- */
15
- export default function Loader({ words = DEFAULT_WORDS, animationOptions = {}, fontToObserve }) {
16
- const isFontLoaded = useFonts(fontToObserve);
17
- const animOptions = {
18
- ...DEFAULT_ANIMATION_OPTIONS,
19
- ...animationOptions,
20
- };
21
-
22
- let word1 = words[0];
23
- let word2 = words[1];
24
- const maxLength = Math.max(word1.length, word2.length);
25
- word1 = word1.padEnd(maxLength, ' ');
26
- word2 = word2.padEnd(maxLength, ' ');
27
-
28
- return isFontLoaded ? <TextSwap words={[word1, word2]} animationOptions={animOptions} /> : null;
29
- }
@@ -1,38 +0,0 @@
1
- .text-swap {
2
- color: #fff;
3
- flex: 0 0 auto;
4
- align-self: center;
5
- width: 100%;
6
- height: 100%;
7
- margin: 0 auto;
8
- text-align: left;
9
- text-transform: uppercase;
10
- display: flex;
11
- flex-direction: column;
12
- padding: 0;
13
- position: relative;
14
-
15
- .word {
16
- position: relative;
17
-
18
- &.hidden {
19
- position: absolute;
20
- visibility: hidden;
21
- z-index: -9000;
22
- }
23
-
24
- .letter {
25
- white-space: pre;
26
- z-index: 10;
27
- display: inline-block;
28
- }
29
- }
30
-
31
- .word-animation {
32
- .letter {
33
- z-index: 10;
34
- position: absolute;
35
- transition: left 2s ease-in-out, top 2s ease-in-out;
36
- }
37
- }
38
- }
@@ -1,22 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
-
3
- export default function useFonts(...fontNames) {
4
- const [isLoaded, setIsLoaded] = useState(false);
5
-
6
- useEffect(() => {
7
- // Inspired by https://stackoverflow.com/a/60138011
8
- if (!document || !document.fonts) {
9
- // eslint-disable-next-line no-console
10
- console.warn('Browser does not support document.fonts API');
11
- setIsLoaded(true);
12
-
13
- return;
14
- }
15
-
16
- Promise.all(fontNames.map((fontName) => document.fonts.load(`16px "${fontName}"`))).then(() => {
17
- setIsLoaded(true);
18
- });
19
- }, [fontNames]);
20
-
21
- return isLoaded;
22
- };
package/src/lib/index.js DELETED
@@ -1,3 +0,0 @@
1
- import TextSwap from './components/index';
2
-
3
- export default TextSwap;
package/src/lib/utils.js DELETED
@@ -1,17 +0,0 @@
1
- /**
2
- * Get a random number between `min` and `max`
3
- * @param {number} min The minimum number you want to include in the random output
4
- * @param {number} max The maximum number you want to include in the random output
5
- * @returns {number} A random number including and between the `min` and `max`
6
- */
7
- export function randomMinMax(min = 0, max = 100) {
8
- return Math.floor(Math.random() * (max - min)) + min;
9
- }
10
-
11
- export function uuidv4() {
12
- return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
13
- const r = (Math.random() * 16) | 0,
14
- v = c === 'x' ? r : (r & 0x3) | 0x8;
15
- return v.toString(16);
16
- });
17
- }