@number-flow/react 0.5.2 → 0.5.4

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.
@@ -0,0 +1,179 @@
1
+ 'use client';
2
+ import * as React from 'react';
3
+ import { define, NumberFlowLite, formatToData, renderInnerHTML } from 'number-flow';
4
+ import { BROWSER } from 'esm-env';
5
+
6
+ const REACT_MAJOR = parseInt(React.version.match(/^(\d+)\./)?.[1]);
7
+ const isReact19 = REACT_MAJOR >= 19;
8
+ // Can't wait to not have to do this in React 19:
9
+ const OBSERVED_ATTRIBUTES = [
10
+ 'data',
11
+ 'digits'
12
+ ];
13
+ class NumberFlowElement extends NumberFlowLite {
14
+ attributeChangedCallback(attr, _oldValue, newValue) {
15
+ this[attr] = JSON.parse(newValue);
16
+ }
17
+ }
18
+ NumberFlowElement.observedAttributes = isReact19 ? [] : OBSERVED_ATTRIBUTES;
19
+ define('number-flow-react', NumberFlowElement);
20
+ // You're supposed to cache these between uses:
21
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
22
+ // Serialize to strings b/c React:
23
+ const formatters = {};
24
+ // Tiny workaround to support React 19 until it's released:
25
+ const serialize = isReact19 ? (p)=>p : JSON.stringify;
26
+ function splitProps(props) {
27
+ const { transformTiming, spinTiming, opacityTiming, animated, respectMotionPreference, trend, plugins, ...rest } = props;
28
+ return [
29
+ {
30
+ transformTiming,
31
+ spinTiming,
32
+ opacityTiming,
33
+ animated,
34
+ respectMotionPreference,
35
+ trend,
36
+ plugins
37
+ },
38
+ rest
39
+ ];
40
+ }
41
+ // We need a class component to use getSnapshotBeforeUpdate:
42
+ class NumberFlowImpl extends React.Component {
43
+ // Update the non-`data` props to avoid JSON serialization
44
+ // Data needs to be set in render still:
45
+ updateProperties(prevProps) {
46
+ if (!this.el) return;
47
+ this.el.manual = !this.props.isolate;
48
+ const [nonData] = splitProps(this.props);
49
+ Object.entries(nonData).forEach(([k, v])=>{
50
+ // @ts-ignore
51
+ this.el[k] = v ?? NumberFlowElement.defaultProps[k];
52
+ });
53
+ if (prevProps?.onAnimationsStart) this.el.removeEventListener('animationsstart', prevProps.onAnimationsStart);
54
+ if (this.props.onAnimationsStart) this.el.addEventListener('animationsstart', this.props.onAnimationsStart);
55
+ if (prevProps?.onAnimationsFinish) this.el.removeEventListener('animationsfinish', prevProps.onAnimationsFinish);
56
+ if (this.props.onAnimationsFinish) this.el.addEventListener('animationsfinish', this.props.onAnimationsFinish);
57
+ }
58
+ componentDidMount() {
59
+ this.updateProperties();
60
+ if (isReact19 && this.el) {
61
+ // React 19 needs this because the attributeChangedCallback isn't called:
62
+ this.el.digits = this.props.digits;
63
+ this.el.data = this.props.data;
64
+ }
65
+ }
66
+ getSnapshotBeforeUpdate(prevProps) {
67
+ this.updateProperties(prevProps);
68
+ if (prevProps.data !== this.props.data) {
69
+ if (this.props.group) {
70
+ this.props.group.willUpdate();
71
+ return ()=>this.props.group?.didUpdate();
72
+ }
73
+ if (!this.props.isolate) {
74
+ this.el?.willUpdate();
75
+ return ()=>this.el?.didUpdate();
76
+ }
77
+ }
78
+ return null;
79
+ }
80
+ componentDidUpdate(_, __, didUpdate) {
81
+ didUpdate?.();
82
+ }
83
+ handleRef(el) {
84
+ if (this.props.innerRef) this.props.innerRef.current = el;
85
+ this.el = el;
86
+ }
87
+ render() {
88
+ const [_, { innerRef, className, data, willChange, isolate, group, digits, onAnimationsStart, onAnimationsFinish, ...rest }] = splitProps(this.props);
89
+ return(// @ts-expect-error missing types
90
+ /*#__PURE__*/ React.createElement("number-flow-react", {
91
+ ref: this.handleRef,
92
+ "data-will-change": willChange ? '' : undefined,
93
+ // Have to rename this:
94
+ class: className,
95
+ "aria-label": data.valueAsString,
96
+ ...rest,
97
+ role: "img",
98
+ dangerouslySetInnerHTML: {
99
+ __html: BROWSER ? '' : renderInnerHTML(data)
100
+ },
101
+ suppressHydrationWarning: true,
102
+ digits: serialize(digits),
103
+ // Make sure data is set last, everything else is updated:
104
+ data: serialize(data)
105
+ }));
106
+ }
107
+ constructor(props){
108
+ super(props);
109
+ this.handleRef = this.handleRef.bind(this);
110
+ }
111
+ }
112
+ const NumberFlow = /*#__PURE__*/ React.forwardRef(function NumberFlow({ value, locales, format, prefix, suffix, ...props }, _ref) {
113
+ React.useImperativeHandle(_ref, ()=>ref.current, []);
114
+ const ref = React.useRef();
115
+ const group = React.useContext(NumberFlowGroupContext);
116
+ group?.useRegister(ref);
117
+ const localesString = React.useMemo(()=>locales ? JSON.stringify(locales) : '', [
118
+ locales
119
+ ]);
120
+ const formatString = React.useMemo(()=>format ? JSON.stringify(format) : '', [
121
+ format
122
+ ]);
123
+ const data = React.useMemo(()=>{
124
+ const formatter = formatters[`${localesString}:${formatString}`] ??= new Intl.NumberFormat(locales, format);
125
+ return formatToData(value, formatter, prefix, suffix);
126
+ }, [
127
+ value,
128
+ localesString,
129
+ formatString,
130
+ prefix,
131
+ suffix
132
+ ]);
133
+ return /*#__PURE__*/ React.createElement(NumberFlowImpl, {
134
+ ...props,
135
+ group: group,
136
+ data: data,
137
+ innerRef: ref
138
+ });
139
+ });
140
+ const NumberFlowGroupContext = /*#__PURE__*/ React.createContext(undefined);
141
+ function NumberFlowGroup({ children }) {
142
+ const flows = React.useRef(new Set());
143
+ const updating = React.useRef(false);
144
+ const pending = React.useRef(new WeakMap());
145
+ const value = React.useMemo(()=>({
146
+ useRegister (ref) {
147
+ React.useEffect(()=>{
148
+ flows.current.add(ref);
149
+ return ()=>{
150
+ flows.current.delete(ref);
151
+ };
152
+ }, []);
153
+ },
154
+ willUpdate () {
155
+ if (updating.current) return;
156
+ updating.current = true;
157
+ flows.current.forEach((ref)=>{
158
+ const f = ref.current;
159
+ if (!f || !f.created) return;
160
+ f.willUpdate();
161
+ pending.current.set(f, true);
162
+ });
163
+ },
164
+ didUpdate () {
165
+ flows.current.forEach((ref)=>{
166
+ const f = ref.current;
167
+ if (!f || !pending.current.get(f)) return;
168
+ f.didUpdate();
169
+ pending.current.delete(f);
170
+ });
171
+ updating.current = false;
172
+ }
173
+ }), []);
174
+ return /*#__PURE__*/ React.createElement(NumberFlowGroupContext.Provider, {
175
+ value: value
176
+ }, children);
177
+ }
178
+
179
+ export { NumberFlow as N, NumberFlowElement as a, NumberFlowGroup as b };
@@ -0,0 +1,201 @@
1
+ 'use client';
2
+ var React = require('react');
3
+ var numberFlow = require('number-flow');
4
+ var esmEnv = require('esm-env');
5
+
6
+ function _interopNamespace(e) {
7
+ if (e && e.__esModule) return e;
8
+ var n = Object.create(null);
9
+ if (e) {
10
+ Object.keys(e).forEach(function (k) {
11
+ if (k !== 'default') {
12
+ var d = Object.getOwnPropertyDescriptor(e, k);
13
+ Object.defineProperty(n, k, d.get ? d : {
14
+ enumerable: true,
15
+ get: function () { return e[k]; }
16
+ });
17
+ }
18
+ });
19
+ }
20
+ n.default = e;
21
+ return n;
22
+ }
23
+
24
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
25
+
26
+ const REACT_MAJOR = parseInt(React__namespace.version.match(/^(\d+)\./)?.[1]);
27
+ const isReact19 = REACT_MAJOR >= 19;
28
+ // Can't wait to not have to do this in React 19:
29
+ const OBSERVED_ATTRIBUTES = [
30
+ 'data',
31
+ 'digits'
32
+ ];
33
+ class NumberFlowElement extends numberFlow.NumberFlowLite {
34
+ attributeChangedCallback(attr, _oldValue, newValue) {
35
+ this[attr] = JSON.parse(newValue);
36
+ }
37
+ }
38
+ NumberFlowElement.observedAttributes = isReact19 ? [] : OBSERVED_ATTRIBUTES;
39
+ numberFlow.define('number-flow-react', NumberFlowElement);
40
+ // You're supposed to cache these between uses:
41
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
42
+ // Serialize to strings b/c React:
43
+ const formatters = {};
44
+ // Tiny workaround to support React 19 until it's released:
45
+ const serialize = isReact19 ? (p)=>p : JSON.stringify;
46
+ function splitProps(props) {
47
+ const { transformTiming, spinTiming, opacityTiming, animated, respectMotionPreference, trend, plugins, ...rest } = props;
48
+ return [
49
+ {
50
+ transformTiming,
51
+ spinTiming,
52
+ opacityTiming,
53
+ animated,
54
+ respectMotionPreference,
55
+ trend,
56
+ plugins
57
+ },
58
+ rest
59
+ ];
60
+ }
61
+ // We need a class component to use getSnapshotBeforeUpdate:
62
+ class NumberFlowImpl extends React__namespace.Component {
63
+ // Update the non-`data` props to avoid JSON serialization
64
+ // Data needs to be set in render still:
65
+ updateProperties(prevProps) {
66
+ if (!this.el) return;
67
+ this.el.manual = !this.props.isolate;
68
+ const [nonData] = splitProps(this.props);
69
+ Object.entries(nonData).forEach(([k, v])=>{
70
+ // @ts-ignore
71
+ this.el[k] = v ?? NumberFlowElement.defaultProps[k];
72
+ });
73
+ if (prevProps?.onAnimationsStart) this.el.removeEventListener('animationsstart', prevProps.onAnimationsStart);
74
+ if (this.props.onAnimationsStart) this.el.addEventListener('animationsstart', this.props.onAnimationsStart);
75
+ if (prevProps?.onAnimationsFinish) this.el.removeEventListener('animationsfinish', prevProps.onAnimationsFinish);
76
+ if (this.props.onAnimationsFinish) this.el.addEventListener('animationsfinish', this.props.onAnimationsFinish);
77
+ }
78
+ componentDidMount() {
79
+ this.updateProperties();
80
+ if (isReact19 && this.el) {
81
+ // React 19 needs this because the attributeChangedCallback isn't called:
82
+ this.el.digits = this.props.digits;
83
+ this.el.data = this.props.data;
84
+ }
85
+ }
86
+ getSnapshotBeforeUpdate(prevProps) {
87
+ this.updateProperties(prevProps);
88
+ if (prevProps.data !== this.props.data) {
89
+ if (this.props.group) {
90
+ this.props.group.willUpdate();
91
+ return ()=>this.props.group?.didUpdate();
92
+ }
93
+ if (!this.props.isolate) {
94
+ this.el?.willUpdate();
95
+ return ()=>this.el?.didUpdate();
96
+ }
97
+ }
98
+ return null;
99
+ }
100
+ componentDidUpdate(_, __, didUpdate) {
101
+ didUpdate?.();
102
+ }
103
+ handleRef(el) {
104
+ if (this.props.innerRef) this.props.innerRef.current = el;
105
+ this.el = el;
106
+ }
107
+ render() {
108
+ const [_, { innerRef, className, data, willChange, isolate, group, digits, onAnimationsStart, onAnimationsFinish, ...rest }] = splitProps(this.props);
109
+ return(// @ts-expect-error missing types
110
+ /*#__PURE__*/ React__namespace.createElement("number-flow-react", {
111
+ ref: this.handleRef,
112
+ "data-will-change": willChange ? '' : undefined,
113
+ // Have to rename this:
114
+ class: className,
115
+ "aria-label": data.valueAsString,
116
+ ...rest,
117
+ role: "img",
118
+ dangerouslySetInnerHTML: {
119
+ __html: esmEnv.BROWSER ? '' : numberFlow.renderInnerHTML(data)
120
+ },
121
+ suppressHydrationWarning: true,
122
+ digits: serialize(digits),
123
+ // Make sure data is set last, everything else is updated:
124
+ data: serialize(data)
125
+ }));
126
+ }
127
+ constructor(props){
128
+ super(props);
129
+ this.handleRef = this.handleRef.bind(this);
130
+ }
131
+ }
132
+ const NumberFlow = /*#__PURE__*/ React__namespace.forwardRef(function NumberFlow({ value, locales, format, prefix, suffix, ...props }, _ref) {
133
+ React__namespace.useImperativeHandle(_ref, ()=>ref.current, []);
134
+ const ref = React__namespace.useRef();
135
+ const group = React__namespace.useContext(NumberFlowGroupContext);
136
+ group?.useRegister(ref);
137
+ const localesString = React__namespace.useMemo(()=>locales ? JSON.stringify(locales) : '', [
138
+ locales
139
+ ]);
140
+ const formatString = React__namespace.useMemo(()=>format ? JSON.stringify(format) : '', [
141
+ format
142
+ ]);
143
+ const data = React__namespace.useMemo(()=>{
144
+ const formatter = formatters[`${localesString}:${formatString}`] ??= new Intl.NumberFormat(locales, format);
145
+ return numberFlow.formatToData(value, formatter, prefix, suffix);
146
+ }, [
147
+ value,
148
+ localesString,
149
+ formatString,
150
+ prefix,
151
+ suffix
152
+ ]);
153
+ return /*#__PURE__*/ React__namespace.createElement(NumberFlowImpl, {
154
+ ...props,
155
+ group: group,
156
+ data: data,
157
+ innerRef: ref
158
+ });
159
+ });
160
+ const NumberFlowGroupContext = /*#__PURE__*/ React__namespace.createContext(undefined);
161
+ function NumberFlowGroup({ children }) {
162
+ const flows = React__namespace.useRef(new Set());
163
+ const updating = React__namespace.useRef(false);
164
+ const pending = React__namespace.useRef(new WeakMap());
165
+ const value = React__namespace.useMemo(()=>({
166
+ useRegister (ref) {
167
+ React__namespace.useEffect(()=>{
168
+ flows.current.add(ref);
169
+ return ()=>{
170
+ flows.current.delete(ref);
171
+ };
172
+ }, []);
173
+ },
174
+ willUpdate () {
175
+ if (updating.current) return;
176
+ updating.current = true;
177
+ flows.current.forEach((ref)=>{
178
+ const f = ref.current;
179
+ if (!f || !f.created) return;
180
+ f.willUpdate();
181
+ pending.current.set(f, true);
182
+ });
183
+ },
184
+ didUpdate () {
185
+ flows.current.forEach((ref)=>{
186
+ const f = ref.current;
187
+ if (!f || !pending.current.get(f)) return;
188
+ f.didUpdate();
189
+ pending.current.delete(f);
190
+ });
191
+ updating.current = false;
192
+ }
193
+ }), []);
194
+ return /*#__PURE__*/ React__namespace.createElement(NumberFlowGroupContext.Provider, {
195
+ value: value
196
+ }, children);
197
+ }
198
+
199
+ exports.NumberFlow = NumberFlow;
200
+ exports.NumberFlowElement = NumberFlowElement;
201
+ exports.NumberFlowGroup = NumberFlowGroup;
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
+ export * from 'number-flow/plugins';
1
2
  import * as React from 'react';
