@w3ux/react-odometer 2.3.3 → 2.3.5

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
@@ -189,7 +189,7 @@ var Odometer = ({
189
189
  color: foundDecimal ? decimalColor : wholeColor,
190
190
  height: lineHeight,
191
191
  lineHeight,
192
- paddingRight: status === "transition" ? `${offsetWidth}px` : "auto"
192
+ paddingRight: offsetWidth ? `${offsetWidth}px` : "0"
193
193
  },
194
194
  children: [
195
195
  status === "inactive" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -199,8 +199,7 @@ var Odometer = ({
199
199
  style: {
200
200
  top: 0,
201
201
  height: lineHeight,
202
- lineHeight,
203
- width: offsetWidth ? `${offsetWidth}px` : "auto"
202
+ lineHeight
204
203
  },
205
204
  children: d === "dot" ? "." : d === "comma" ? "," : d
206
205
  }
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 type { RefObject } from 'react'\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 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// 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: 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\thandleValueDigitRefs(value)\n\t}, [])\n\n\t// Phase 1: new digits and refs are added to the odometer.\n\tuseEffectIgnoreInitial(() => {\n\t\tif (Object.keys(allDigitRefs)) {\n\t\t\thandleValueDigitRefs(value)\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<>\n\t\t\t{allDigits.map((d, i) => (\n\t\t\t\t<span\n\t\t\t\t\tkey={`odometer_template_digit_${i}`}\n\t\t\t\t\tref={allDigitRefs[`d_${d}`]}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\t\ttop: '-999%',\n\t\t\t\t\t\tleft: '-999%',\n\t\t\t\t\t\tuserSelect: 'none',\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\n\t\t\t\t</span>\n\t\t\t))}\n\t\t\t<span className=\"odometer\">\n\t\t\t\t<span className=\"odometer-inner\" ref={odometerRef}>\n\t\t\t\t\t{spaceBefore ? <span style={{ paddingLeft: spaceBefore }} /> : null}\n\t\t\t\t\t{digits.map((d, i) => {\n\t\t\t\t\t\tif (d === 'dot') {\n\t\t\t\t\t\t\tfoundDecimal = true\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If transitioning, get digits needed to animate.\n\t\t\t\t\t\tlet childDigits = null\n\t\t\t\t\t\tif (status === 'transition') {\n\t\t\t\t\t\t\tconst digitsToAnimate = []\n\t\t\t\t\t\t\tconst digitIndex = allDigits.indexOf(digits[i])\n\t\t\t\t\t\t\tconst prevDigitIndex = allDigits.indexOf(prevDigits[i])\n\t\t\t\t\t\t\tconst difference = Math.abs(digitIndex - prevDigitIndex)\n\t\t\t\t\t\t\tconst delay = `${0.01 * (digits.length - i - 1)}s`\n\t\t\t\t\t\t\tconst direction: Direction =\n\t\t\t\t\t\t\t\tdigitIndex === prevDigitIndex ? 'none' : 'down'\n\t\t\t\t\t\t\tconst animClass = `slide-${direction}-${difference} `\n\n\t\t\t\t\t\t\t// Push current prev digit to stop of stack.\n\t\t\t\t\t\t\tdigitsToAnimate.push(prevDigits[i])\n\n\t\t\t\t\t\t\t// If transitioning between two digits, animate all digits in between.\n\t\t\t\t\t\t\tif (digitIndex < prevDigitIndex) {\n\t\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t\t(_, k) => allDigits[prevDigitIndex - k - 1],\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} else {\n\t\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t\t(_, k) => allDigits[k + prevDigitIndex + 1],\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}\n\n\t\t\t\t\t\t\tchildDigits = (\n\t\t\t\t\t\t\t\t<span\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\tanimationName: direction === 'none' ? undefined : animClass,\n\t\t\t\t\t\t\t\t\t\tanimationDuration:\n\t\t\t\t\t\t\t\t\t\t\tdirection === 'none' ? undefined : DURATION_SECS,\n\t\t\t\t\t\t\t\t\t\tanimationFillMode: 'forwards',\n\t\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\t\tanimationDelay: delay,\n\t\t\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\t\t\tuserSelect: 'none',\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{digitsToAnimate.map((c, j) => (\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tkey={`child_digit_${j}`}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"odometer-digit odometer-child\"\n\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\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\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t>\n\t\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\t</span>\n\t\t\t\t\t\t\t\t\t))}\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}\n\n\t\t\t\t\t\tconst offsetWidth = allDigitRefs[`d_${d}`]?.current?.offsetWidth\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tkey={`digit_${i}`}\n\t\t\t\t\t\t\t\tref={digitRefs[i]}\n\t\t\t\t\t\t\t\tclassName=\"odometer-digit\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\tpaddingRight:\n\t\t\t\t\t\t\t\t\t\tstatus === 'transition' ? `${offsetWidth}px` : 'auto',\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{status === 'inactive' && (\n\t\t\t\t\t\t\t\t\t<span\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: 0,\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\twidth: offsetWidth ? `${offsetWidth}px` : 'auto',\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{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\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\t{status === 'transition' && childDigits}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)\n\t\t\t\t\t})}\n\t\t\t\t\t{spaceAfter ? <span style={{ paddingRight: spaceAfter }} /> : null}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t</>\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 { 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 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// 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: 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\thandleValueDigitRefs(value)\n\t}, [])\n\n\t// Phase 1: new digits and refs are added to the odometer.\n\tuseEffectIgnoreInitial(() => {\n\t\tif (Object.keys(allDigitRefs)) {\n\t\t\thandleValueDigitRefs(value)\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<>\n\t\t\t{allDigits.map((d, i) => (\n\t\t\t\t<span\n\t\t\t\t\tkey={`odometer_template_digit_${i}`}\n\t\t\t\t\tref={allDigitRefs[`d_${d}`]}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\t\ttop: '-999%',\n\t\t\t\t\t\tleft: '-999%',\n\t\t\t\t\t\tuserSelect: 'none',\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\n\t\t\t\t</span>\n\t\t\t))}\n\t\t\t<span className=\"odometer\">\n\t\t\t\t<span className=\"odometer-inner\" ref={odometerRef}>\n\t\t\t\t\t{spaceBefore ? <span style={{ paddingLeft: spaceBefore }} /> : null}\n\t\t\t\t\t{digits.map((d, i) => {\n\t\t\t\t\t\tif (d === 'dot') {\n\t\t\t\t\t\t\tfoundDecimal = true\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If transitioning, get digits needed to animate.\n\t\t\t\t\t\tlet childDigits = null\n\t\t\t\t\t\tif (status === 'transition') {\n\t\t\t\t\t\t\tconst digitsToAnimate = []\n\t\t\t\t\t\t\tconst digitIndex = allDigits.indexOf(digits[i])\n\t\t\t\t\t\t\tconst prevDigitIndex = allDigits.indexOf(prevDigits[i])\n\t\t\t\t\t\t\tconst difference = Math.abs(digitIndex - prevDigitIndex)\n\t\t\t\t\t\t\tconst delay = `${0.01 * (digits.length - i - 1)}s`\n\t\t\t\t\t\t\tconst direction: Direction =\n\t\t\t\t\t\t\t\tdigitIndex === prevDigitIndex ? 'none' : 'down'\n\t\t\t\t\t\t\tconst animClass = `slide-${direction}-${difference} `\n\n\t\t\t\t\t\t\t// Push current prev digit to stop of stack.\n\t\t\t\t\t\t\tdigitsToAnimate.push(prevDigits[i])\n\n\t\t\t\t\t\t\t// If transitioning between two digits, animate all digits in between.\n\t\t\t\t\t\t\tif (digitIndex < prevDigitIndex) {\n\t\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t\t(_, k) => allDigits[prevDigitIndex - k - 1],\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} else {\n\t\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t\t(_, k) => allDigits[k + prevDigitIndex + 1],\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}\n\n\t\t\t\t\t\t\tchildDigits = (\n\t\t\t\t\t\t\t\t<span\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\tanimationName: direction === 'none' ? undefined : animClass,\n\t\t\t\t\t\t\t\t\t\tanimationDuration:\n\t\t\t\t\t\t\t\t\t\t\tdirection === 'none' ? undefined : DURATION_SECS,\n\t\t\t\t\t\t\t\t\t\tanimationFillMode: 'forwards',\n\t\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\t\tanimationDelay: delay,\n\t\t\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\t\t\tuserSelect: 'none',\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{digitsToAnimate.map((c, j) => (\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tkey={`child_digit_${j}`}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"odometer-digit odometer-child\"\n\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\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\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t>\n\t\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\t</span>\n\t\t\t\t\t\t\t\t\t))}\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}\n\n\t\t\t\t\t\tconst offsetWidth = allDigitRefs[`d_${d}`]?.current?.offsetWidth\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tkey={`digit_${i}`}\n\t\t\t\t\t\t\t\tref={digitRefs[i]}\n\t\t\t\t\t\t\t\tclassName=\"odometer-digit\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\tpaddingRight: offsetWidth ? `${offsetWidth}px` : '0',\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{status === 'inactive' && (\n\t\t\t\t\t\t\t\t\t<span\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: 0,\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{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\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\t{status === 'transition' && childDigits}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)\n\t\t\t\t\t})}\n\t\t\t\t\t{spaceAfter ? <span style={{ paddingRight: spaceAfter }} /> : null}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t</>\n\t)\n}\n\nexport default Odometer\n"],"mappings":"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","names":["v"]}
package/index.js CHANGED
@@ -164,7 +164,7 @@ var Odometer = ({
164
164
  color: foundDecimal ? decimalColor : wholeColor,
165
165
  height: lineHeight,
166
166
  lineHeight,
167
- paddingRight: status === "transition" ? `${offsetWidth}px` : "auto"
167
+ paddingRight: offsetWidth ? `${offsetWidth}px` : "0"
168
168
  },
169
169
  children: [
170
170
  status === "inactive" && /* @__PURE__ */ jsx(
@@ -174,8 +174,7 @@ var Odometer = ({
174
174
  style: {
175
175
  top: 0,
176
176
  height: lineHeight,
177
- lineHeight,
178
- width: offsetWidth ? `${offsetWidth}px` : "auto"
177
+ lineHeight
179
178
  },
180
179
  children: d === "dot" ? "." : d === "comma" ? "," : d
181
180
  }
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 type { RefObject } from 'react'\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 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// 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: 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\thandleValueDigitRefs(value)\n\t}, [])\n\n\t// Phase 1: new digits and refs are added to the odometer.\n\tuseEffectIgnoreInitial(() => {\n\t\tif (Object.keys(allDigitRefs)) {\n\t\t\thandleValueDigitRefs(value)\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<>\n\t\t\t{allDigits.map((d, i) => (\n\t\t\t\t<span\n\t\t\t\t\tkey={`odometer_template_digit_${i}`}\n\t\t\t\t\tref={allDigitRefs[`d_${d}`]}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\t\ttop: '-999%',\n\t\t\t\t\t\tleft: '-999%',\n\t\t\t\t\t\tuserSelect: 'none',\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\n\t\t\t\t</span>\n\t\t\t))}\n\t\t\t<span className=\"odometer\">\n\t\t\t\t<span className=\"odometer-inner\" ref={odometerRef}>\n\t\t\t\t\t{spaceBefore ? <span style={{ paddingLeft: spaceBefore }} /> : null}\n\t\t\t\t\t{digits.map((d, i) => {\n\t\t\t\t\t\tif (d === 'dot') {\n\t\t\t\t\t\t\tfoundDecimal = true\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If transitioning, get digits needed to animate.\n\t\t\t\t\t\tlet childDigits = null\n\t\t\t\t\t\tif (status === 'transition') {\n\t\t\t\t\t\t\tconst digitsToAnimate = []\n\t\t\t\t\t\t\tconst digitIndex = allDigits.indexOf(digits[i])\n\t\t\t\t\t\t\tconst prevDigitIndex = allDigits.indexOf(prevDigits[i])\n\t\t\t\t\t\t\tconst difference = Math.abs(digitIndex - prevDigitIndex)\n\t\t\t\t\t\t\tconst delay = `${0.01 * (digits.length - i - 1)}s`\n\t\t\t\t\t\t\tconst direction: Direction =\n\t\t\t\t\t\t\t\tdigitIndex === prevDigitIndex ? 'none' : 'down'\n\t\t\t\t\t\t\tconst animClass = `slide-${direction}-${difference} `\n\n\t\t\t\t\t\t\t// Push current prev digit to stop of stack.\n\t\t\t\t\t\t\tdigitsToAnimate.push(prevDigits[i])\n\n\t\t\t\t\t\t\t// If transitioning between two digits, animate all digits in between.\n\t\t\t\t\t\t\tif (digitIndex < prevDigitIndex) {\n\t\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t\t(_, k) => allDigits[prevDigitIndex - k - 1],\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} else {\n\t\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t\t(_, k) => allDigits[k + prevDigitIndex + 1],\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}\n\n\t\t\t\t\t\t\tchildDigits = (\n\t\t\t\t\t\t\t\t<span\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\tanimationName: direction === 'none' ? undefined : animClass,\n\t\t\t\t\t\t\t\t\t\tanimationDuration:\n\t\t\t\t\t\t\t\t\t\t\tdirection === 'none' ? undefined : DURATION_SECS,\n\t\t\t\t\t\t\t\t\t\tanimationFillMode: 'forwards',\n\t\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\t\tanimationDelay: delay,\n\t\t\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\t\t\tuserSelect: 'none',\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{digitsToAnimate.map((c, j) => (\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tkey={`child_digit_${j}`}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"odometer-digit odometer-child\"\n\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\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\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t>\n\t\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\t</span>\n\t\t\t\t\t\t\t\t\t))}\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}\n\n\t\t\t\t\t\tconst offsetWidth = allDigitRefs[`d_${d}`]?.current?.offsetWidth\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tkey={`digit_${i}`}\n\t\t\t\t\t\t\t\tref={digitRefs[i]}\n\t\t\t\t\t\t\t\tclassName=\"odometer-digit\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\tpaddingRight:\n\t\t\t\t\t\t\t\t\t\tstatus === 'transition' ? `${offsetWidth}px` : 'auto',\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{status === 'inactive' && (\n\t\t\t\t\t\t\t\t\t<span\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: 0,\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\twidth: offsetWidth ? `${offsetWidth}px` : 'auto',\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{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\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\t{status === 'transition' && childDigits}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)\n\t\t\t\t\t})}\n\t\t\t\t\t{spaceAfter ? <span style={{ paddingRight: spaceAfter }} /> : null}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t</>\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 { 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 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// 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: 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\thandleValueDigitRefs(value)\n\t}, [])\n\n\t// Phase 1: new digits and refs are added to the odometer.\n\tuseEffectIgnoreInitial(() => {\n\t\tif (Object.keys(allDigitRefs)) {\n\t\t\thandleValueDigitRefs(value)\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<>\n\t\t\t{allDigits.map((d, i) => (\n\t\t\t\t<span\n\t\t\t\t\tkey={`odometer_template_digit_${i}`}\n\t\t\t\t\tref={allDigitRefs[`d_${d}`]}\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\tposition: 'fixed',\n\t\t\t\t\t\ttop: '-999%',\n\t\t\t\t\t\tleft: '-999%',\n\t\t\t\t\t\tuserSelect: 'none',\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\n\t\t\t\t</span>\n\t\t\t))}\n\t\t\t<span className=\"odometer\">\n\t\t\t\t<span className=\"odometer-inner\" ref={odometerRef}>\n\t\t\t\t\t{spaceBefore ? <span style={{ paddingLeft: spaceBefore }} /> : null}\n\t\t\t\t\t{digits.map((d, i) => {\n\t\t\t\t\t\tif (d === 'dot') {\n\t\t\t\t\t\t\tfoundDecimal = true\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// If transitioning, get digits needed to animate.\n\t\t\t\t\t\tlet childDigits = null\n\t\t\t\t\t\tif (status === 'transition') {\n\t\t\t\t\t\t\tconst digitsToAnimate = []\n\t\t\t\t\t\t\tconst digitIndex = allDigits.indexOf(digits[i])\n\t\t\t\t\t\t\tconst prevDigitIndex = allDigits.indexOf(prevDigits[i])\n\t\t\t\t\t\t\tconst difference = Math.abs(digitIndex - prevDigitIndex)\n\t\t\t\t\t\t\tconst delay = `${0.01 * (digits.length - i - 1)}s`\n\t\t\t\t\t\t\tconst direction: Direction =\n\t\t\t\t\t\t\t\tdigitIndex === prevDigitIndex ? 'none' : 'down'\n\t\t\t\t\t\t\tconst animClass = `slide-${direction}-${difference} `\n\n\t\t\t\t\t\t\t// Push current prev digit to stop of stack.\n\t\t\t\t\t\t\tdigitsToAnimate.push(prevDigits[i])\n\n\t\t\t\t\t\t\t// If transitioning between two digits, animate all digits in between.\n\t\t\t\t\t\t\tif (digitIndex < prevDigitIndex) {\n\t\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t\t(_, k) => allDigits[prevDigitIndex - k - 1],\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} else {\n\t\t\t\t\t\t\t\tdigitsToAnimate.push(\n\t\t\t\t\t\t\t\t\t...Array.from(\n\t\t\t\t\t\t\t\t\t\t{ length: difference },\n\t\t\t\t\t\t\t\t\t\t(_, k) => allDigits[k + prevDigitIndex + 1],\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}\n\n\t\t\t\t\t\t\tchildDigits = (\n\t\t\t\t\t\t\t\t<span\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\tanimationName: direction === 'none' ? undefined : animClass,\n\t\t\t\t\t\t\t\t\t\tanimationDuration:\n\t\t\t\t\t\t\t\t\t\t\tdirection === 'none' ? undefined : DURATION_SECS,\n\t\t\t\t\t\t\t\t\t\tanimationFillMode: 'forwards',\n\t\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\t\tanimationDelay: delay,\n\t\t\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\t\t\tuserSelect: 'none',\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{digitsToAnimate.map((c, j) => (\n\t\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\t\tkey={`child_digit_${j}`}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"odometer-digit odometer-child\"\n\t\t\t\t\t\t\t\t\t\t\tstyle={{\n\t\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\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t>\n\t\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\t</span>\n\t\t\t\t\t\t\t\t\t))}\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}\n\n\t\t\t\t\t\tconst offsetWidth = allDigitRefs[`d_${d}`]?.current?.offsetWidth\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tkey={`digit_${i}`}\n\t\t\t\t\t\t\t\tref={digitRefs[i]}\n\t\t\t\t\t\t\t\tclassName=\"odometer-digit\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tcolor: foundDecimal ? decimalColor : wholeColor,\n\t\t\t\t\t\t\t\t\theight: lineHeight,\n\t\t\t\t\t\t\t\t\tlineHeight,\n\t\t\t\t\t\t\t\t\tpaddingRight: offsetWidth ? `${offsetWidth}px` : '0',\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{status === 'inactive' && (\n\t\t\t\t\t\t\t\t\t<span\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: 0,\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{d === 'dot' ? '.' : d === 'comma' ? ',' : d}\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\t{status === 'transition' && childDigits}\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t)\n\t\t\t\t\t})}\n\t\t\t\t\t{spaceAfter ? <span style={{ paddingRight: spaceAfter }} /> : null}\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t</>\n\t)\n}\n\nexport default Odometer\n"],"mappings":"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","names":["v"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@w3ux/react-odometer",
3
- "version": "2.3.3",
3
+ "version": "2.3.5",
4
4
  "license": "GPL-3.0-only",
5
5
  "type": "module",
6
6
  "description": "An odometer effect used for number and balance transitions",