fix: 修复关闭SSH终端标签页时会话状态未更新的问题

This commit is contained in:
2026-04-18 02:35:38 +08:00
commit 6e2e2f9387
43467 changed files with 5489040 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2018 Glenn Reyes
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+494
View File
@@ -0,0 +1,494 @@
# [React CountUp](https://tr8tk.csb.app/)
[![GitHub license](https://img.shields.io/npm/l/react-countup.svg?style=flat-square)](https://github.com/glennreyes/react-countup/blob/master/LICENSE)
[![Build Status](https://img.shields.io/travis/glennreyes/react-countup.svg?style=flat-square)](https://travis-ci.org/glennreyes/react-countup)
[![Coverage Status](https://img.shields.io/coveralls/glennreyes/react-countup.svg?style=flat-square)](https://coveralls.io/github/glennreyes/react-countup)
[![Version](https://img.shields.io/npm/v/react-countup.svg?style=flat-square)](https://www.npmjs.com/package/react-countup)
[![Downloads](https://img.shields.io/npm/dm/react-countup.svg?style=flat-square)](http://www.npmtrends.com/react-countup)
[![Gzip size](https://img.badgesize.io/https://unpkg.com/react-countup?style=flat-square&compression=gzip)](https://img.badgesize.io/https://unpkg.com/react-countup)
A configurable React component wrapper around [CountUp.js](https://inorganik.github.io/countUp.js/).
Click [here](https://codesandbox.io/s/github/glennreyes/react-countup/tree/master/demo?fontsize=14&hidenavigation=1&theme=dark&view=preview) to view on CodeSandbox.
### Previous docs
- [v3.x](https://github.com/glennreyes/react-countup/tree/d0002932dac8a274f951e53b1d9b1f4719176147)
- [v4.x](https://github.com/glennreyes/react-countup/tree/afd39ca66a317271ad3135b0a924b86e2982f207)
- [v5.x](https://github.com/glennreyes/react-countup/tree/ae4586c9f502fba726ff2d24d215c88d8f4879d7)
![react-countup](https://user-images.githubusercontent.com/5080854/43985960-0a7fb776-9d0c-11e8-8082-975b1e8bf51c.gif)
## Table of Contents
- [Installation](#installation)
- [Usage](#usage)
- [Simple example](#simple-example)
- [Render prop example](#render-prop-example)
- [More examples](#more-examples)
- [Manually start with render prop](#manually-start-with-render-prop)
- [Autostart with render prop](#autostart-with-render-prop)
- [Delay start](#delay-start)
- [Hook](#hook)
- [API](#api)
- [Props](#props)
- [`className: string`](#classname-string)
- [`decimal: string`](#decimal-string)
- [`decimals: number`](#decimals-number)
- [`delay: ?number`](#delay-number)
- [`duration: number`](#duration-number)
- [`end: number`](#end-number)
- [`prefix: string`](#prefix-string)
- [`redraw: boolean`](#redraw-boolean)
- [`preserveValue: boolean`](#preservevalue-boolean)
- [`separator: string`](#separator-string)
- [`start: number`](#start-number)
- [`plugin: CountUpPlugin`](#plugin-countupplugin)
- [`startOnMount: boolean`](#startonmount-boolean)
- [`suffix: string`](#suffix-string)
- [`useEasing: boolean`](#useeasing-boolean)
- [`useGrouping: boolean`](#usegrouping-boolean)
- [`useIndianSeparators: boolean`](#useindianseparators-boolean)
- [`easingFn: (t: number, b: number, c: number, d: number) => number`](#easingfn-t-number-b-number-c-number-d-number--number)
- [`formattingFn: (value: number) => string`](#formattingfn-value-number--string)
- [`enableScrollSpy: boolean`](#enablescrollspy-boolean)
- [`scrollSpyDelay: number`](#scrollspydelay-number)
- [`scrollSpyOnce: boolean`](#scrollspyonce-boolean)
- [`onEnd: ({ pauseResume, reset, start, update }) => void`](#onend--pauseresume-reset-start-update---void)
- [`onStart: ({ pauseResume, reset, update }) => void`](#onstart--pauseresume-reset-update---void)
- [`onPauseResume: ({ reset, start, update }) => void`](#onpauseresume--reset-start-update---void)
- [`onReset: ({ pauseResume, start, update }) => void`](#onreset--pauseresume-start-update---void)
- [`onUpdate: ({ pauseResume, reset, start }) => void`](#onupdate--pauseresume-reset-start---void)
- [Render props](#render-props)
- [`countUpRef: () => void`](#countupref---void)
- [`pauseResume: () => void`](#pauseresume---void)
- [`reset: () => void`](#reset---void)
- [`start: () => void`](#start---void)
- [`update: (newEnd: number?) => void`](#update-newend-number--void)
- [Protips](#protips)
- [Trigger of transition](#trigger-of-transition)
- [Run if in focus](#run-if-in-focus)
- [Set accessibility properties for occupation period](#set-accessibility-properties-for-occupation-period)
- [License](#license)
## Installation
```bash
yarn add react-countup
```
## Usage
```js
import CountUp from 'react-countup';
```
### Simple example
```js
<CountUp end={100} />
```
This will start a count up transition from `0` to `100` on render.
### Render prop example
```js
<CountUp
start={-875.039}
end={160527.012}
duration={2.75}
separator=" "
decimals={4}
decimal=","
prefix="EUR "
suffix=" left"
onEnd={() => console.log('Ended! 👏')}
onStart={() => console.log('Started! 💨')}
>
{({ countUpRef, start }) => (
<div>
<span ref={countUpRef} />
<button onClick={start}>Start</button>
</div>
)}
</CountUp>
```
The transition won't start on initial render as it needs to be triggered manually here.
> Tip: If you need to start the render prop component immediately, you can set delay={0}.
### More examples
#### Manually start with render prop
```js
<CountUp start={0} end={100}>
{({ countUpRef, start }) => (
<div>
<span ref={countUpRef} />
<button onClick={start}>Start</button>
</div>
)}
</CountUp>
```
#### Autostart with render prop
Render start value but start transition on first render:
```js
<CountUp start={0} end={100} delay={0}>
{({ countUpRef }) => (
<div>
<span ref={countUpRef} />
</div>
)}
</CountUp>
```
Note that `delay={0}` will automatically start the count up.
#### Delay start
```js
<CountUp delay={2} end={100} />
```
### Hook
#### Simple example
```js
import { useCountUp } from 'react-countup';
const SimpleHook = () => {
useCountUp({ ref: 'counter', end: 1234567 });
return <span id="counter" />;
};
```
#### Complete example
```js
import { useCountUp } from 'react-countup';
const CompleteHook = () => {
const countUpRef = React.useRef(null);
const { start, pauseResume, reset, update } = useCountUp({
ref: countUpRef,
start: 0,
end: 1234567,
delay: 1000,
duration: 5,
onReset: () => console.log('Resetted!'),
onUpdate: () => console.log('Updated!'),
onPauseResume: () => console.log('Paused or resumed!'),
onStart: ({ pauseResume }) => console.log(pauseResume),
onEnd: ({ pauseResume }) => console.log(pauseResume),
});
return (
<div>
<div ref={countUpRef} />
<button onClick={start}>Start</button>
<button onClick={reset}>Reset</button>
<button onClick={pauseResume}>Pause/Resume</button>
<button onClick={() => update(2000)}>Update to 2000</button>
</div>
);
};
```
## API
### Props
#### `className: string`
CSS class name of the span element.
> Note: This won't be applied when using CountUp with render props.
#### `decimal: string`
Specifies decimal character.
Default: `.`
#### `decimals: number`
Amount of decimals to display.
Default: `0`
#### `delay: number`
Delay in seconds before starting the transition.
Default: `null`
> Note: `delay={0}` will automatically start the count up.
#### `duration: number`
Duration in seconds.
Default: `2`
#### `end: number`
Target value.
#### `prefix: string`
Static text before the transitioning value.
#### `redraw: boolean`
Forces count up transition on every component update.
Default: `false`
#### `preserveValue: boolean`
Save previously ended number to start every new animation from it.
Default: `false`
#### `separator: string`
Specifies character of thousands separator.
#### `start: number`
Initial value.
Default: `0`
#### `plugin: CountUpPlugin`
Define plugin for alternate animations
#### `startOnMount: boolean`
Use for start counter on mount for hook usage.
Default: `true`
#### `suffix: string`
Static text after the transitioning value.
#### `useEasing: boolean`
Enables easing. Set to `false` for a linear transition.
Default: `true`
#### `useGrouping: boolean`
Enables grouping with [separator](#separator-string).
Default: `true`
#### `useIndianSeparators: boolean`
Enables grouping using indian separation, f.e. 1,00,000 vs 100,000
Default: `false`
#### `easingFn: (t: number, b: number, c: number, d: number) => number`
Easing function. Click [here](http://robertpenner.com/easing) for more details.
Default: [`easeInExpo`](https://github.com/inorganik/countUp.js/blob/master/countUp.js#L103-L106)
#### `formattingFn: (value: number) => string`
Function to customize the formatting of the number.
To prevent component from unnecessary updates this function should be memoized with [useCallback](https://reactjs.org/docs/hooks-reference.html#usecallback)
#### `enableScrollSpy: boolean`
Enables start animation when target is in view.
#### `scrollSpyDelay: number`
Delay (ms) after target comes into view
#### `scrollSpyOnce: boolean`
Run scroll spy only once
#### `onEnd: ({ pauseResume, reset, start, update }) => void`
Callback function on transition end.
#### `onStart: ({ pauseResume, reset, update }) => void`
Callback function on transition start.
#### `onPauseResume: ({ reset, start, update }) => void`
Callback function on pause or resume.
#### `onReset: ({ pauseResume, start, update }) => void`
Callback function on reset.
#### `onUpdate: ({ pauseResume, reset, start }) => void`
Callback function on update.
### Render props
#### `countUpRef: () => void`
Ref to hook the countUp instance to
#### `pauseResume: () => void`
Pauses or resumes the transition
#### `reset: () => void`
Resets to initial value
#### `start: () => void`
Starts or restarts the transition
#### `update: (newEnd: number?) => void`
Updates transition to the new end value (if given)
## Protips
### Trigger of transition
By default, the animation is triggered if any of the following props has changed:
- `duration`
- `end`
- `start`
If `redraw` is set to `true` your component will start the transition on every component update.
### Run if in focus
You need to check if your counter in viewport, [react-visibility-sensor](https://github.com/joshwnj/react-visibility-sensor) can be used for this purpose.
```js
import React from 'react';
import CountUp from 'react-countup';
import VisibilitySensor from 'react-visibility-sensor';
import './styles.css';
export default function App() {
return (
<div className="App">
<div className="content" />
<VisibilitySensor partialVisibility offset={{ bottom: 200 }}>
{({ isVisible }) => (
<div style={{ height: 100 }}>
{isVisible ? <CountUp end={1000} /> : null}
</div>
)}
</VisibilitySensor>
</div>
);
}
```
> Note: For latest **react-countup** releases there are new options [`enableScrollSpy`](#enablescrollspy-boolean) and [`scrollSpyDelay`](#scrollspydelay-number) which enable scroll spy, so that as user scrolls to the target element, it begins counting animation automatically once it has scrolled into view.
```js
import './styles.css';
import CountUp, { useCountUp } from 'react-countup';
export default function App() {
useCountUp({
ref: 'counter',
end: 1234567,
enableScrollSpy: true,
scrollSpyDelay: 1000,
});
return (
<div className="App">
<div className="content" />
<CountUp end={100} enableScrollSpy />
<br />
<span id="counter" />
</div>
);
}
```
### Set accessibility properties for occupation period
You can use callback properties to control accessibility:
```js
import React from 'react';
import CountUp, { useCountUp } from 'react-countup';
export default function App() {
useCountUp({ ref: 'counter', end: 10, duration: 2 });
const [loading, setLoading] = React.useState(false);
const onStart = () => {
setLoading(true);
};
const onEnd = () => {
setLoading(false);
};
const containerProps = {
'aria-busy': loading,
};
return (
<>
<CountUp
end={123457}
duration="3"
onStart={onStart}
onEnd={onEnd}
containerProps={containerProps}
/>
<div id="counter" aria-busy={loading} />
</>
);
}
```
### Plugin usage
```js
import { CountUp } from 'countup.js';
import { Odometer } from 'odometer_countup';
export default function App() {
useCountUp({
ref: 'counter',
end: 1234567,
enableScrollSpy: true,
scrollSpyDelay: 1000,
plugin: Odometer,
});
return (
<div className="App">
<span id="counter" />
</div>
);
}
```
## License
MIT
+12
View File
@@ -0,0 +1,12 @@
import React, { CSSProperties, ReactNode, ComponentPropsWithoutRef } from 'react';
import { CallbackProps, CommonProps, RenderCounterProps } from './types';
export interface CountUpProps extends CommonProps, CallbackProps {
className?: string;
redraw?: boolean;
children?: (props: RenderCounterProps) => ReactNode;
style?: CSSProperties;
preserveValue?: boolean;
containerProps?: ComponentPropsWithoutRef<'span'>;
}
declare const CountUp: React.FC<CountUpProps>;
export default CountUp;
+3
View File
@@ -0,0 +1,3 @@
import { CountUp } from 'countup.js';
import { CountUpInstanceProps } from './types';
export declare const createCountUpInstance: (el: string | HTMLElement, props: CountUpInstanceProps) => CountUp;
+7
View File
@@ -0,0 +1,7 @@
/**
* Create a stable reference to a callback which is updated after each render is committed.
* Typed version borrowed from Formik v2.2.1. Licensed MIT.
*
* https://github.com/formium/formik/blob/9316a864478f8fcd4fa99a0735b1d37afdf507dc/LICENSE
*/
export declare function useEventCallback<T extends (...args: any[]) => any>(fn: T): T;
@@ -0,0 +1,8 @@
import { useLayoutEffect } from 'react';
/**
* Silence SSR Warnings.
* Borrowed from Formik v2.1.1, Licensed MIT.
*
* https://github.com/formium/formik/blob/9316a864478f8fcd4fa99a0735b1d37afdf507dc/LICENSE
*/
export declare const useIsomorphicLayoutEffect: typeof useLayoutEffect;
+3
View File
@@ -0,0 +1,3 @@
export { default } from './CountUp';
export type { CountUpProps } from './CountUp';
export { default as useCountUp } from './useCountUp';
+442
View File
@@ -0,0 +1,442 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var React = require('react');
var countup_js = require('countup.js');
function _iterableToArrayLimit(r, l) {
var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (null != t) {
var e,
n,
i,
u,
a = [],
f = !0,
o = !1;
try {
if (i = (t = t.call(r)).next, 0 === l) {
if (Object(t) !== t) return;
f = !1;
} else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
} catch (r) {
o = !0, n = r;
} finally {
try {
if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
} finally {
if (o) throw n;
}
}
return a;
}
}
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;
}
function _objectSpread2(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;
}
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);
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == typeof i ? i : String(i);
}
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 _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
/**
* Silence SSR Warnings.
* Borrowed from Formik v2.1.1, Licensed MIT.
*
* https://github.com/formium/formik/blob/9316a864478f8fcd4fa99a0735b1d37afdf507dc/LICENSE
*/
var useIsomorphicLayoutEffect = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined' ? React.useLayoutEffect : React.useEffect;
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
* Create a stable reference to a callback which is updated after each render is committed.
* Typed version borrowed from Formik v2.2.1. Licensed MIT.
*
* https://github.com/formium/formik/blob/9316a864478f8fcd4fa99a0735b1d37afdf507dc/LICENSE
*/
function useEventCallback(fn) {
var ref = React.useRef(fn);
// we copy a ref to the callback scoped to the current state/props on each render
useIsomorphicLayoutEffect(function () {
ref.current = fn;
});
return React.useCallback(function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return ref.current.apply(void 0, args);
}, []);
}
var createCountUpInstance = function createCountUpInstance(el, props) {
var decimal = props.decimal,
decimals = props.decimals,
duration = props.duration,
easingFn = props.easingFn,
end = props.end,
formattingFn = props.formattingFn,
numerals = props.numerals,
prefix = props.prefix,
separator = props.separator,
start = props.start,
suffix = props.suffix,
useEasing = props.useEasing,
useGrouping = props.useGrouping,
useIndianSeparators = props.useIndianSeparators,
enableScrollSpy = props.enableScrollSpy,
scrollSpyDelay = props.scrollSpyDelay,
scrollSpyOnce = props.scrollSpyOnce,
plugin = props.plugin;
return new countup_js.CountUp(el, end, {
startVal: start,
duration: duration,
decimal: decimal,
decimalPlaces: decimals,
easingFn: easingFn,
formattingFn: formattingFn,
numerals: numerals,
separator: separator,
prefix: prefix,
suffix: suffix,
plugin: plugin,
useEasing: useEasing,
useIndianSeparators: useIndianSeparators,
useGrouping: useGrouping,
enableScrollSpy: enableScrollSpy,
scrollSpyDelay: scrollSpyDelay,
scrollSpyOnce: scrollSpyOnce
});
};
var _excluded$1 = ["ref", "startOnMount", "enableReinitialize", "delay", "onEnd", "onStart", "onPauseResume", "onReset", "onUpdate"];
var DEFAULTS = {
decimal: '.',
separator: ',',
delay: null,
prefix: '',
suffix: '',
duration: 2,
start: 0,
decimals: 0,
startOnMount: true,
enableReinitialize: true,
useEasing: true,
useGrouping: true,
useIndianSeparators: false
};
var useCountUp = function useCountUp(props) {
var filteredProps = Object.fromEntries(Object.entries(props).filter(function (_ref) {
var _ref2 = _slicedToArray(_ref, 2),
value = _ref2[1];
return value !== undefined;
}));
var _useMemo = React.useMemo(function () {
return _objectSpread2(_objectSpread2({}, DEFAULTS), filteredProps);
}, [props]),
ref = _useMemo.ref,
startOnMount = _useMemo.startOnMount,
enableReinitialize = _useMemo.enableReinitialize,
delay = _useMemo.delay,
onEnd = _useMemo.onEnd,
onStart = _useMemo.onStart,
onPauseResume = _useMemo.onPauseResume,
onReset = _useMemo.onReset,
onUpdate = _useMemo.onUpdate,
instanceProps = _objectWithoutProperties(_useMemo, _excluded$1);
var countUpRef = React.useRef();
var timerRef = React.useRef();
var isInitializedRef = React.useRef(false);
var createInstance = useEventCallback(function () {
return createCountUpInstance(typeof ref === 'string' ? ref : ref.current, instanceProps);
});
var getCountUp = useEventCallback(function (recreate) {
var countUp = countUpRef.current;
if (countUp && !recreate) {
return countUp;
}
var newCountUp = createInstance();
countUpRef.current = newCountUp;
return newCountUp;
});
var start = useEventCallback(function () {
var run = function run() {
return getCountUp(true).start(function () {
onEnd === null || onEnd === void 0 || onEnd({
pauseResume: pauseResume,
reset: reset,
start: restart,
update: update
});
});
};
if (delay && delay > 0) {
timerRef.current = setTimeout(run, delay * 1000);
} else {
run();
}
onStart === null || onStart === void 0 || onStart({
pauseResume: pauseResume,
reset: reset,
update: update
});
});
var pauseResume = useEventCallback(function () {
getCountUp().pauseResume();
onPauseResume === null || onPauseResume === void 0 || onPauseResume({
reset: reset,
start: restart,
update: update
});
});
var reset = useEventCallback(function () {
// Quick fix for https://github.com/glennreyes/react-countup/issues/736 - should be investigated
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
if (getCountUp().el) {
timerRef.current && clearTimeout(timerRef.current);
getCountUp().reset();
onReset === null || onReset === void 0 || onReset({
pauseResume: pauseResume,
start: restart,
update: update
});
}
});
var update = useEventCallback(function (newEnd) {
getCountUp().update(newEnd);
onUpdate === null || onUpdate === void 0 || onUpdate({
pauseResume: pauseResume,
reset: reset,
start: restart
});
});
var restart = useEventCallback(function () {
reset();
start();
});
var maybeInitialize = useEventCallback(function (shouldReset) {
if (startOnMount) {
if (shouldReset) {
reset();
}
start();
}
});
React.useEffect(function () {
if (!isInitializedRef.current) {
isInitializedRef.current = true;
maybeInitialize();
} else if (enableReinitialize) {
maybeInitialize(true);
}
}, [enableReinitialize, isInitializedRef, maybeInitialize, delay, props.start, props.suffix, props.prefix, props.duration, props.separator, props.decimals, props.decimal, props.formattingFn]);
React.useEffect(function () {
return function () {
reset();
};
}, [reset]);
return {
start: restart,
pauseResume: pauseResume,
reset: reset,
update: update,
getCountUp: getCountUp
};
};
var _excluded = ["className", "redraw", "containerProps", "children", "style"];
var CountUp = function CountUp(props) {
var className = props.className,
redraw = props.redraw,
containerProps = props.containerProps,
children = props.children,
style = props.style,
useCountUpProps = _objectWithoutProperties(props, _excluded);
var containerRef = React.useRef(null);
var isInitializedRef = React.useRef(false);
var _useCountUp = useCountUp(_objectSpread2(_objectSpread2({}, useCountUpProps), {}, {
ref: containerRef,
startOnMount: typeof children !== 'function' || props.delay === 0,
// component manually restarts
enableReinitialize: false
})),
start = _useCountUp.start,
reset = _useCountUp.reset,
updateCountUp = _useCountUp.update,
pauseResume = _useCountUp.pauseResume,
getCountUp = _useCountUp.getCountUp;
var restart = useEventCallback(function () {
start();
});
var update = useEventCallback(function (end) {
if (!props.preserveValue) {
reset();
}
updateCountUp(end);
});
var initializeOnMount = useEventCallback(function () {
if (typeof props.children === 'function') {
// Warn when user didn't use containerRef at all
if (!(containerRef.current instanceof Element)) {
console.error("Couldn't find attached element to hook the CountUp instance into! Try to attach \"containerRef\" from the render prop to a an Element, eg. <span ref={containerRef} />.");
return;
}
}
// unlike the hook, the CountUp component initializes on mount
getCountUp();
});
React.useEffect(function () {
initializeOnMount();
}, [initializeOnMount]);
React.useEffect(function () {
if (isInitializedRef.current) {
update(props.end);
}
}, [props.end, update]);
var redrawDependencies = redraw && props;
// if props.redraw, call this effect on every props change
React.useEffect(function () {
if (redraw && isInitializedRef.current) {
restart();
}
}, [restart, redraw, redrawDependencies]);
// if not props.redraw, call this effect only when certain props are changed
React.useEffect(function () {
if (!redraw && isInitializedRef.current) {
restart();
}
}, [restart, redraw, props.start, props.suffix, props.prefix, props.duration, props.separator, props.decimals, props.decimal, props.className, props.formattingFn]);
React.useEffect(function () {
isInitializedRef.current = true;
}, []);
if (typeof children === 'function') {
// TypeScript forces functional components to return JSX.Element | null.
return children({
countUpRef: containerRef,
start: start,
reset: reset,
update: updateCountUp,
pauseResume: pauseResume,
getCountUp: getCountUp
});
}
return /*#__PURE__*/React.createElement("span", _extends({
className: className,
ref: containerRef,
style: style
}, containerProps), typeof props.start !== 'undefined' ? getCountUp().formattingFn(props.start) : '');
};
exports.default = CountUp;
exports.useCountUp = useCountUp;
+64
View File
@@ -0,0 +1,64 @@
import * as React from 'react';
import { CountUp as CountUpJs, CountUpOptions } from 'countup.js';
type VoidFn = () => void;
export type UpdateFn = (newEnd: string | number) => void;
export type GetCountUpFn = (recreate?: boolean) => CountUpJs;
export interface CountUpApi {
start: VoidFn;
pauseResume: VoidFn;
reset: VoidFn;
update: UpdateFn;
getCountUp: GetCountUpFn;
}
export interface OnEndArgs {
pauseResume: VoidFn;
reset: VoidFn;
start: VoidFn;
update: UpdateFn;
}
export type OnEndCallback = (args: OnEndArgs) => void;
export interface OnStartArgs {
pauseResume: VoidFn;
reset: VoidFn;
update: UpdateFn;
}
export type OnStartCallback = (args: OnStartArgs) => void;
export interface OnPauseResumeArgs {
reset: VoidFn;
start: VoidFn;
update: UpdateFn;
}
export type OnPauseResumeCallback = (args: OnPauseResumeArgs) => void;
export interface OnResetArgs {
pauseResume: VoidFn;
start: VoidFn;
update: UpdateFn;
}
export type OnResetCallback = (args: OnResetArgs) => void;
export interface OnUpdateArgs {
pauseResume: VoidFn;
reset: VoidFn;
start: VoidFn;
}
export type OnUpdateCallback = (args: OnUpdateArgs) => void;
export interface CountUpInstanceProps extends CountUpOptions {
decimals?: number;
end: number;
start?: number;
useEasing?: boolean;
}
export interface CommonProps extends CountUpInstanceProps {
startOnMount?: boolean;
delay?: number | null;
}
export interface CallbackProps {
onEnd?: OnEndCallback;
onStart?: OnStartCallback;
onPauseResume?: OnPauseResumeCallback;
onReset?: OnResetCallback;
onUpdate?: OnUpdateCallback;
}
export interface RenderCounterProps extends CountUpApi {
countUpRef: React.RefObject<HTMLElement>;
}
export {};
+8
View File
@@ -0,0 +1,8 @@
import { CallbackProps, CommonProps, CountUpApi } from './types';
import React from 'react';
export interface UseCountUpProps extends CommonProps, CallbackProps {
ref: string | React.RefObject<HTMLElement>;
enableReinitialize?: boolean;
}
declare const useCountUp: (props: UseCountUpProps) => CountUpApi;
export default useCountUp;
+65
View File
@@ -0,0 +1,65 @@
{
"name": "react-countup",
"version": "6.5.3",
"description": "A React component wrapper around CountUp.js",
"author": "Glenn Reyes <glenn@glennreyes.com> (https://twitter.com/glnnrys)",
"keywords": [
"react-component",
"react",
"react.js",
"countup",
"countup.js",
"counter",
"animation"
],
"license": "MIT",
"repository": "glennreyes/react-countup",
"bugs": {
"url": "https://github.com/glennreyes/react-countup/issues"
},
"homepage": "https://react-countup.now.sh",
"main": "build",
"files": [
"build/index.js",
"build/index.d.ts"
],
"typings": "build/index.d.ts",
"scripts": {
"format": "prettier --write \"*.md\" \"src/**/*.ts\" \"src/**/*.tsx\"",
"build": "rm -rf build && rollup --bundleConfigAsCjs -c && tsc --emitDeclarationOnly --noEmit false --project src/tsconfig.json --outDir build",
"prepack": "yarn build",
"test": "jest"
},
"peerDependencies": {
"react": ">= 16.3.0"
},
"dependencies": {
"countup.js": "^2.8.0"
},
"devDependencies": {
"@babel/core": "7.23.9",
"@babel/preset-env": "7.24.0",
"@babel/preset-react": "7.23.3",
"@babel/preset-typescript": "^7.23.2",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-node-resolve": "^15.2.3",
"@testing-library/react": "14.2.0",
"@typescript-eslint/eslint-plugin": "^6.9.1",
"@typescript-eslint/parser": "^6.9.1",
"babel-jest": "29.7.0",
"eslint": "^8.52.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"jest": "29.7.0",
"jest-environment-jsdom": "^29.7.0",
"prettier": "3.2.4",
"pretty-quick": "3.1.3",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-test-renderer": "18.2.0",
"rollup": "4.9.6",
"typescript": "^5.2.2"
}
}