@w3ux/react-odometer 2.3.9 → 2.3.10
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 +7 -4
- package/index.cjs.map +1 -1
- package/index.js +7 -4
- package/index.js.map +1 -1
- package/package.json +1 -1
package/index.cjs
CHANGED
|
@@ -80,7 +80,10 @@ var Odometer = ({
|
|
|
80
80
|
if (digitRefs.length > 0 && !digitRefs.find((d) => d.current === null)) {
|
|
81
81
|
digitRefs.forEach((ref, i) => {
|
|
82
82
|
if (ref.current) {
|
|
83
|
-
const
|
|
83
|
+
const childSpan = ref.current.querySelector(
|
|
84
|
+
".odometer-child"
|
|
85
|
+
);
|
|
86
|
+
const width = childSpan?.offsetWidth;
|
|
84
87
|
const digit = digits[i];
|
|
85
88
|
if (width && !digitWidths.current[digit]) {
|
|
86
89
|
digitWidths.current[digit] = width;
|
|
@@ -188,9 +191,9 @@ var Odometer = ({
|
|
|
188
191
|
{
|
|
189
192
|
className: "odometer-digit odometer-child",
|
|
190
193
|
style: {
|
|
191
|
-
position: "absolute",
|
|
192
|
-
top: 0,
|
|
193
|
-
left: 0,
|
|
194
|
+
position: offsetWidth ? "absolute" : "relative",
|
|
195
|
+
top: offsetWidth ? 0 : void 0,
|
|
196
|
+
left: offsetWidth ? 0 : void 0,
|
|
194
197
|
height: lineHeight,
|
|
195
198
|
lineHeight,
|
|
196
199
|
width: offsetWidth ? `${offsetWidth}px` : "auto"
|
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\tconst width = ref.current.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: 'absolute',\n\t\t\t\t\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\t\t\t\t\tleft: 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: 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 { 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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,mBAAuD;AAEvD,mBAAuC;AAwIpB;AArIZ,IAAM,WAAW,CAAC;AAAA,EACxB;AAAA,EACA,cAAc;AAAA,EACd,aAAa;AAAA,EACb,aAAa;AAAA,EACb,eAAe;AAAA,EACf,eAAe;AAChB,MAAa;AAEZ,QAAM,CAAC,SAAS,QAAI,uBAAkB;AAAA,IACrC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,CAAC;AAGD,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAkB,CAAC,CAAC;AAGhD,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAkB,CAAC,CAAC;AAGxD,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAiB,UAAU;AAGvD,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAkB,KAAK;AAG7D,QAAM,CAAC,WAAW,QAAI,2BAAS,wBAA2B,CAAC;AAG3D,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAqB,CAAC,CAAC;AAGzD,QAAM,kBAAc,qBAA+B,CAAC,CAAC;AAGrD,QAAM,8BAA0B,qBAAe,CAAC;AAGhD,QAAM,cAAc;AACpB,QAAM,gBAAgB,GAAG,cAAc,GAAI;AAG3C,QAAM,uBAAuB,CAAC,MAAuB;AACpD,QAAI,OAAO,CAAC,MAAM,MAAM,OAAO,CAAC,EAAE,QAAQ,YAAY,IAAI;AAE1D,UAAM,YAAY,EAChB,SAAS,EACT,MAAM,EAAE,EACR,IAAI,CAACA,OAAOA,OAAM,MAAM,QAAQA,EAAE,EAClC,IAAI,CAACA,OAAOA,OAAM,MAAM,UAAUA,EAAE;AAEtC,cAAU,SAAS;AAEnB,QAAI,CAAC,aAAa;AACjB,qBAAe,IAAI;AAAA,IACpB,OAAO;AACN,gBAAU,KAAK;AACf,oBAAc,MAAM;AAAA,IACrB;AACA;AAAA,MACC,MAAM,KAAK,EAAE,QAAQ,UAAU,OAAO,GAAG,UAAM,wBAAU,CAAa;AAAA,IACvE;AAAA,EACD;AAGA,8BAAU,MAAM;AACf,yBAAqB,KAAK;AAAA,EAC3B,GAAG,CAAC,CAAC;AAGL,8BAAU,MAAM;AACf,QAAI,UAAU,SAAS,KAAK,CAAC,UAAU,KAAK,CAAC,MAAM,EAAE,YAAY,IAAI,GAAG;AACvE,gBAAU,QAAQ,CAAC,KAAK,MAAM;AAC7B,YAAI,IAAI,SAAS;AAEhB,gBAAM,YAAY,IAAI,QAAQ;AAAA,YAC7B;AAAA,UACD;AACA,gBAAM,QAAQ,WAAW;AACzB,gBAAM,QAAQ,OAAO,CAAC;AACtB,cAAI,SAAS,CAAC,YAAY,QAAQ,KAAK,GAAG;AACzC,wBAAY,QAAQ,KAAK,IAAI;AAAA,UAC9B;AAAA,QACD;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD,GAAG,CAAC,WAAW,MAAM,CAAC;AAGtB,2CAAuB,MAAM;AAC5B,yBAAqB,KAAK;AAAA,EAC3B,GAAG,CAAC,KAAK,CAAC;AAGV,8BAAU,MAAM;AACf,QAAI,WAAW,SAAS,CAAC,UAAU,KAAK,CAAC,MAAM,EAAE,YAAY,IAAI,GAAG;AACnE,gBAAU,YAAY;AACtB,8BAAwB;AAExB,iBAAW,MAAM;AAChB,gCAAwB;AACxB,YAAI,wBAAwB,YAAY,GAAG;AAC1C,oBAAU,UAAU;AAAA,QACrB;AAAA,MACD,GAAG,WAAW;AAAA,IACf;AAAA,EACD,GAAG,CAAC,QAAQ,SAAS,CAAC;AAEtB,QAAM,kBAA0C,YAAY;AAC5D,MAAI,aAAa,kBACd,OAAO,iBAAiB,eAAe,EAAE,aACzC;AAGH,eAAa,eAAe,WAAW,WAAW;AAGlD,MAAI,eAAe;AAEnB,SACC,4CAAC,UAAK,WAAU,YACf,uDAAC,UAAK,WAAU,kBAAiB,KAAK,aACpC;AAAA,kBAAc,4CAAC,UAAK,OAAO,EAAE,aAAa,YAAY,GAAG,IAAK;AAAA,IAC9D,OAAO,IAAI,CAAC,GAAG,MAAM;AACrB,UAAI,MAAM,OAAO;AAChB,uBAAe;AAAA,MAChB;AAGA,UAAI,cAAc;AAClB,UAAI,WAAW,cAAc;AAC5B,cAAM,kBAAkB,CAAC;AACzB,cAAM,aAAa,UAAU,QAAQ,OAAO,CAAC,CAAC;AAC9C,cAAM,iBAAiB,UAAU,QAAQ,WAAW,CAAC,CAAC;AACtD,cAAM,aAAa,KAAK,IAAI,aAAa,cAAc;AACvD,cAAM,QAAQ,GAAG,QAAQ,OAAO,SAAS,IAAI,EAAE;AAC/C,cAAM,YACL,eAAe,iBAAiB,SAAS;AAC1C,cAAM,YAAY,SAAS,SAAS,IAAI,UAAU;AAGlD,wBAAgB,KAAK,WAAW,CAAC,CAAC;AAGlC,YAAI,aAAa,gBAAgB;AAChC,0BAAgB;AAAA,YACf,GAAG,MAAM;AAAA,cACR,EAAE,QAAQ,WAAW;AAAA,cACrB,CAAC,GAAG,MAAM,UAAU,iBAAiB,IAAI,CAAC;AAAA,YAC3C;AAAA,UACD;AAAA,QACD,OAAO;AACN,0BAAgB;AAAA,YACf,GAAG,MAAM;AAAA,cACR,EAAE,QAAQ,WAAW;AAAA,cACrB,CAAC,GAAG,MAAM,UAAU,IAAI,iBAAiB,CAAC;AAAA,YAC3C;AAAA,UACD;AAAA,QACD;AAEA,sBACC;AAAA,UAAC;AAAA;AAAA,YACA,OAAO;AAAA,cACN,UAAU;AAAA,cACV,KAAK;AAAA,cACL,MAAM;AAAA,cACN,eAAe,cAAc,SAAS,SAAY;AAAA,cAClD,mBACC,cAAc,SAAS,SAAY;AAAA,cACpC,mBAAmB;AAAA,cACnB,yBAAyB;AAAA,cACzB,gBAAgB;AAAA,cAChB,OAAO,eAAe,eAAe;AAAA,cACrC,YAAY;AAAA,YACb;AAAA,YAEC,0BAAgB,IAAI,CAAC,GAAG,MACxB;AAAA,cAAC;AAAA;AAAA,gBAEA,WAAU;AAAA,gBACV,OAAO;AAAA,kBACN,KAAK,MAAM,IAAI,IAAI,GAAG,MAAM,CAAC;AAAA,kBAC7B,QAAQ;AAAA,kBACR;AAAA,gBACD;AAAA,gBAEC,gBAAM,QAAQ,MAAM,MAAM,UAAU,MAAM;AAAA;AAAA,cARtC,eAAe,CAAC;AAAA,YAStB,CACA;AAAA;AAAA,QACF;AAAA,MAEF;AAEA,YAAM,cAAc,YAAY,QAAQ,CAAC;AAEzC,aACC;AAAA,QAAC;AAAA;AAAA,UAEA,KAAK,UAAU,CAAC;AAAA,UAChB,WAAU;AAAA,UACV,OAAO;AAAA,YACN,OAAO,eAAe,eAAe;AAAA,YACrC,QAAQ;AAAA,YACR;AAAA,YACA,UAAU,cAAc,GAAG,WAAW,OAAO;AAAA,UAC9C;AAAA,UAEC;AAAA,uBAAW,cACX;AAAA,cAAC;AAAA;AAAA,gBACA,WAAU;AAAA,gBACV,OAAO;AAAA,kBACN,UAAU,cAAc,aAAa;AAAA,kBACrC,KAAK,cAAc,IAAI;AAAA,kBACvB,MAAM,cAAc,IAAI;AAAA,kBACxB,QAAQ;AAAA,kBACR;AAAA,kBACA,OAAO,cAAc,GAAG,WAAW,OAAO;AAAA,gBAC3C;AAAA,gBAEC,gBAAM,QAAQ,MAAM,MAAM,UAAU,MAAM;AAAA;AAAA,YAC5C;AAAA,YAEA,WAAW,gBAAgB;AAAA;AAAA;AAAA,QAzBvB,SAAS,CAAC;AAAA,MA0BhB;AAAA,IAEF,CAAC;AAAA,IACA,aAAa,4CAAC,UAAK,OAAO,EAAE,cAAc,WAAW,GAAG,IAAK;AAAA,KAC/D,GACD;AAEF;AAEA,IAAO,gBAAQ;","names":["v"]}
|
package/index.js
CHANGED
|
@@ -55,7 +55,10 @@ var Odometer = ({
|
|
|
55
55
|
if (digitRefs.length > 0 && !digitRefs.find((d) => d.current === null)) {
|
|
56
56
|
digitRefs.forEach((ref, i) => {
|
|
57
57
|
if (ref.current) {
|
|
58
|
-
const
|
|
58
|
+
const childSpan = ref.current.querySelector(
|
|
59
|
+
".odometer-child"
|
|
60
|
+
);
|
|
61
|
+
const width = childSpan?.offsetWidth;
|
|
59
62
|
const digit = digits[i];
|
|
60
63
|
if (width && !digitWidths.current[digit]) {
|
|
61
64
|
digitWidths.current[digit] = width;
|
|
@@ -163,9 +166,9 @@ var Odometer = ({
|
|
|
163
166
|
{
|
|
164
167
|
className: "odometer-digit odometer-child",
|
|
165
168
|
style: {
|
|
166
|
-
position: "absolute",
|
|
167
|
-
top: 0,
|
|
168
|
-
left: 0,
|
|
169
|
+
position: offsetWidth ? "absolute" : "relative",
|
|
170
|
+
top: offsetWidth ? 0 : void 0,
|
|
171
|
+
left: offsetWidth ? 0 : void 0,
|
|
169
172
|
height: lineHeight,
|
|
170
173
|
lineHeight,
|
|
171
174
|
width: offsetWidth ? `${offsetWidth}px` : "auto"
|
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\tconst width = ref.current.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: 'absolute',\n\t\t\t\t\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\t\t\t\t\tleft: 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: 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 { 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"]}
|