@w3ux/react-odometer 2.3.10 → 2.3.12

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/index.cjs CHANGED
@@ -25,7 +25,6 @@ __export(index_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(index_exports);
27
27
  var import_react = require("react");
28
- var import_hooks = require("@w3ux/hooks");
29
28
  var import_jsx_runtime = require("react/jsx-runtime");
30
29
  var Odometer = ({
31
30
  value,
@@ -55,45 +54,31 @@ var Odometer = ({
55
54
  const [initialized, setInitialized] = (0, import_react.useState)(false);
56
55
  const [odometerRef] = (0, import_react.useState)((0, import_react.createRef)());
57
56
  const [digitRefs, setDigitRefs] = (0, import_react.useState)([]);
58
- const digitWidths = (0, import_react.useRef)({});
57
+ const [allDigitRefs, setAllDigitRefs] = (0, import_react.useState)({});
59
58
  const activeTransitionCounter = (0, import_react.useRef)(0);
60
59
  const DURATION_MS = 750;
61
60
  const DURATION_SECS = `${DURATION_MS / 1e3}s`;
62
- const handleValueDigitRefs = (v) => {
63
- v = String(v) === "0" ? Number(v).toFixed(zeroDecimals) : v;
64
- const newDigits = v.toString().split("").map((v2) => v2 === "." ? "dot" : v2).map((v2) => v2 === "," ? "comma" : v2);
65
- setDigits(newDigits);
66
- if (!initialized) {
67
- setInitialized(true);
68
- } else {
69
- setStatus("new");
70
- setPrevDigits(digits);
71
- }
72
- setDigitRefs(
73
- Array.from({ length: newDigits.length }, () => (0, import_react.createRef)())
74
- );
75
- };
76
61
  (0, import_react.useEffect)(() => {
77
- handleValueDigitRefs(value);
62
+ const all = Object.fromEntries(
63
+ Object.values(allDigits).map((v) => [`d_${v}`, (0, import_react.createRef)()])
64
+ );
65
+ setAllDigitRefs(all);
78
66
  }, []);
79
67
  (0, import_react.useEffect)(() => {
80
- if (digitRefs.length > 0 && !digitRefs.find((d) => d.current === null)) {
81
- digitRefs.forEach((ref, i) => {
82
- if (ref.current) {
83
- const childSpan = ref.current.querySelector(
84
- ".odometer-child"
85
- );
86
- const width = childSpan?.offsetWidth;
87
- const digit = digits[i];
88
- if (width && !digitWidths.current[digit]) {
89
- digitWidths.current[digit] = width;
90
- }
91
- }
92
- });
68
+ if (Object.keys(allDigitRefs)) {
69
+ value = String(value) === "0" ? Number(value).toFixed(zeroDecimals) : value;
70
+ const newDigits = value.toString().split("").map((v) => v === "." ? "dot" : v).map((v) => v === "," ? "comma" : v);
71
+ setDigits(newDigits);
72
+ if (!initialized) {
73
+ setInitialized(true);
74
+ } else {
75
+ setStatus("new");
76
+ setPrevDigits(digits);
77
+ }
78
+ setDigitRefs(
79
+ Array.from({ length: newDigits.length }, () => (0, import_react.createRef)())
80
+ );
93
81
  }
94
- }, [digitRefs, digits]);
95
- (0, import_hooks.useEffectIgnoreInitial)(() => {
96
- handleValueDigitRefs(value);
97
82
  }, [value]);
98
83
  (0, import_react.useEffect)(() => {
99
84
  if (status === "new" && !digitRefs.find((d) => d.current === null)) {
@@ -112,6 +97,21 @@ var Odometer = ({
112
97
  lineHeight = lineHeight === "normal" ? "1.1rem" : lineHeight;
113
98
  let foundDecimal = false;
114
99
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "odometer", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "odometer-inner", ref: odometerRef, children: [
100
+ allDigits.map((d, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
101
+ "span",
102
+ {
103
+ ref: allDigitRefs[`d_${d}`],
104
+ style: {
105
+ opacity: 0,
106
+ position: "fixed",
107
+ top: "-999%",
108
+ left: "-999%",
109
+ userSelect: "none"
110
+ },
111
+ children: d === "dot" ? "." : d === "comma" ? "," : d
112
+ },
113
+ `odometer_template_digit_${i}`
114
+ )),
115
115
  spaceBefore ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { paddingLeft: spaceBefore } }) : null,
116
116
  digits.map((d, i) => {
117
117
  if (d === "dot") {
@@ -173,7 +173,6 @@ var Odometer = ({
173
173
  }
174
174
  );
175
175
  }
176
- const offsetWidth = digitWidths.current[d];
177
176
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
178
177
  "span",
179
178
  {
@@ -183,7 +182,7 @@ var Odometer = ({
183
182
  color: foundDecimal ? decimalColor : wholeColor,
184
183
  height: lineHeight,
185
184
  lineHeight,
186
- minWidth: offsetWidth ? `${offsetWidth}px` : void 0
185
+ paddingRight: status === "transition" ? `${allDigitRefs[`d_${d}`]?.current?.offsetWidth}px` : "0"
187
186
  },
188
187
  children: [
189
188
  status === "inactive" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -191,12 +190,10 @@ var Odometer = ({
191
190
  {
192
191
  className: "odometer-digit odometer-child",
193
192
  style: {
194
- position: offsetWidth ? "absolute" : "relative",
195
- top: offsetWidth ? 0 : void 0,
196
- left: offsetWidth ? 0 : void 0,
193
+ top: 0,
197
194
  height: lineHeight,
198
195
  lineHeight,
199
- width: offsetWidth ? `${offsetWidth}px` : "auto"
196
+ width: `${allDigitRefs[`d_${d}`]?.current?.offsetWidth}px`
200
197
  },
201
198
  children: d === "dot" ? "." : d === "comma" ? "," : d
202
199
  }
package/index.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx"],"sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { createRef, useEffect, useRef, useState } from 'react'\nimport './index.css'\nimport { useEffectIgnoreInitial } from '@w3ux/hooks'\nimport type { Digit, DigitRef, Direction, Props, Status } from './types'\n\nexport const Odometer = ({\n\tvalue,\n\tspaceBefore = 0,\n\tspaceAfter = '0.25rem',\n\twholeColor = 'var(--text-color-primary)',\n\tdecimalColor = 'var(--text-color-secondary)',\n\tzeroDecimals = 0,\n}: Props) => {\n\t// Store all possible digits.\n\tconst [allDigits] = useState<Digit[]>([\n\t\t'comma',\n\t\t'dot',\n\t\t'0',\n\t\t'1',\n\t\t'2',\n\t\t'3',\n\t\t'4',\n\t\t'5',\n\t\t'6',\n\t\t'7',\n\t\t'8',\n\t\t'9',\n\t])\n\n\t// Store the digits of the current value.\n\tconst [digits, setDigits] = useState<Digit[]>([])\n\n\t// Store digits of the previous value.\n\tconst [prevDigits, setPrevDigits] = useState<Digit[]>([])\n\n\t// Store the status of the odometer (transitioning or stable).\n\tconst [status, setStatus] = useState<Status>('inactive')\n\n\t// Store whether component has initialized.\n\tconst [initialized, setInitialized] = useState<boolean>(false)\n\n\t// Store ref of the odometer.\n\tconst [odometerRef] = useState(createRef<HTMLSpanElement>())\n\n\t// Store refs of each digit.\n\tconst [digitRefs, setDigitRefs] = useState<DigitRef[]>([])\n\n\t// Store measured widths for each digit character.\n\tconst digitWidths = useRef<Record<string, number>>({})\n\n\t// Keep track of active transitions.\n\tconst activeTransitionCounter = useRef<number>(0)\n\n\t// Transition duration.\n\tconst DURATION_MS = 750\n\tconst DURATION_SECS = `${DURATION_MS / 1000}s`\n\n\t// Set digit refs for a value.\n\tconst handleValueDigitRefs = (v: string | number) => {\n\t\tv = String(v) === '0' ? Number(v).toFixed(zeroDecimals) : v\n\n\t\tconst newDigits = v\n\t\t\t.toString()\n\t\t\t.split('')\n\t\t\t.map((v) => (v === '.' ? 'dot' : v))\n\t\t\t.map((v) => (v === ',' ? 'comma' : v)) as Digit[]\n\n\t\tsetDigits(newDigits)\n\n\t\tif (!initialized) {\n\t\t\tsetInitialized(true)\n\t\t} else {\n\t\t\tsetStatus('new')\n\t\t\tsetPrevDigits(digits)\n\t\t}\n\t\tsetDigitRefs(\n\t\t\tArray.from({ length: newDigits.length }, () => createRef() as DigitRef),\n\t\t)\n\t}\n\n\t// Phase 0: initialize with first value.\n\tuseEffect(() => {\n\t\thandleValueDigitRefs(value)\n\t}, [])\n\n\t// Phase 1: measure digit widths after refs are attached.\n\tuseEffect(() => {\n\t\tif (digitRefs.length > 0 && !digitRefs.find((d) => d.current === null)) {\n\t\t\tdigitRefs.forEach((ref, i) => {\n\t\t\t\tif (ref.current) {\n\t\t\t\t\t// Measure the child span's width\n\t\t\t\t\tconst childSpan = ref.current.querySelector(\n\t\t\t\t\t\t'.odometer-child',\n\t\t\t\t\t) as HTMLSpanElement\n\t\t\t\t\tconst width = childSpan?.offsetWidth\n\t\t\t\t\tconst digit = digits[i]\n\t\t\t\t\tif (width && !digitWidths.current[digit]) {\n\t\t\t\t\t\tdigitWidths.current[digit] = width\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}, [digitRefs, digits])\n\n\t// Phase 2: new digits and refs are added to the odometer.\n\tuseEffectIgnoreInitial(() => {\n\t\thandleValueDigitRefs(value)\n\t}, [value])\n\n\t// Phase 3: set up digit transition.\n\tuseEffect(() => {\n\t\tif (status === 'new' && !digitRefs.find((d) => d.current === null)) {\n\t\t\tsetStatus('transition')\n\t\t\tactiveTransitionCounter.current++\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tactiveTransitionCounter.current--\n\t\t\t\tif (activeTransitionCounter.current === 0) {\n\t\t\t\t\tsetStatus('inactive')\n\t\t\t\t}\n\t\t\t}, DURATION_MS)\n\t\t}\n\t}, [status, digitRefs])\n\n\tconst odometerCurrent: HTMLSpanElement | null = odometerRef.current\n\tlet lineHeight = odometerCurrent\n\t\t? window.getComputedStyle(odometerCurrent).lineHeight\n\t\t: 'inherit'\n\n\t// Fallback line height to `1.1rem` if `normal`.\n\tlineHeight = lineHeight === 'normal' ? '1.1rem' : lineHeight\n\n\t// Track whether decimal point has been found.\n\tlet foundDecimal = false\n\n\treturn (\n\t\t<span className=\"odometer\">\n\t\t\t<span className=\"odometer-inner\" ref={odometerRef}>\n\t\t\t\t{spaceBefore ? <span style={{ paddingLeft: spaceBefore }} /> : null}\n\t\t\t\t{digits.map((d, i) => {\n\t\t\t\t\tif (d === 'dot') {\n\t\t\t\t\t\tfoundDecimal = true\n\t\t\t\t\t}\n\n\t\t\t\t\t// If transitioning, get digits needed to animate.\n\t\t\t\t\tlet childDigits = null\n\t\t\t\t\tif (status === 'transition') {\n\t\t\t\t\t\tconst digitsToAnimate = []\n\t\t\t\t\t\tconst digitIndex = allDigits.indexOf(digits[i])\n\t\t\t\t\t\tconst prevDigitIndex = allDigits.indexOf(prevDigits[i])\n\t\t\t\t\t\tconst difference = Math.abs(digitIndex - prevDigitIndex)\n\t\t\t\t\t\tconst delay = `${0.01 * (digits.length - i - 1)}s`\n\t\t\t\t\t\tconst direction: Direction =\n\t\t\t\t\t\t\tdigitIndex === prevDigitIndex ? 'none' : 'down'\n\t\t\t\t\t\tconst animClass = `slide-${direction}-${difference} `\n\n\t\t\t\t\t\t// Push current prev digit to stop of stack.\n\t\t\t\t\t\tdigitsToAnimate.push(prevDigits[i])\n\n\t\t\t\t\t\t// If transitioning between two digits, animate all digits in between.\n\t\t\t\t\t\tif (digitIndex < prevDigitIndex) {\n\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t(_, k) => allDigits[prevDigitIndex - k - 1],\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t(_, k) => allDigits[k + prevDigitIndex + 1],\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tchildDigits = (\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\t\t\t\tanimationName: direction === 'none' ? undefined : animClass,\n\t\t\t\t\t\t\t\t\tanimationDuration:\n\t\t\t\t\t\t\t\t\t\tdirection === 'none' ? undefined : DURATION_SECS,\n\t\t\t\t\t\t\t\t\tanimationFillMode: 'forwards',\n\t\t\t\t\t\t\t\t\tanimationTimingFunction: 'cubic-bezier(0.1, 1, 0.2, 1)',\n\t\t\t\t\t\t\t\t\tanimationDelay: delay,\n\t\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\t\tuserSelect: 'none',\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{digitsToAnimate.map((c, j) => (\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tkey={`child_digit_${j}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"odometer-digit odometer-child\"\n\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\ttop: j === 0 ? 0 : `${100 * j}%`,\n\t\t\t\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{c === 'dot' ? '.' : c === 'comma' ? ',' : c}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst offsetWidth = digitWidths.current[d]\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tkey={`digit_${i}`}\n\t\t\t\t\t\t\tref={digitRefs[i]}\n\t\t\t\t\t\t\tclassName=\"odometer-digit\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\tminWidth: offsetWidth ? `${offsetWidth}px` : undefined,\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{status === 'inactive' && (\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tclassName=\"odometer-digit odometer-child\"\n\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\tposition: offsetWidth ? 'absolute' : 'relative',\n\t\t\t\t\t\t\t\t\t\ttop: offsetWidth ? 0 : undefined,\n\t\t\t\t\t\t\t\t\t\tleft: offsetWidth ? 0 : undefined,\n\t\t\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\t\twidth: offsetWidth ? `${offsetWidth}px` : 'auto',\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{status === 'transition' && childDigits}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)\n\t\t\t\t})}\n\t\t\t\t{spaceAfter ? <span style={{ paddingRight: spaceAfter }} /> : null}\n\t\t\t</span>\n\t\t</span>\n\t)\n}\n\nexport default Odometer\n"],"mappings":"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","names":["v"]}
1
+ {"version":3,"sources":["../src/index.tsx"],"sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { RefObject } from 'react'\nimport { createRef, useEffect, useRef, useState } from 'react'\nimport './index.css'\nimport type { Digit, DigitRef, Direction, Props, Status } from './types'\n\nexport const Odometer = ({\n\tvalue,\n\tspaceBefore = 0,\n\tspaceAfter = '0.25rem',\n\twholeColor = 'var(--text-color-primary)',\n\tdecimalColor = 'var(--text-color-secondary)',\n\tzeroDecimals = 0,\n}: Props) => {\n\t// Store all possible digits.\n\tconst [allDigits] = useState<Digit[]>([\n\t\t'comma',\n\t\t'dot',\n\t\t'0',\n\t\t'1',\n\t\t'2',\n\t\t'3',\n\t\t'4',\n\t\t'5',\n\t\t'6',\n\t\t'7',\n\t\t'8',\n\t\t'9',\n\t])\n\n\t// Store the digits of the current value.\n\tconst [digits, setDigits] = useState<Digit[]>([])\n\n\t// Store digits of the previous value.\n\tconst [prevDigits, setPrevDigits] = useState<Digit[]>([])\n\n\t// Store the status of the odometer (transitioning or stable).\n\tconst [status, setStatus] = useState<Status>('inactive')\n\n\t// Store whether component has iniiialized.\n\tconst [initialized, setInitialized] = useState<boolean>(false)\n\n\t// Store ref of the odometer.\n\tconst [odometerRef] = useState(createRef<HTMLSpanElement>())\n\n\t// Store refs of each digit.\n\tconst [digitRefs, setDigitRefs] = useState<DigitRef[]>([])\n\n\t// Store refs of each `all` digit.\n\tconst [allDigitRefs, setAllDigitRefs] = useState<\n\t\tRecord<string, RefObject<HTMLSpanElement | null>>\n\t>({})\n\n\t// Keep track of active transitions.\n\tconst activeTransitionCounter = useRef<number>(0)\n\n\t// Transition duration.\n\tconst DURATION_MS = 750\n\tconst DURATION_SECS = `${DURATION_MS / 1000}s`\n\n\t// Phase 0: populate `allDigitRefs`.\n\tuseEffect(() => {\n\t\tconst all: Record<\n\t\t\tstring,\n\t\t\tRefObject<HTMLSpanElement | null>\n\t\t> = Object.fromEntries(\n\t\t\tObject.values(allDigits).map((v) => [`d_${v}`, createRef()]),\n\t\t)\n\n\t\tsetAllDigitRefs(all)\n\t}, [])\n\n\t// Phase 1: new digits and refs are added to the odometer.\n\tuseEffect(() => {\n\t\tif (Object.keys(allDigitRefs)) {\n\t\t\tvalue =\n\t\t\t\tString(value) === '0' ? Number(value).toFixed(zeroDecimals) : value\n\n\t\t\tconst newDigits = value\n\t\t\t\t.toString()\n\t\t\t\t.split('')\n\t\t\t\t.map((v) => (v === '.' ? 'dot' : v))\n\t\t\t\t.map((v) => (v === ',' ? 'comma' : v)) as Digit[]\n\n\t\t\tsetDigits(newDigits)\n\n\t\t\tif (!initialized) {\n\t\t\t\tsetInitialized(true)\n\t\t\t} else {\n\t\t\t\tsetStatus('new')\n\t\t\t\tsetPrevDigits(digits)\n\t\t\t}\n\t\t\tsetDigitRefs(\n\t\t\t\tArray.from({ length: newDigits.length }, () => createRef() as DigitRef),\n\t\t\t)\n\t\t}\n\t}, [value])\n\n\t// Phase 2: set up digit transition.\n\tuseEffect(() => {\n\t\tif (status === 'new' && !digitRefs.find((d) => d.current === null)) {\n\t\t\tsetStatus('transition')\n\t\t\tactiveTransitionCounter.current++\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tactiveTransitionCounter.current--\n\t\t\t\tif (activeTransitionCounter.current === 0) {\n\t\t\t\t\tsetStatus('inactive')\n\t\t\t\t}\n\t\t\t}, DURATION_MS)\n\t\t}\n\t}, [status, digitRefs])\n\n\tconst odometerCurrent: HTMLSpanElement | null = odometerRef.current\n\tlet lineHeight = odometerCurrent\n\t\t? window.getComputedStyle(odometerCurrent).lineHeight\n\t\t: 'inherit'\n\n\t// Fallback line height to `1.1rem` if `normal`.\n\tlineHeight = lineHeight === 'normal' ? '1.1rem' : lineHeight\n\n\t// Track whether decimal point has been found.\n\tlet foundDecimal = false\n\n\treturn (\n\t\t<span className=\"odometer\">\n\t\t\t<span className=\"odometer-inner\" ref={odometerRef}>\n\t\t\t\t{allDigits.map((d, i) => (\n\t\t\t\t\t<span\n\t\t\t\t\t\tkey={`odometer_template_digit_${i}`}\n\t\t\t\t\t\tref={allDigitRefs[`d_${d}`]}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\t\t\ttop: '-999%',\n\t\t\t\t\t\t\tleft: '-999%',\n\t\t\t\t\t\t\tuserSelect: 'none',\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\n\t\t\t\t\t</span>\n\t\t\t\t))}\n\n\t\t\t\t{spaceBefore ? <span style={{ paddingLeft: spaceBefore }} /> : null}\n\t\t\t\t{digits.map((d, i) => {\n\t\t\t\t\tif (d === 'dot') {\n\t\t\t\t\t\tfoundDecimal = true\n\t\t\t\t\t}\n\n\t\t\t\t\t// If transitioning, get digits needed to animate.\n\t\t\t\t\tlet childDigits = null\n\t\t\t\t\tif (status === 'transition') {\n\t\t\t\t\t\tconst digitsToAnimate = []\n\t\t\t\t\t\tconst digitIndex = allDigits.indexOf(digits[i])\n\t\t\t\t\t\tconst prevDigitIndex = allDigits.indexOf(prevDigits[i])\n\t\t\t\t\t\tconst difference = Math.abs(digitIndex - prevDigitIndex)\n\t\t\t\t\t\tconst delay = `${0.01 * (digits.length - i - 1)}s`\n\t\t\t\t\t\tconst direction: Direction =\n\t\t\t\t\t\t\tdigitIndex === prevDigitIndex ? 'none' : 'down'\n\t\t\t\t\t\tconst animClass = `slide-${direction}-${difference} `\n\n\t\t\t\t\t\t// Push current prev digit to stop of stack.\n\t\t\t\t\t\tdigitsToAnimate.push(prevDigits[i])\n\n\t\t\t\t\t\t// If transitioning between two digits, animate all digits in between.\n\t\t\t\t\t\tif (digitIndex < prevDigitIndex) {\n\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t(_, k) => allDigits[prevDigitIndex - k - 1],\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t(_, k) => allDigits[k + prevDigitIndex + 1],\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tchildDigits = (\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\t\t\t\tanimationName: direction === 'none' ? undefined : animClass,\n\t\t\t\t\t\t\t\t\tanimationDuration:\n\t\t\t\t\t\t\t\t\t\tdirection === 'none' ? undefined : DURATION_SECS,\n\t\t\t\t\t\t\t\t\tanimationFillMode: 'forwards',\n\t\t\t\t\t\t\t\t\tanimationTimingFunction: 'cubic-bezier(0.1, 1, 0.2, 1)',\n\t\t\t\t\t\t\t\t\tanimationDelay: delay,\n\t\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\t\tuserSelect: 'none',\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{digitsToAnimate.map((c, j) => (\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tkey={`child_digit_${j}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"odometer-digit odometer-child\"\n\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\ttop: j === 0 ? 0 : `${100 * j}%`,\n\t\t\t\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{c === 'dot' ? '.' : c === 'comma' ? ',' : c}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tkey={`digit_${i}`}\n\t\t\t\t\t\t\tref={digitRefs[i]}\n\t\t\t\t\t\t\tclassName=\"odometer-digit\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\tpaddingRight:\n\t\t\t\t\t\t\t\t\tstatus === 'transition'\n\t\t\t\t\t\t\t\t\t\t? `${allDigitRefs[`d_${d}`]?.current?.offsetWidth}px`\n\t\t\t\t\t\t\t\t\t\t: '0',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{status === 'inactive' && (\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tclassName=\"odometer-digit odometer-child\"\n\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\t\twidth: `${allDigitRefs[`d_${d}`]?.current?.offsetWidth}px`,\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{status === 'transition' && childDigits}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)\n\t\t\t\t})}\n\t\t\t\t{spaceAfter ? <span style={{ paddingRight: spaceAfter }} /> : null}\n\t\t\t</span>\n\t\t</span>\n\t)\n}\n\nexport default Odometer\n"],"mappings":"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","names":[]}
package/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  // src/index.tsx
2
2
  import { createRef, useEffect, useRef, useState } from "react";
3
- import { useEffectIgnoreInitial } from "@w3ux/hooks";
4
3
  import { jsx, jsxs } from "react/jsx-runtime";
5
4
  var Odometer = ({
6
5
  value,
@@ -30,45 +29,31 @@ var Odometer = ({
30
29
  const [initialized, setInitialized] = useState(false);
31
30
  const [odometerRef] = useState(createRef());
32
31
  const [digitRefs, setDigitRefs] = useState([]);
33
- const digitWidths = useRef({});
32
+ const [allDigitRefs, setAllDigitRefs] = useState({});
34
33
  const activeTransitionCounter = useRef(0);
35
34
  const DURATION_MS = 750;
36
35
  const DURATION_SECS = `${DURATION_MS / 1e3}s`;
37
- const handleValueDigitRefs = (v) => {
38
- v = String(v) === "0" ? Number(v).toFixed(zeroDecimals) : v;
39
- const newDigits = v.toString().split("").map((v2) => v2 === "." ? "dot" : v2).map((v2) => v2 === "," ? "comma" : v2);
40
- setDigits(newDigits);
41
- if (!initialized) {
42
- setInitialized(true);
43
- } else {
44
- setStatus("new");
45
- setPrevDigits(digits);
46
- }
47
- setDigitRefs(
48
- Array.from({ length: newDigits.length }, () => createRef())
49
- );
50
- };
51
36
  useEffect(() => {
52
- handleValueDigitRefs(value);
37
+ const all = Object.fromEntries(
38
+ Object.values(allDigits).map((v) => [`d_${v}`, createRef()])
39
+ );
40
+ setAllDigitRefs(all);
53
41
  }, []);
54
42
  useEffect(() => {
55
- if (digitRefs.length > 0 && !digitRefs.find((d) => d.current === null)) {
56
- digitRefs.forEach((ref, i) => {
57
- if (ref.current) {
58
- const childSpan = ref.current.querySelector(
59
- ".odometer-child"
60
- );
61
- const width = childSpan?.offsetWidth;
62
- const digit = digits[i];
63
- if (width && !digitWidths.current[digit]) {
64
- digitWidths.current[digit] = width;
65
- }
66
- }
67
- });
43
+ if (Object.keys(allDigitRefs)) {
44
+ value = String(value) === "0" ? Number(value).toFixed(zeroDecimals) : value;
45
+ const newDigits = value.toString().split("").map((v) => v === "." ? "dot" : v).map((v) => v === "," ? "comma" : v);
46
+ setDigits(newDigits);
47
+ if (!initialized) {
48
+ setInitialized(true);
49
+ } else {
50
+ setStatus("new");
51
+ setPrevDigits(digits);
52
+ }
53
+ setDigitRefs(
54
+ Array.from({ length: newDigits.length }, () => createRef())
55
+ );
68
56
  }
69
- }, [digitRefs, digits]);
70
- useEffectIgnoreInitial(() => {
71
- handleValueDigitRefs(value);
72
57
  }, [value]);
73
58
  useEffect(() => {
74
59
  if (status === "new" && !digitRefs.find((d) => d.current === null)) {
@@ -87,6 +72,21 @@ var Odometer = ({
87
72
  lineHeight = lineHeight === "normal" ? "1.1rem" : lineHeight;
88
73
  let foundDecimal = false;
89
74
  return /* @__PURE__ */ jsx("span", { className: "odometer", children: /* @__PURE__ */ jsxs("span", { className: "odometer-inner", ref: odometerRef, children: [
75
+ allDigits.map((d, i) => /* @__PURE__ */ jsx(
76
+ "span",
77
+ {
78
+ ref: allDigitRefs[`d_${d}`],
79
+ style: {
80
+ opacity: 0,
81
+ position: "fixed",
82
+ top: "-999%",
83
+ left: "-999%",
84
+ userSelect: "none"
85
+ },
86
+ children: d === "dot" ? "." : d === "comma" ? "," : d
87
+ },
88
+ `odometer_template_digit_${i}`
89
+ )),
90
90
  spaceBefore ? /* @__PURE__ */ jsx("span", { style: { paddingLeft: spaceBefore } }) : null,
91
91
  digits.map((d, i) => {
92
92
  if (d === "dot") {
@@ -148,7 +148,6 @@ var Odometer = ({
148
148
  }
149
149
  );
150
150
  }
151
- const offsetWidth = digitWidths.current[d];
152
151
  return /* @__PURE__ */ jsxs(
153
152
  "span",
154
153
  {
@@ -158,7 +157,7 @@ var Odometer = ({
158
157
  color: foundDecimal ? decimalColor : wholeColor,
159
158
  height: lineHeight,
160
159
  lineHeight,
161
- minWidth: offsetWidth ? `${offsetWidth}px` : void 0
160
+ paddingRight: status === "transition" ? `${allDigitRefs[`d_${d}`]?.current?.offsetWidth}px` : "0"
162
161
  },
163
162
  children: [
164
163
  status === "inactive" && /* @__PURE__ */ jsx(
@@ -166,12 +165,10 @@ var Odometer = ({
166
165
  {
167
166
  className: "odometer-digit odometer-child",
168
167
  style: {
169
- position: offsetWidth ? "absolute" : "relative",
170
- top: offsetWidth ? 0 : void 0,
171
- left: offsetWidth ? 0 : void 0,
168
+ top: 0,
172
169
  height: lineHeight,
173
170
  lineHeight,
174
- width: offsetWidth ? `${offsetWidth}px` : "auto"
171
+ width: `${allDigitRefs[`d_${d}`]?.current?.offsetWidth}px`
175
172
  },
176
173
  children: d === "dot" ? "." : d === "comma" ? "," : d
177
174
  }
package/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx"],"sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { createRef, useEffect, useRef, useState } from 'react'\nimport './index.css'\nimport { useEffectIgnoreInitial } from '@w3ux/hooks'\nimport type { Digit, DigitRef, Direction, Props, Status } from './types'\n\nexport const Odometer = ({\n\tvalue,\n\tspaceBefore = 0,\n\tspaceAfter = '0.25rem',\n\twholeColor = 'var(--text-color-primary)',\n\tdecimalColor = 'var(--text-color-secondary)',\n\tzeroDecimals = 0,\n}: Props) => {\n\t// Store all possible digits.\n\tconst [allDigits] = useState<Digit[]>([\n\t\t'comma',\n\t\t'dot',\n\t\t'0',\n\t\t'1',\n\t\t'2',\n\t\t'3',\n\t\t'4',\n\t\t'5',\n\t\t'6',\n\t\t'7',\n\t\t'8',\n\t\t'9',\n\t])\n\n\t// Store the digits of the current value.\n\tconst [digits, setDigits] = useState<Digit[]>([])\n\n\t// Store digits of the previous value.\n\tconst [prevDigits, setPrevDigits] = useState<Digit[]>([])\n\n\t// Store the status of the odometer (transitioning or stable).\n\tconst [status, setStatus] = useState<Status>('inactive')\n\n\t// Store whether component has initialized.\n\tconst [initialized, setInitialized] = useState<boolean>(false)\n\n\t// Store ref of the odometer.\n\tconst [odometerRef] = useState(createRef<HTMLSpanElement>())\n\n\t// Store refs of each digit.\n\tconst [digitRefs, setDigitRefs] = useState<DigitRef[]>([])\n\n\t// Store measured widths for each digit character.\n\tconst digitWidths = useRef<Record<string, number>>({})\n\n\t// Keep track of active transitions.\n\tconst activeTransitionCounter = useRef<number>(0)\n\n\t// Transition duration.\n\tconst DURATION_MS = 750\n\tconst DURATION_SECS = `${DURATION_MS / 1000}s`\n\n\t// Set digit refs for a value.\n\tconst handleValueDigitRefs = (v: string | number) => {\n\t\tv = String(v) === '0' ? Number(v).toFixed(zeroDecimals) : v\n\n\t\tconst newDigits = v\n\t\t\t.toString()\n\t\t\t.split('')\n\t\t\t.map((v) => (v === '.' ? 'dot' : v))\n\t\t\t.map((v) => (v === ',' ? 'comma' : v)) as Digit[]\n\n\t\tsetDigits(newDigits)\n\n\t\tif (!initialized) {\n\t\t\tsetInitialized(true)\n\t\t} else {\n\t\t\tsetStatus('new')\n\t\t\tsetPrevDigits(digits)\n\t\t}\n\t\tsetDigitRefs(\n\t\t\tArray.from({ length: newDigits.length }, () => createRef() as DigitRef),\n\t\t)\n\t}\n\n\t// Phase 0: initialize with first value.\n\tuseEffect(() => {\n\t\thandleValueDigitRefs(value)\n\t}, [])\n\n\t// Phase 1: measure digit widths after refs are attached.\n\tuseEffect(() => {\n\t\tif (digitRefs.length > 0 && !digitRefs.find((d) => d.current === null)) {\n\t\t\tdigitRefs.forEach((ref, i) => {\n\t\t\t\tif (ref.current) {\n\t\t\t\t\t// Measure the child span's width\n\t\t\t\t\tconst childSpan = ref.current.querySelector(\n\t\t\t\t\t\t'.odometer-child',\n\t\t\t\t\t) as HTMLSpanElement\n\t\t\t\t\tconst width = childSpan?.offsetWidth\n\t\t\t\t\tconst digit = digits[i]\n\t\t\t\t\tif (width && !digitWidths.current[digit]) {\n\t\t\t\t\t\tdigitWidths.current[digit] = width\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}, [digitRefs, digits])\n\n\t// Phase 2: new digits and refs are added to the odometer.\n\tuseEffectIgnoreInitial(() => {\n\t\thandleValueDigitRefs(value)\n\t}, [value])\n\n\t// Phase 3: set up digit transition.\n\tuseEffect(() => {\n\t\tif (status === 'new' && !digitRefs.find((d) => d.current === null)) {\n\t\t\tsetStatus('transition')\n\t\t\tactiveTransitionCounter.current++\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tactiveTransitionCounter.current--\n\t\t\t\tif (activeTransitionCounter.current === 0) {\n\t\t\t\t\tsetStatus('inactive')\n\t\t\t\t}\n\t\t\t}, DURATION_MS)\n\t\t}\n\t}, [status, digitRefs])\n\n\tconst odometerCurrent: HTMLSpanElement | null = odometerRef.current\n\tlet lineHeight = odometerCurrent\n\t\t? window.getComputedStyle(odometerCurrent).lineHeight\n\t\t: 'inherit'\n\n\t// Fallback line height to `1.1rem` if `normal`.\n\tlineHeight = lineHeight === 'normal' ? '1.1rem' : lineHeight\n\n\t// Track whether decimal point has been found.\n\tlet foundDecimal = false\n\n\treturn (\n\t\t<span className=\"odometer\">\n\t\t\t<span className=\"odometer-inner\" ref={odometerRef}>\n\t\t\t\t{spaceBefore ? <span style={{ paddingLeft: spaceBefore }} /> : null}\n\t\t\t\t{digits.map((d, i) => {\n\t\t\t\t\tif (d === 'dot') {\n\t\t\t\t\t\tfoundDecimal = true\n\t\t\t\t\t}\n\n\t\t\t\t\t// If transitioning, get digits needed to animate.\n\t\t\t\t\tlet childDigits = null\n\t\t\t\t\tif (status === 'transition') {\n\t\t\t\t\t\tconst digitsToAnimate = []\n\t\t\t\t\t\tconst digitIndex = allDigits.indexOf(digits[i])\n\t\t\t\t\t\tconst prevDigitIndex = allDigits.indexOf(prevDigits[i])\n\t\t\t\t\t\tconst difference = Math.abs(digitIndex - prevDigitIndex)\n\t\t\t\t\t\tconst delay = `${0.01 * (digits.length - i - 1)}s`\n\t\t\t\t\t\tconst direction: Direction =\n\t\t\t\t\t\t\tdigitIndex === prevDigitIndex ? 'none' : 'down'\n\t\t\t\t\t\tconst animClass = `slide-${direction}-${difference} `\n\n\t\t\t\t\t\t// Push current prev digit to stop of stack.\n\t\t\t\t\t\tdigitsToAnimate.push(prevDigits[i])\n\n\t\t\t\t\t\t// If transitioning between two digits, animate all digits in between.\n\t\t\t\t\t\tif (digitIndex < prevDigitIndex) {\n\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t(_, k) => allDigits[prevDigitIndex - k - 1],\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t(_, k) => allDigits[k + prevDigitIndex + 1],\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tchildDigits = (\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\t\t\t\tanimationName: direction === 'none' ? undefined : animClass,\n\t\t\t\t\t\t\t\t\tanimationDuration:\n\t\t\t\t\t\t\t\t\t\tdirection === 'none' ? undefined : DURATION_SECS,\n\t\t\t\t\t\t\t\t\tanimationFillMode: 'forwards',\n\t\t\t\t\t\t\t\t\tanimationTimingFunction: 'cubic-bezier(0.1, 1, 0.2, 1)',\n\t\t\t\t\t\t\t\t\tanimationDelay: delay,\n\t\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\t\tuserSelect: 'none',\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{digitsToAnimate.map((c, j) => (\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tkey={`child_digit_${j}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"odometer-digit odometer-child\"\n\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\ttop: j === 0 ? 0 : `${100 * j}%`,\n\t\t\t\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{c === 'dot' ? '.' : c === 'comma' ? ',' : c}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst offsetWidth = digitWidths.current[d]\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tkey={`digit_${i}`}\n\t\t\t\t\t\t\tref={digitRefs[i]}\n\t\t\t\t\t\t\tclassName=\"odometer-digit\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\tminWidth: offsetWidth ? `${offsetWidth}px` : undefined,\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{status === 'inactive' && (\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tclassName=\"odometer-digit odometer-child\"\n\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\tposition: offsetWidth ? 'absolute' : 'relative',\n\t\t\t\t\t\t\t\t\t\ttop: offsetWidth ? 0 : undefined,\n\t\t\t\t\t\t\t\t\t\tleft: offsetWidth ? 0 : undefined,\n\t\t\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\t\twidth: offsetWidth ? `${offsetWidth}px` : 'auto',\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{status === 'transition' && childDigits}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)\n\t\t\t\t})}\n\t\t\t\t{spaceAfter ? <span style={{ paddingRight: spaceAfter }} /> : null}\n\t\t\t</span>\n\t\t</span>\n\t)\n}\n\nexport default Odometer\n"],"mappings":"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","names":["v"]}
1
+ {"version":3,"sources":["../src/index.tsx"],"sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { RefObject } from 'react'\nimport { createRef, useEffect, useRef, useState } from 'react'\nimport './index.css'\nimport type { Digit, DigitRef, Direction, Props, Status } from './types'\n\nexport const Odometer = ({\n\tvalue,\n\tspaceBefore = 0,\n\tspaceAfter = '0.25rem',\n\twholeColor = 'var(--text-color-primary)',\n\tdecimalColor = 'var(--text-color-secondary)',\n\tzeroDecimals = 0,\n}: Props) => {\n\t// Store all possible digits.\n\tconst [allDigits] = useState<Digit[]>([\n\t\t'comma',\n\t\t'dot',\n\t\t'0',\n\t\t'1',\n\t\t'2',\n\t\t'3',\n\t\t'4',\n\t\t'5',\n\t\t'6',\n\t\t'7',\n\t\t'8',\n\t\t'9',\n\t])\n\n\t// Store the digits of the current value.\n\tconst [digits, setDigits] = useState<Digit[]>([])\n\n\t// Store digits of the previous value.\n\tconst [prevDigits, setPrevDigits] = useState<Digit[]>([])\n\n\t// Store the status of the odometer (transitioning or stable).\n\tconst [status, setStatus] = useState<Status>('inactive')\n\n\t// Store whether component has iniiialized.\n\tconst [initialized, setInitialized] = useState<boolean>(false)\n\n\t// Store ref of the odometer.\n\tconst [odometerRef] = useState(createRef<HTMLSpanElement>())\n\n\t// Store refs of each digit.\n\tconst [digitRefs, setDigitRefs] = useState<DigitRef[]>([])\n\n\t// Store refs of each `all` digit.\n\tconst [allDigitRefs, setAllDigitRefs] = useState<\n\t\tRecord<string, RefObject<HTMLSpanElement | null>>\n\t>({})\n\n\t// Keep track of active transitions.\n\tconst activeTransitionCounter = useRef<number>(0)\n\n\t// Transition duration.\n\tconst DURATION_MS = 750\n\tconst DURATION_SECS = `${DURATION_MS / 1000}s`\n\n\t// Phase 0: populate `allDigitRefs`.\n\tuseEffect(() => {\n\t\tconst all: Record<\n\t\t\tstring,\n\t\t\tRefObject<HTMLSpanElement | null>\n\t\t> = Object.fromEntries(\n\t\t\tObject.values(allDigits).map((v) => [`d_${v}`, createRef()]),\n\t\t)\n\n\t\tsetAllDigitRefs(all)\n\t}, [])\n\n\t// Phase 1: new digits and refs are added to the odometer.\n\tuseEffect(() => {\n\t\tif (Object.keys(allDigitRefs)) {\n\t\t\tvalue =\n\t\t\t\tString(value) === '0' ? Number(value).toFixed(zeroDecimals) : value\n\n\t\t\tconst newDigits = value\n\t\t\t\t.toString()\n\t\t\t\t.split('')\n\t\t\t\t.map((v) => (v === '.' ? 'dot' : v))\n\t\t\t\t.map((v) => (v === ',' ? 'comma' : v)) as Digit[]\n\n\t\t\tsetDigits(newDigits)\n\n\t\t\tif (!initialized) {\n\t\t\t\tsetInitialized(true)\n\t\t\t} else {\n\t\t\t\tsetStatus('new')\n\t\t\t\tsetPrevDigits(digits)\n\t\t\t}\n\t\t\tsetDigitRefs(\n\t\t\t\tArray.from({ length: newDigits.length }, () => createRef() as DigitRef),\n\t\t\t)\n\t\t}\n\t}, [value])\n\n\t// Phase 2: set up digit transition.\n\tuseEffect(() => {\n\t\tif (status === 'new' && !digitRefs.find((d) => d.current === null)) {\n\t\t\tsetStatus('transition')\n\t\t\tactiveTransitionCounter.current++\n\n\t\t\tsetTimeout(() => {\n\t\t\t\tactiveTransitionCounter.current--\n\t\t\t\tif (activeTransitionCounter.current === 0) {\n\t\t\t\t\tsetStatus('inactive')\n\t\t\t\t}\n\t\t\t}, DURATION_MS)\n\t\t}\n\t}, [status, digitRefs])\n\n\tconst odometerCurrent: HTMLSpanElement | null = odometerRef.current\n\tlet lineHeight = odometerCurrent\n\t\t? window.getComputedStyle(odometerCurrent).lineHeight\n\t\t: 'inherit'\n\n\t// Fallback line height to `1.1rem` if `normal`.\n\tlineHeight = lineHeight === 'normal' ? '1.1rem' : lineHeight\n\n\t// Track whether decimal point has been found.\n\tlet foundDecimal = false\n\n\treturn (\n\t\t<span className=\"odometer\">\n\t\t\t<span className=\"odometer-inner\" ref={odometerRef}>\n\t\t\t\t{allDigits.map((d, i) => (\n\t\t\t\t\t<span\n\t\t\t\t\t\tkey={`odometer_template_digit_${i}`}\n\t\t\t\t\t\tref={allDigitRefs[`d_${d}`]}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\t\t\ttop: '-999%',\n\t\t\t\t\t\t\tleft: '-999%',\n\t\t\t\t\t\t\tuserSelect: 'none',\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\n\t\t\t\t\t</span>\n\t\t\t\t))}\n\n\t\t\t\t{spaceBefore ? <span style={{ paddingLeft: spaceBefore }} /> : null}\n\t\t\t\t{digits.map((d, i) => {\n\t\t\t\t\tif (d === 'dot') {\n\t\t\t\t\t\tfoundDecimal = true\n\t\t\t\t\t}\n\n\t\t\t\t\t// If transitioning, get digits needed to animate.\n\t\t\t\t\tlet childDigits = null\n\t\t\t\t\tif (status === 'transition') {\n\t\t\t\t\t\tconst digitsToAnimate = []\n\t\t\t\t\t\tconst digitIndex = allDigits.indexOf(digits[i])\n\t\t\t\t\t\tconst prevDigitIndex = allDigits.indexOf(prevDigits[i])\n\t\t\t\t\t\tconst difference = Math.abs(digitIndex - prevDigitIndex)\n\t\t\t\t\t\tconst delay = `${0.01 * (digits.length - i - 1)}s`\n\t\t\t\t\t\tconst direction: Direction =\n\t\t\t\t\t\t\tdigitIndex === prevDigitIndex ? 'none' : 'down'\n\t\t\t\t\t\tconst animClass = `slide-${direction}-${difference} `\n\n\t\t\t\t\t\t// Push current prev digit to stop of stack.\n\t\t\t\t\t\tdigitsToAnimate.push(prevDigits[i])\n\n\t\t\t\t\t\t// If transitioning between two digits, animate all digits in between.\n\t\t\t\t\t\tif (digitIndex < prevDigitIndex) {\n\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t(_, k) => allDigits[prevDigitIndex - k - 1],\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t(_, k) => allDigits[k + prevDigitIndex + 1],\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tchildDigits = (\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\t\t\t\tanimationName: direction === 'none' ? undefined : animClass,\n\t\t\t\t\t\t\t\t\tanimationDuration:\n\t\t\t\t\t\t\t\t\t\tdirection === 'none' ? undefined : DURATION_SECS,\n\t\t\t\t\t\t\t\t\tanimationFillMode: 'forwards',\n\t\t\t\t\t\t\t\t\tanimationTimingFunction: 'cubic-bezier(0.1, 1, 0.2, 1)',\n\t\t\t\t\t\t\t\t\tanimationDelay: delay,\n\t\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\t\tuserSelect: 'none',\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{digitsToAnimate.map((c, j) => (\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tkey={`child_digit_${j}`}\n\t\t\t\t\t\t\t\t\t\tclassName=\"odometer-digit odometer-child\"\n\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\t\ttop: j === 0 ? 0 : `${100 * j}%`,\n\t\t\t\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{c === 'dot' ? '.' : c === 'comma' ? ',' : c}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tkey={`digit_${i}`}\n\t\t\t\t\t\t\tref={digitRefs[i]}\n\t\t\t\t\t\t\tclassName=\"odometer-digit\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\tpaddingRight:\n\t\t\t\t\t\t\t\t\tstatus === 'transition'\n\t\t\t\t\t\t\t\t\t\t? `${allDigitRefs[`d_${d}`]?.current?.offsetWidth}px`\n\t\t\t\t\t\t\t\t\t\t: '0',\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{status === 'inactive' && (\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tclassName=\"odometer-digit odometer-child\"\n\t\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\t\twidth: `${allDigitRefs[`d_${d}`]?.current?.offsetWidth}px`,\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{status === 'transition' && childDigits}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)\n\t\t\t\t})}\n\t\t\t\t{spaceAfter ? <span style={{ paddingRight: spaceAfter }} /> : null}\n\t\t\t</span>\n\t\t</span>\n\t)\n}\n\nexport default Odometer\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@w3ux/react-odometer",
3
- "version": "2.3.10",
3
+ "version": "2.3.12",
4
4
  "license": "GPL-3.0-only",
5
5
  "type": "module",
6
6
  "description": "An odometer effect used for number and balance transitions",
@@ -33,9 +33,6 @@
33
33
  "require": "./index.css"
34
34
  }
35
35
  },
36
- "dependencies": {
37
- "@w3ux/hooks": "^2.4.0"
38
- },
39
36
  "peerDependencies": {
40
37
  "react": "^19.1.0",
41
38
  "react-dom": "^19.1.0"