2
3
  import { NumberFlowLite, Value, Format, Props } from 'number-flow';
3
4
  export { Format, NumberPartType, Trend, Value } from 'number-flow';
4
- export * from 'number-flow/plugins';
5
5
 
6
6
  declare const OBSERVED_ATTRIBUTES: readonly ["data", "digits"];
7
7
  type ObservedAttribute = (typeof OBSERVED_ATTRIBUTES)[number];
@@ -38,6 +38,7 @@ declare const NumberFlow: React.ForwardRefExoticComponent<React.HTMLAttributes<N
38
38
  declare function NumberFlowGroup({ children }: {
39
39
  children: React.ReactNode;
40
40
  }): React.JSX.Element;
41
+
41
42
  declare const useIsSupported: () => boolean;
42
43
  declare const usePrefersReducedMotion: () => boolean;
43
44
  declare function useCanAnimate({ respectMotionPreference }?: {
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
+ export * from 'number-flow/plugins';
1
2
  import * as React from 'react';
2
3
  import { NumberFlowLite, Value, Format, Props } from 'number-flow';
3
4
  export { Format, NumberPartType, Trend, Value } from 'number-flow';
4
- export * from 'number-flow/plugins';
5
5
 
6
6
  declare const OBSERVED_ATTRIBUTES: readonly ["data", "digits"];
7
7
  type ObservedAttribute = (typeof OBSERVED_ATTRIBUTES)[number];
@@ -38,6 +38,7 @@ declare const NumberFlow: React.ForwardRefExoticComponent<React.HTMLAttributes<N
38
38
  declare function NumberFlowGroup({ children }: {
39
39
  children: React.ReactNode;
40
40
  }): React.JSX.Element;
41
+
41
42
  declare const useIsSupported: () => boolean;
42
43
  declare const usePrefersReducedMotion: () => boolean;
43
44
  declare function useCanAnimate({ respectMotionPreference }?: {
package/dist/index.js CHANGED
@@ -1,254 +1,50 @@
1
- "use strict";
2
- "use client";
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __export = (target, all) => {
10
- for (var name in all)
11
- __defProp(target, name, { get: all[name], enumerable: true });
12
- };
13
- var __copyProps = (to, from, except, desc) => {
14
- if (from && typeof from === "object" || typeof from === "function") {
15
- for (let key of __getOwnPropNames(from))
16
- if (!__hasOwnProp.call(to, key) && key !== except)
17
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
- }
19
- return to;
20
- };
21
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
22
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
- // If the importer is in node compatibility mode or this is not an ESM
24
- // file that has been converted to a CommonJS file using a Babel-
25
- // compatible transform (i.e. "__esModule" has not been set), then set
26
- // "default" to the CommonJS "module.exports" for node compatibility.
27
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
- mod
29
- ));
30
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ Object.defineProperty(exports, '__esModule', { value: true });
31
2
 
32
- // src/index.tsx
33
- var src_exports = {};
34
- __export(src_exports, {
35
- NumberFlowElement: () => NumberFlowElement,
36
- NumberFlowGroup: () => NumberFlowGroup,
37
- default: () => src_default,
38
- useCanAnimate: () => useCanAnimate,
39
- useIsSupported: () => useIsSupported,
40
- usePrefersReducedMotion: () => usePrefersReducedMotion
41
- });
42
- module.exports = __toCommonJS(src_exports);
43
- var React = __toESM(require("react"));
44
- var import_number_flow = require("number-flow");
45
- var import_esm_env = require("esm-env");
46
- __reExport(src_exports, require("number-flow/plugins"), module.exports);
47
- var REACT_MAJOR = parseInt(React.version.match(/^(\d+)\./)?.[1]);
48
- var isReact19 = REACT_MAJOR >= 19;
49
- var OBSERVED_ATTRIBUTES = ["data", "digits"];
50
- var NumberFlowElement = class extends import_number_flow.NumberFlowLite {
51
- attributeChangedCallback(attr, _oldValue, newValue) {
52
- this[attr] = JSON.parse(newValue);
53
- }
54
- };
55
- NumberFlowElement.observedAttributes = isReact19 ? [] : OBSERVED_ATTRIBUTES;
56
- (0, import_number_flow.define)("number-flow-react", NumberFlowElement);
57
- var formatters = {};
58
- var serialize = isReact19 ? (p) => p : JSON.stringify;
59
- function splitProps(props) {
60
- const {
61
- transformTiming,
62
- spinTiming,
63
- opacityTiming,
64
- animated,
65
- respectMotionPreference,
66
- trend,
67
- plugins,
68
- ...rest
69
- } = props;
70
- return [
71
- {
72
- transformTiming,
73
- spinTiming,
74
- opacityTiming,
75
- animated,
76
- respectMotionPreference,
77
- trend,
78
- plugins
79
- },
80
- rest
81
- ];
82
- }
83
- var NumberFlowImpl = class extends React.Component {
84
- constructor(props) {
85
- super(props);
86
- this.handleRef = this.handleRef.bind(this);
87
- }
88
- // Update the non-`data` props to avoid JSON serialization
89
- // Data needs to be set in render still:
90
- updateProperties(prevProps) {
91
- if (!this.el) return;
92
- this.el.manual = !this.props.isolate;
93
- const [nonData] = splitProps(this.props);
94
- Object.entries(nonData).forEach(([k, v]) => {
95
- this.el[k] = v ?? NumberFlowElement.defaultProps[k];
96
- });
97
- if (prevProps?.onAnimationsStart)
98
- this.el.removeEventListener("animationsstart", prevProps.onAnimationsStart);
99
- if (this.props.onAnimationsStart)
100
- this.el.addEventListener("animationsstart", this.props.onAnimationsStart);
101
- if (prevProps?.onAnimationsFinish)
102
- this.el.removeEventListener("animationsfinish", prevProps.onAnimationsFinish);
103
- if (this.props.onAnimationsFinish)
104
- this.el.addEventListener("animationsfinish", this.props.onAnimationsFinish);
105
- }
106
- componentDidMount() {
107
- this.updateProperties();
108
- if (isReact19 && this.el) {
109
- this.el.digits = this.props.digits;
110
- this.el.data = this.props.data;
111
- }
112
- }
113
- getSnapshotBeforeUpdate(prevProps) {
114
- this.updateProperties(prevProps);
115
- if (prevProps.data !== this.props.data) {
116
- if (this.props.group) {
117
- this.props.group.willUpdate();
118
- return () => this.props.group?.didUpdate();
119
- }
120
- if (!this.props.isolate) {
121
- this.el?.willUpdate();
122
- return () => this.el?.didUpdate();
123
- }
124
- }
125
- return null;
126
- }
127
- componentDidUpdate(_, __, didUpdate) {
128
- didUpdate?.();
129
- }
130
- handleRef(el) {
131
- if (this.props.innerRef) this.props.innerRef.current = el;
132
- this.el = el;
133
- }
134
- render() {
135
- const [
136
- _,
137
- {
138
- innerRef,
139
- className,
140
- data,
141
- willChange,
142
- isolate,
143
- group,
144
- digits,
145
- onAnimationsStart,
146
- onAnimationsFinish,
147
- ...rest
148
- }
149
- ] = splitProps(this.props);
150
- return (
151
- // @ts-expect-error missing types
152
- /* @__PURE__ */ React.createElement(
153
- "number-flow-react",
154
- {
155
- ref: this.handleRef,
156
- "data-will-change": willChange ? "" : void 0,
157
- class: className,
158
- "aria-label": data.valueAsString,
159
- ...rest,
160
- role: "img",
161
- dangerouslySetInnerHTML: { __html: import_esm_env.BROWSER ? "" : (0, import_number_flow.renderInnerHTML)(data) },
162
- suppressHydrationWarning: true,
163
- digits: serialize(digits),
164
- data: serialize(data)
165
- }
166
- )
167
- );
168
- }
169
- };
170
- var NumberFlow = React.forwardRef(function NumberFlow2({ value, locales, format, prefix, suffix, ...props }, _ref) {
171
- React.useImperativeHandle(_ref, () => ref.current, []);
172
- const ref = React.useRef();
173
- const group = React.useContext(NumberFlowGroupContext);
174
- group?.useRegister(ref);
175
- const localesString = React.useMemo(() => locales ? JSON.stringify(locales) : "", [locales]);
176
- const formatString = React.useMemo(() => format ? JSON.stringify(format) : "", [format]);
177
- const data = React.useMemo(() => {
178
- const formatter = formatters[`${localesString}:${formatString}`] ??= new Intl.NumberFormat(
179
- locales,
180
- format
181
- );
182
- return (0, import_number_flow.formatToData)(value, formatter, prefix, suffix);
183
- }, [value, localesString, formatString, prefix, suffix]);
184
- return /* @__PURE__ */ React.createElement(NumberFlowImpl, { ...props, group, data, innerRef: ref });
185
- });
186
- var src_default = NumberFlow;
187
- var NumberFlowGroupContext = React.createContext(void 0);
188
- function NumberFlowGroup({ children }) {
189
- const flows = React.useRef(/* @__PURE__ */ new Set());
190
- const updating = React.useRef(false);
191
- const pending = React.useRef(/* @__PURE__ */ new WeakMap());
192
- const value = React.useMemo(
193
- () => ({
194
- useRegister(ref) {
195
- React.useEffect(() => {
196
- flows.current.add(ref);
197
- return () => {
198
- flows.current.delete(ref);
199
- };
200
- }, []);
201
- },
202
- willUpdate() {
203
- if (updating.current) return;
204
- updating.current = true;
205
- flows.current.forEach((ref) => {
206
- const f = ref.current;
207
- if (!f || !f.created) return;
208
- f.willUpdate();
209
- pending.current.set(f, true);
210
- });
211
- },
212
- didUpdate() {
213
- flows.current.forEach((ref) => {
214
- const f = ref.current;
215
- if (!f || !pending.current.get(f)) return;
216
- f.didUpdate();
217
- pending.current.delete(f);
218
- });
219
- updating.current = false;
220
- }
221
- }),
222
- []
223
- );
224
- return /* @__PURE__ */ React.createElement(NumberFlowGroupContext.Provider, { value }, children);
3
+ var React = require('react');
4
+ var numberFlow = require('number-flow');
5
+ var plugins = require('number-flow/plugins');
6
+ var NumberFlowClient = require('./NumberFlow-client-CMnZwURp.js');
7
+
8
+ function _interopNamespace(e) {
9
+ if (e && e.__esModule) return e;
10
+ var n = Object.create(null);
11
+ if (e) {
12
+ Object.keys(e).forEach(function (k) {
13
+ if (k !== 'default') {
14
+ var d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: function () { return e[k]; }
18
+ });
19
+ }
20
+ });
21
+ }
22
+ n.default = e;
23
+ return n;
225
24
  }
226
- var useIsSupported = () => React.useSyncExternalStore(
227
- () => () => {
228
- },
229
- // this value doesn't change, but it's useful to specify a different SSR value:
230
- () => import_number_flow.canAnimate,
231
- () => false
232
- );
233
- var usePrefersReducedMotion = () => React.useSyncExternalStore(
234
- (cb) => {
235
- import_number_flow.prefersReducedMotion?.addEventListener("change", cb);
236
- return () => import_number_flow.prefersReducedMotion?.removeEventListener("change", cb);
237
- },
238
- () => import_number_flow.prefersReducedMotion.matches,
239
- () => false
240
- );
25
+
26
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
27
+
28
+ const useIsSupported = ()=>React__namespace.useSyncExternalStore(()=>()=>{}, ()=>numberFlow.canAnimate, ()=>false);
29
+ const usePrefersReducedMotion = ()=>React__namespace.useSyncExternalStore((cb)=>{
30
+ numberFlow.prefersReducedMotion?.addEventListener('change', cb);
31
+ return ()=>numberFlow.prefersReducedMotion?.removeEventListener('change', cb);
32
+ }, ()=>numberFlow.prefersReducedMotion.matches, ()=>false);
241
33
  function useCanAnimate({ respectMotionPreference = true } = {}) {
242
- const isSupported = useIsSupported();
243
- const reducedMotion = usePrefersReducedMotion();
244
- return isSupported && (!respectMotionPreference || !reducedMotion);
34
+ const isSupported = useIsSupported();
35
+ const reducedMotion = usePrefersReducedMotion();
36
+ return isSupported && (!respectMotionPreference || !reducedMotion);
245
37
  }
246
- // Annotate the CommonJS export names for ESM import in node:
247
- 0 && (module.exports = {
248
- NumberFlowElement,
249
- NumberFlowGroup,
250
- useCanAnimate,
251
- useIsSupported,
252
- usePrefersReducedMotion,
253
- ...require("number-flow/plugins")
38
+
39
+ exports.NumberFlowElement = NumberFlowClient.NumberFlowElement;
40
+ exports.NumberFlowGroup = NumberFlowClient.NumberFlowGroup;
41
+ exports.default = NumberFlowClient.NumberFlow;
42
+ exports.useCanAnimate = useCanAnimate;
43
+ exports.useIsSupported = useIsSupported;
44
+ exports.usePrefersReducedMotion = usePrefersReducedMotion;
45
+ Object.keys(plugins).forEach(function (k) {
46
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
47
+ enumerable: true,
48
+ get: function () { return plugins[k]; }
49
+ });
254
50
  });
package/dist/index.mjs CHANGED
@@ -1,221 +1,17 @@
1
- "use client";
1
+ import * as React from 'react';
2
+ import { canAnimate, prefersReducedMotion } from 'number-flow';
3
+ export * from 'number-flow/plugins';
4
+ export { a as NumberFlowElement, b as NumberFlowGroup, N as default } from './NumberFlow-client-CHWbu7lx.mjs';
2
5
 
3
- // src/index.tsx
4
- import * as React from "react";
5
- import {
6
- renderInnerHTML,
7
- formatToData,
8
- NumberFlowLite,
9
- prefersReducedMotion as _prefersReducedMotion,
10
- canAnimate as _canAnimate,
11
- define
12
- } from "number-flow";
13
- import { BROWSER } from "esm-env";
14
- export * from "number-flow/plugins";
15
- var REACT_MAJOR = parseInt(React.version.match(/^(\d+)\./)?.[1]);
16
- var isReact19 = REACT_MAJOR >= 19;
17
- var OBSERVED_ATTRIBUTES = ["data", "digits"];
18
- var NumberFlowElement = class extends NumberFlowLite {
19
- attributeChangedCallback(attr, _oldValue, newValue) {
20
- this[attr] = JSON.parse(newValue);
21
- }
22
- };
23
- NumberFlowElement.observedAttributes = isReact19 ? [] : OBSERVED_ATTRIBUTES;
24
- define("number-flow-react", NumberFlowElement);
25
- var formatters = {};
26
- var serialize = isReact19 ? (p) => p : JSON.stringify;
27
- function splitProps(props) {
28
- const {
29
- transformTiming,
30
- spinTiming,
31
- opacityTiming,
32
- animated,
33
- respectMotionPreference,
34
- trend,
35
- plugins,
36
- ...rest
37
- } = props;
38
- return [
39
- {
40
- transformTiming,
41
- spinTiming,
42
- opacityTiming,
43
- animated,
44
- respectMotionPreference,
45
- trend,
46
- plugins
47
- },
48
- rest
49
- ];
50
- }
51
- var NumberFlowImpl = class extends React.Component {
52
- constructor(props) {
53
- super(props);
54
- this.handleRef = this.handleRef.bind(this);
55
- }
56
- // Update the non-`data` props to avoid JSON serialization
57
- // Data needs to be set in render still:
58
- updateProperties(prevProps) {
59
- if (!this.el) return;
60
- this.el.manual = !this.props.isolate;
61
- const [nonData] = splitProps(this.props);
62
- Object.entries(nonData).forEach(([k, v]) => {
63
- this.el[k] = v ?? NumberFlowElement.defaultProps[k];
64
- });
65
- if (prevProps?.onAnimationsStart)
66
- this.el.removeEventListener("animationsstart", prevProps.onAnimationsStart);
67
- if (this.props.onAnimationsStart)
68
- this.el.addEventListener("animationsstart", this.props.onAnimationsStart);
69
- if (prevProps?.onAnimationsFinish)
70
- this.el.removeEventListener("animationsfinish", prevProps.onAnimationsFinish);
71
- if (this.props.onAnimationsFinish)
72
- this.el.addEventListener("animationsfinish", this.props.onAnimationsFinish);
73
- }
74
- componentDidMount() {
75
- this.updateProperties();
76
- if (isReact19 && this.el) {
77
- this.el.digits = this.props.digits;
78
- this.el.data = this.props.data;
79
- }
80
- }
81
- getSnapshotBeforeUpdate(prevProps) {
82
- this.updateProperties(prevProps);
83
- if (prevProps.data !== this.props.data) {
84
- if (this.props.group) {
85
- this.props.group.willUpdate();
86
- return () => this.props.group?.didUpdate();
87
- }
88
- if (!this.props.isolate) {
89
- this.el?.willUpdate();
90
- return () => this.el?.didUpdate();
91
- }
92
- }
93
- return null;
94
- }
95
- componentDidUpdate(_, __, didUpdate) {
96
- didUpdate?.();
97
- }
98
- handleRef(el) {
99
- if (this.props.innerRef) this.props.innerRef.current = el;
100
- this.el = el;
101
- }
102
- render() {
103
- const [
104
- _,
105
- {
106
- innerRef,
107
- className,
108
- data,
109
- willChange,
110
- isolate,
111
- group,
112
- digits,
113
- onAnimationsStart,
114
- onAnimationsFinish,
115
- ...rest
116
- }
117
- ] = splitProps(this.props);
118
- return (
119
- // @ts-expect-error missing types
120
- /* @__PURE__ */ React.createElement(
121
- "number-flow-react",
122
- {
123
- ref: this.handleRef,
124
- "data-will-change": willChange ? "" : void 0,
125
- class: className,
126
- "aria-label": data.valueAsString,
127
- ...rest,
128
- role: "img",
129
- dangerouslySetInnerHTML: { __html: BROWSER ? "" : renderInnerHTML(data) },
130
- suppressHydrationWarning: true,
131
- digits: serialize(digits),
132
- data: serialize(data)
133
- }
134
- )
135
- );
136
- }
137
- };
138
- var NumberFlow = React.forwardRef(function NumberFlow2({ value, locales, format, prefix, suffix, ...props }, _ref) {
139
- React.useImperativeHandle(_ref, () => ref.current, []);
140
- const ref = React.useRef();
141
- const group = React.useContext(NumberFlowGroupContext);
142
- group?.useRegister(ref);
143
- const localesString = React.useMemo(() => locales ? JSON.stringify(locales) : "", [locales]);
144
- const formatString = React.useMemo(() => format ? JSON.stringify(format) : "", [format]);
145
- const data = React.useMemo(() => {
146
- const formatter = formatters[`${localesString}:${formatString}`] ??= new Intl.NumberFormat(
147
- locales,
148
- format
149
- );
150
- return formatToData(value, formatter, prefix, suffix);
151
- }, [value, localesString, formatString, prefix, suffix]);
152
- return /* @__PURE__ */ React.createElement(NumberFlowImpl, { ...props, group, data, innerRef: ref });
153
- });
154
- var src_default = NumberFlow;
155
- var NumberFlowGroupContext = React.createContext(void 0);
156
- function NumberFlowGroup({ children }) {
157
- const flows = React.useRef(/* @__PURE__ */ new Set());
158
- const updating = React.useRef(false);
159
- const pending = React.useRef(/* @__PURE__ */ new WeakMap());
160
- const value = React.useMemo(
161
- () => ({
162
- useRegister(ref) {
163
- React.useEffect(() => {
164
- flows.current.add(ref);
165
- return () => {
166
- flows.current.delete(ref);
167
- };
168
- }, []);
169
- },
170
- willUpdate() {
171
- if (updating.current) return;
172
- updating.current = true;
173
- flows.current.forEach((ref) => {
174
- const f = ref.current;
175
- if (!f || !f.created) return;
176
- f.willUpdate();
177
- pending.current.set(f, true);
178
- });
179
- },
180
- didUpdate() {
181
- flows.current.forEach((ref) => {
182
- const f = ref.current;
183
- if (!f || !pending.current.get(f)) return;
184
- f.didUpdate();
185
- pending.current.delete(f);
186
- });
187
- updating.current = false;
188
- }
189
- }),
190
- []
191
- );
192
- return /* @__PURE__ */ React.createElement(NumberFlowGroupContext.Provider, { value }, children);
193
- }
194
- var useIsSupported = () => React.useSyncExternalStore(
195
- () => () => {
196
- },
197
- // this value doesn't change, but it's useful to specify a different SSR value:
198
- () => _canAnimate,
199
- () => false
200
- );
201
- var usePrefersReducedMotion = () => React.useSyncExternalStore(
202
- (cb) => {
203
- _prefersReducedMotion?.addEventListener("change", cb);
204
- return () => _prefersReducedMotion?.removeEventListener("change", cb);
205
- },
206
- () => _prefersReducedMotion.matches,
207
- () => false
208
- );
6
+ const useIsSupported = ()=>React.useSyncExternalStore(()=>()=>{}, ()=>canAnimate, ()=>false);
7
+ const usePrefersReducedMotion = ()=>React.useSyncExternalStore((cb)=>{
8
+ prefersReducedMotion?.addEventListener('change', cb);
9
+ return ()=>prefersReducedMotion?.removeEventListener('change', cb);
10
+ }, ()=>prefersReducedMotion.matches, ()=>false);
209
11
  function useCanAnimate({ respectMotionPreference = true } = {}) {
210
- const isSupported = useIsSupported();
211
- const reducedMotion = usePrefersReducedMotion();
212
- return isSupported && (!respectMotionPreference || !reducedMotion);
12
+ const isSupported = useIsSupported();
13
+ const reducedMotion = usePrefersReducedMotion();
14
+ return isSupported && (!respectMotionPreference || !reducedMotion);
213
15
  }
214
- export {
215
- NumberFlowElement,
216
- NumberFlowGroup,
217
- src_default as default,
218
- useCanAnimate,
219
- useIsSupported,
220
- usePrefersReducedMotion
221
- };
16
+
17
+ export { useCanAnimate, useIsSupported, usePrefersReducedMotion };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.5.2",
6
+ "version": "0.5.4",
7
7
  "author": {
8
8
  "name": "Maxwell Barvian",
9
9
  "email": "max@barvian.me",
@@ -56,17 +56,17 @@
56
56
  "@types/node": "^22.7.9",
57
57
  "@types/react": "^18.3.3",
58
58
  "@types/react-dom": "^18.3.0",
59
+ "bunchee": "^6.3.1",
59
60
  "react": "^18.3.1",
60
- "react-dom": "^18.3.1",
61
- "tsup": "^8.2.4"
61
+ "react-dom": "^18.3.1"
62
62
  },
63
63
  "peerDependencies": {
64
64
  "react": "^18 || ^19",
65
65
  "react-dom": "^18 || ^19"
66
66
  },
67
67
  "scripts": {
68
- "build": "tsup --tsconfig tsconfig.build.json",
69
- "dev": "tsup --watch",
68
+ "build": "bunchee --tsconfig tsconfig.build.json",
69
+ "dev": "bunchee --watch",
70
70
  "test": "pnpm -r --workspace-concurrency 1 --filter=\"./test/apps/*\" test"
71
71
  }
72
72
  }