light-odometer 0.0.1
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/LICENSE +9 -0
- package/README.md +5 -0
- package/dist/main.d.ts +277 -0
- package/dist/main.js +1 -0
- package/package.json +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Copyright (c) 2013 HubSpot, Inc.
|
|
2
|
+
Copyright (c) 2020-2025 Marco Trinastich
|
|
3
|
+
Copyright (c) 2025 EDM115
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# light-odometer 
|
|
2
|
+
|
|
3
|
+
This project is made only for personal use, as a small and lightweight build of [tm-odometer](https://github.com/mtmarco87/tm-odometer), which is itself a fork of [HubSpot's odometer](https://github.com/HubSpot/odometer).
|
|
4
|
+
Do not use this, use [@mtmarco87](https://github.com/mtmarco87)'s package instead.
|
|
5
|
+
Huge props to him for this TypeScript refactor !
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
//#region src/shared/interfaces.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* TmOdometer global options interface
|
|
4
|
+
* @interface OdometerOptions
|
|
5
|
+
* @property {string} [selector] - The selector for the odometer elements.
|
|
6
|
+
* @property {boolean} [auto] - Whether to automatically initialize odometers.
|
|
7
|
+
* @property {any} [key] - Additional options.
|
|
8
|
+
*/
|
|
9
|
+
interface OdometerOptions {
|
|
10
|
+
selector?: string;
|
|
11
|
+
auto?: boolean;
|
|
12
|
+
[key: string]: any;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* TmOdometer options interface
|
|
16
|
+
* Extends the base configuration options (`TmOdometerConfig`) with additional required properties.
|
|
17
|
+
* @interface TmOdometerOptions
|
|
18
|
+
* @extends TmOdometerConfig
|
|
19
|
+
* @property {HTMLElement} el - The HTML element to attach the odometer to.
|
|
20
|
+
*/
|
|
21
|
+
interface TmOdometerOptions extends TmOdometerConfig {
|
|
22
|
+
el: HTMLElement;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* TmOdometer config interface
|
|
26
|
+
* @interface TmOdometerConfig
|
|
27
|
+
* @property {string | number | null} [value] - The initial value of the odometer.
|
|
28
|
+
* @property {string} [format] - The format string for the odometer.
|
|
29
|
+
* @property {string} [theme] - The theme for the odometer.
|
|
30
|
+
* @property {number} [duration] - The duration of the animation in milliseconds.
|
|
31
|
+
* @property {'count' | 'slide'} [animation] - The animation type ('count' or 'slide').
|
|
32
|
+
* @property {(value: number) => string} [formatFunction] - A custom format function.
|
|
33
|
+
* @property {any} [key] - Additional options.
|
|
34
|
+
*/
|
|
35
|
+
interface TmOdometerConfig {
|
|
36
|
+
value?: string | number | null;
|
|
37
|
+
format?: string;
|
|
38
|
+
theme?: string;
|
|
39
|
+
duration?: number;
|
|
40
|
+
animation?: "count" | "slide";
|
|
41
|
+
formatFunction?: (value: number) => string;
|
|
42
|
+
[key: string]: any;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* FormatObject interface
|
|
46
|
+
* @interface FormatObject
|
|
47
|
+
* @property {string} repeating - The repeating part of the format. (i.e. '(,ddd)')
|
|
48
|
+
* @property {string} [radix] - The radix separator. (i.e. '.')
|
|
49
|
+
* @property {number} precision - The number of decimal places. (i.e. 'dd')
|
|
50
|
+
*/
|
|
51
|
+
interface FormatObject {
|
|
52
|
+
repeating: string;
|
|
53
|
+
radix?: string;
|
|
54
|
+
precision: number;
|
|
55
|
+
}
|
|
56
|
+
declare global {
|
|
57
|
+
interface Window extends WindowOrWorkerGlobalScope {
|
|
58
|
+
odometerOptions?: OdometerOptions;
|
|
59
|
+
jQuery?: any;
|
|
60
|
+
mozRequestAnimationFrame?: (callback: FrameRequestCallback) => number;
|
|
61
|
+
webkitRequestAnimationFrame?: (callback: FrameRequestCallback) => number;
|
|
62
|
+
msRequestAnimationFrame?: (callback: FrameRequestCallback) => number;
|
|
63
|
+
WebKitMutationObserver?: any;
|
|
64
|
+
MozMutationObserver?: any;
|
|
65
|
+
}
|
|
66
|
+
interface HTMLElement {
|
|
67
|
+
odometer?: TmOdometer;
|
|
68
|
+
doScroll?: any;
|
|
69
|
+
}
|
|
70
|
+
interface CSSStyleDeclaration {
|
|
71
|
+
webkitTransition: string;
|
|
72
|
+
mozTransition?: any;
|
|
73
|
+
oTransition?: any;
|
|
74
|
+
}
|
|
75
|
+
interface Document {
|
|
76
|
+
createEventObject?: any;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/utils/compatibility.d.ts
|
|
81
|
+
declare const MutationObserver: typeof window.MutationObserver;
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/core/odometer.d.ts
|
|
84
|
+
declare class TmOdometer {
|
|
85
|
+
static options: OdometerOptions;
|
|
86
|
+
options: TmOdometerOptions;
|
|
87
|
+
el: HTMLElement;
|
|
88
|
+
value: number;
|
|
89
|
+
inside: HTMLElement;
|
|
90
|
+
observer?: MutationObserver;
|
|
91
|
+
watchMutations: boolean;
|
|
92
|
+
transitionEndBound: boolean;
|
|
93
|
+
format: FormatObject;
|
|
94
|
+
MAX_VALUES: number;
|
|
95
|
+
digits: HTMLElement[];
|
|
96
|
+
ribbons: Record<number, HTMLElement>;
|
|
97
|
+
/**
|
|
98
|
+
* Initializes a new instance of the TmOdometer class.
|
|
99
|
+
* Sets up the odometer's options, formats, and DOM structure.
|
|
100
|
+
* If an odometer instance already exists on the element, it returns the existing instance.
|
|
101
|
+
* @param {TmOdometerOptions} options - Configuration options for the odometer.
|
|
102
|
+
*/
|
|
103
|
+
constructor(options: TmOdometerOptions);
|
|
104
|
+
/**
|
|
105
|
+
* Renders the inner container of the odometer.
|
|
106
|
+
* Clears the root element (`this.el`) and appends a new child element
|
|
107
|
+
* with the class `odometer-inside`.
|
|
108
|
+
* @returns {void}
|
|
109
|
+
*/
|
|
110
|
+
renderInside(): void;
|
|
111
|
+
/**
|
|
112
|
+
* Observes changes to the root element's content and updates the odometer accordingly.
|
|
113
|
+
* This is a fallback for environments like Safari where `.innerHTML` cannot be wrapped.
|
|
114
|
+
* @returns {void}
|
|
115
|
+
*/
|
|
116
|
+
watchForMutations(): void;
|
|
117
|
+
/**
|
|
118
|
+
* Starts observing mutations on the root element (`this.el`).
|
|
119
|
+
* Listens for changes to the element's child nodes (e.g., additions or removals).
|
|
120
|
+
* Requires `this.watchMutations` to be `true` and a `MutationObserver` to be initialized.
|
|
121
|
+
* @returns {void}
|
|
122
|
+
*/
|
|
123
|
+
startWatchingMutations(): void;
|
|
124
|
+
/**
|
|
125
|
+
* Stops observing mutations on the root element (`this.el`).
|
|
126
|
+
* Disconnects the `MutationObserver` if it is initialized.
|
|
127
|
+
* @returns {void}
|
|
128
|
+
*/
|
|
129
|
+
stopWatchingMutations(): void;
|
|
130
|
+
/**
|
|
131
|
+
* Cleans and normalizes a value to ensure it can be processed as a number.
|
|
132
|
+
* Converts formatted strings into numeric values by handling radix symbols
|
|
133
|
+
* and removing unnecessary characters.
|
|
134
|
+
* @param {string | number} val - The value to clean and normalize.
|
|
135
|
+
* @returns {number} The cleaned and rounded numeric value.
|
|
136
|
+
*/
|
|
137
|
+
cleanValue(val: string | number): number;
|
|
138
|
+
/**
|
|
139
|
+
* Binds transition end events to the root element (`this.el`).
|
|
140
|
+
* Ensures that the odometer re-renders only once per transition, even if multiple
|
|
141
|
+
* transition end events are triggered. After rendering, it dispatches the
|
|
142
|
+
* `odometerdone` custom event.
|
|
143
|
+
* @returns {void}
|
|
144
|
+
*/
|
|
145
|
+
bindTransitionEnd(): void;
|
|
146
|
+
/**
|
|
147
|
+
* Resets and parses the odometer's format configuration.
|
|
148
|
+
* Extracts the repeating pattern, radix symbol, and precision from the format string.
|
|
149
|
+
* Throws an error if the format string is invalid or unparsable.
|
|
150
|
+
* @returns {void}
|
|
151
|
+
*/
|
|
152
|
+
resetFormat(): void;
|
|
153
|
+
/**
|
|
154
|
+
* Renders the odometer with the specified value.
|
|
155
|
+
* Updates the DOM structure, applies the appropriate theme and classes,
|
|
156
|
+
* and formats the digits for display.
|
|
157
|
+
* @param {number} [value] - The value to render. Defaults to the current value (`this.value`).
|
|
158
|
+
* @returns {void}
|
|
159
|
+
*/
|
|
160
|
+
render(value?: number): void;
|
|
161
|
+
/**
|
|
162
|
+
* Formats the given value into individual digits and renders them.
|
|
163
|
+
* If a custom format function is provided, it uses that to format the value.
|
|
164
|
+
* Otherwise, it preserves the precision and formats the value based on the odometer's configuration.
|
|
165
|
+
* @param {number} value - The value to format and render as digits.
|
|
166
|
+
* @returns {void}
|
|
167
|
+
*/
|
|
168
|
+
formatDigits(value: number): void;
|
|
169
|
+
/**
|
|
170
|
+
* Ensures the value maintains the specified precision by adding trailing zeros if necessary.
|
|
171
|
+
* This is used to keep the decimal places consistent at the end of the animation.
|
|
172
|
+
* @param {number} value - The numeric value to format with preserved precision.
|
|
173
|
+
* @returns {string} The value as a string with the required precision.
|
|
174
|
+
*/
|
|
175
|
+
preservePrecision(value: number): string;
|
|
176
|
+
/**
|
|
177
|
+
* Updates the odometer to display a new value.
|
|
178
|
+
* Cleans and normalizes the input value, determines the difference from the current value,
|
|
179
|
+
* and triggers the appropriate animations and DOM updates.
|
|
180
|
+
* @param {string | number} newValue - The new value to update the odometer to.
|
|
181
|
+
* @returns {number} The updated value of the odometer.
|
|
182
|
+
*/
|
|
183
|
+
update(newValue: string | number): number;
|
|
184
|
+
/**
|
|
185
|
+
* Creates and returns a new digit element for the odometer.
|
|
186
|
+
* The digit element is generated from the predefined `DIGIT_HTML` template.
|
|
187
|
+
* @returns {HTMLElement} The newly created digit element.
|
|
188
|
+
*/
|
|
189
|
+
renderDigit(): HTMLElement;
|
|
190
|
+
/**
|
|
191
|
+
* Inserts a digit element into the odometer's inner container.
|
|
192
|
+
* If a reference element (`before`) is provided, the digit is inserted before it.
|
|
193
|
+
* Otherwise, the digit is appended to the container or inserted at the beginning if other children exist.
|
|
194
|
+
* @param {HTMLElement} digit - The digit element to insert.
|
|
195
|
+
* @param {HTMLElement | null} [before] - The reference element to insert the digit before. Defaults to `null`.
|
|
196
|
+
* @returns {HTMLElement} The inserted digit element.
|
|
197
|
+
*/
|
|
198
|
+
insertDigit(digit: HTMLElement, before?: HTMLElement | null): HTMLElement;
|
|
199
|
+
/**
|
|
200
|
+
* Creates and inserts a spacer element into the odometer's inner container.
|
|
201
|
+
* A spacer is a non-digit element (e.g., a comma or decimal point) used for formatting.
|
|
202
|
+
* @param {string} chr - The character to display in the spacer.
|
|
203
|
+
* @param {HTMLElement | null} [before] - The reference element to insert the spacer before. Defaults to `null`.
|
|
204
|
+
* @param {string} [extraClasses] - Additional CSS classes to apply to the spacer element.
|
|
205
|
+
* @returns {HTMLElement} The inserted spacer element.
|
|
206
|
+
*/
|
|
207
|
+
addSpacer(chr: string, before?: HTMLElement | null, extraClasses?: string): HTMLElement;
|
|
208
|
+
/**
|
|
209
|
+
* Adds a digit or spacer element to the odometer's inner container.
|
|
210
|
+
* Handles special cases for negation (`-`) and radix (`.`) characters,
|
|
211
|
+
* and ensures the format's repeating pattern is respected.
|
|
212
|
+
* @param {string} value - The digit or character to add.
|
|
213
|
+
* @param {boolean} [repeating=true] - Whether to use the repeating format pattern. Defaults to `true`.
|
|
214
|
+
* @returns {HTMLElement} The inserted digit or spacer element.
|
|
215
|
+
* @throws {Error} If the format string is invalid or lacks digits.
|
|
216
|
+
*/
|
|
217
|
+
addDigit(value: string, repeating?: boolean): HTMLElement;
|
|
218
|
+
/**
|
|
219
|
+
* Animates the odometer to transition to a new value.
|
|
220
|
+
* Chooses the appropriate animation method (`count` or `slide`) based on the configuration and browser support.
|
|
221
|
+
* @param {number} newValue - The new value to animate the odometer to.
|
|
222
|
+
* @returns {void}
|
|
223
|
+
*/
|
|
224
|
+
animate(newValue: number): void;
|
|
225
|
+
/**
|
|
226
|
+
* Animates the odometer by incrementing or decrementing the value over time.
|
|
227
|
+
* Uses a "counting" animation to transition smoothly to the new value.
|
|
228
|
+
* @param {number} newValue - The new value to animate the odometer to.
|
|
229
|
+
* @returns {void}
|
|
230
|
+
*/
|
|
231
|
+
animateCount(newValue: number): void;
|
|
232
|
+
/**
|
|
233
|
+
* Calculates the number of digits in the largest absolute value from the provided numbers.
|
|
234
|
+
* @param {...number} values - A list of numbers to evaluate.
|
|
235
|
+
* @returns {number} The number of digits in the largest absolute value.
|
|
236
|
+
*/
|
|
237
|
+
getDigitCount(...values: number[]): number;
|
|
238
|
+
/**
|
|
239
|
+
* Calculates the maximum number of fractional digits (decimal places) among the provided numbers.
|
|
240
|
+
* Assumes the values have already been rounded to the specified precision.
|
|
241
|
+
* @param {...number} values - A list of numbers to evaluate.
|
|
242
|
+
* @returns {number} The maximum number of fractional digits.
|
|
243
|
+
*/
|
|
244
|
+
getFractionalDigitCount(...values: number[]): number;
|
|
245
|
+
/**
|
|
246
|
+
* Resets the odometer's digits and ribbons.
|
|
247
|
+
* Clears the inner container, resets the format configuration,
|
|
248
|
+
* and prepares the odometer for re-rendering.
|
|
249
|
+
* @returns {void}
|
|
250
|
+
*/
|
|
251
|
+
resetDigits(): void;
|
|
252
|
+
/**
|
|
253
|
+
* Creates an array of numbers between two values
|
|
254
|
+
* @param start The starting value of the range
|
|
255
|
+
* @param end The ending value of the range
|
|
256
|
+
* @param inclusive Whether to include the end value in the range
|
|
257
|
+
* @returns An array containing the range of numbers
|
|
258
|
+
*/
|
|
259
|
+
createRange(start: number, end: number, inclusive: boolean): number[];
|
|
260
|
+
/**
|
|
261
|
+
* Animates the odometer to transition to a new value using a sliding animation.
|
|
262
|
+
* Breaks the value into individual digits, calculates the frames for each digit's animation,
|
|
263
|
+
* and updates the DOM to reflect the sliding effect.
|
|
264
|
+
* @param {number} newValue - The new value to animate the odometer to.
|
|
265
|
+
* @returns {void}
|
|
266
|
+
*/
|
|
267
|
+
animateSlide(newValue: number): void;
|
|
268
|
+
/**
|
|
269
|
+
* Initializes all odometer elements on the page.
|
|
270
|
+
* Selects elements matching the configured selector or the default `.odometer` class,
|
|
271
|
+
* and creates a `TmOdometer` instance for each element.
|
|
272
|
+
* @returns {TmOdometer[]} An array of initialized `TmOdometer` instances.
|
|
273
|
+
*/
|
|
274
|
+
static init(): TmOdometer[];
|
|
275
|
+
}
|
|
276
|
+
//#endregion
|
|
277
|
+
export { TmOdometer };
|
package/dist/main.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=/^\(?([^)]*)\)?(?:(.)(d+))?$/,t=document.createElement(`div`).style.transition!=null,n=window.requestAnimationFrame,r=window.MutationObserver,i=e=>{let t=document.createElement(`div`);if(t.innerHTML=e,!t.children[0])throw Error(`Invalid HTML: No valid root element found.`);return t.children[0]},a=(e,t)=>e.className=e.className.replace(RegExp(`(^| )${t.split(` `).join(`|`)}( |$)`,`gi`),` `),o=(e,t)=>(a(e,t),e.className+=` ${t}`),s=(e,t)=>{if(typeof CustomEvent==`function`){let n=new CustomEvent(t,{bubbles:!0,cancelable:!0});e.dispatchEvent(n)}else if(document.createEvent){let n=document.createEvent(`HTMLEvents`);n.initEvent(t,!0,!0),e.dispatchEvent(n)}},c=()=>{var e,t;let n=(e=window.performance)==null||(t=e.now)==null?void 0:t.call(e);return n==null?+new Date:n},l=(e,t)=>(t!=null||(t=0),t?(e*=10**t,e+=.5,e=Math.floor(e),e/=10**t):Math.round(e)),u=e=>e<0?Math.ceil(e):Math.floor(e),d=e=>{setTimeout(()=>{if(window.odometerOptions)for(let n in window.odometerOptions){var t;(t=e.options)[n]!=null||(t[n]=window.odometerOptions[n])}},0)},f=e=>{var t;if((t=document.documentElement)!=null&&t.doScroll&&document.createEventObject){let t=document.onreadystatechange;document.onreadystatechange=function(){document.readyState===`complete`&&e.options.auto!==!1&&e.init(),t&&(t==null||t.apply(this,arguments))}}else document.addEventListener(`DOMContentLoaded`,function(){e.options.auto!==!1&&e.init()},!1)};function p(e){"@babel/helpers - typeof";return p=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},p(e)}function m(e,t){if(p(e)!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(p(r)!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function h(e){var t=m(e,`string`);return p(t)==`symbol`?t:t+``}function g(e,t,n){return(t=h(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var _,v=class d{constructor(e){var t,n;if(g(this,`options`,void 0),g(this,`el`,void 0),g(this,`value`,0),g(this,`inside`,void 0),g(this,`observer`,void 0),g(this,`watchMutations`,!1),g(this,`transitionEndBound`,!1),g(this,`format`,{repeating:``,precision:0}),g(this,`MAX_VALUES`,void 0),g(this,`digits`,[]),g(this,`ribbons`,{}),this.options=e,this.el=this.options.el,this.el.odometer)return this.el.odometer;for(let e in this.el.odometer=this,d.options){var r;let t=d.options[e];(r=this.options)[e]!=null||(r[e]=t)}(t=this.options).duration!=null||(t.duration=2e3),this.MAX_VALUES=this.options.duration/33.333333333333336/2|0,this.resetFormat(),this.value=this.cleanValue((n=this.options.value)==null?``:n),this.renderInside(),this.render();try{for(let e of[`innerHTML`,`innerText`,`textContent`])this.el[e]&&Object.defineProperty(this.el,e,{get:()=>{if(e===`innerHTML`)return this.inside.outerHTML;var t,n;return(t=(n=this.inside.innerText)==null?this.inside.textContent:n)==null?``:t},set:e=>this.update(e)})}catch(e){this.watchForMutations()}}renderInside(){this.inside=document.createElement(`div`),this.inside.className=`odometer-inside`,this.el.innerHTML=``,this.el.appendChild(this.inside)}watchForMutations(){if(r)try{this.observer!=null||(this.observer=new r(e=>{let t=this.el.innerText||``;this.renderInside(),this.render(this.value),this.update(t)})),this.watchMutations=!0,this.startWatchingMutations()}catch(e){}}startWatchingMutations(){if(this.watchMutations){var e;(e=this.observer)==null||e.observe(this.el,{childList:!0})}}stopWatchingMutations(){var e;(e=this.observer)==null||e.disconnect()}cleanValue(e){if(typeof e==`string`){var t;e=e.replace((t=this.format.radix)==null?`.`:t,`<radix>`),e=e.replace(/[.,]/g,``),e=e.replace(`<radix>`,`.`),e=parseFloat(e)||0}return l(e,this.format.precision)}bindTransitionEnd(){if(this.transitionEndBound)return;this.transitionEndBound=!0;let e=!1,t=`transitionend`.split(` `);for(let n of t)this.el.addEventListener(n,()=>e?!0:(e=!0,setTimeout(()=>{this.render(),e=!1,s(this.el,`odometerdone`)},0),!0),!1)}resetFormat(){var t;let n=(t=this.options.format)==null?`(,ddd).dd`:t;n=n||`d`;let r=e.exec(n);if(!r)throw Error(`TmOdometer: Unparsable digit format`);let[i,a,o,s]=r,c=(s==null?void 0:s.length)||0;this.format={repeating:a,radix:o,precision:c}}render(e){e!=null||(e=this.value),this.stopWatchingMutations(),this.resetFormat(),this.inside.innerHTML=``;let{theme:n}=this.options,r=this.el.className.split(` `),i=[];for(let e of r)if(e.length){let t=/^odometer-theme-(.+)$/.exec(e);if(t){n=t[1];continue}if(/^odometer(-|$)/.test(e))continue;i.push(e)}i.push(`odometer`),t||i.push(`odometer-no-transitions`),n?i.push(`odometer-theme-${n}`):i.push(`odometer-auto-theme`),this.el.className=i.join(` `),this.ribbons={},this.formatDigits(e),this.startWatchingMutations()}formatDigits(e){if(this.digits=[],this.options.formatFunction){let t=this.options.formatFunction(e);for(let e of t.split(``).toReversed())if(e.match(/0-9/)){let t=this.renderDigit();t.querySelector(`.odometer-value`).innerHTML=e,this.digits.push(t),this.insertDigit(t)}else this.addSpacer(e)}else{let t=this.preservePrecision(e),n=!this.format.precision;for(let e of t.split(``).toReversed())e===`.`&&(n=!0),this.addDigit(e,n)}}preservePrecision(e){let t=e.toString();if(this.format.precision){let e=t.split(`.`);e.length===1&&(t+=`.`,e[1]=``);for(let n=0;n<this.format.precision;n++)e[1][n]||(t+=`0`)}return t}update(e){e=this.cleanValue(e);let t=e-this.value;return t?(a(this.el,`odometer-animating-up odometer-animating-down odometer-animating`),t>0?o(this.el,`odometer-animating-up`):o(this.el,`odometer-animating-down`),this.stopWatchingMutations(),this.animate(e),this.startWatchingMutations(),setTimeout(()=>{this.el.offsetHeight,o(this.el,`odometer-animating`)},0),this.value=e,this.value):this.value}renderDigit(){return i(`<span class="odometer-digit"><span class="odometer-digit-spacer">8</span><span class="odometer-digit-inner"><span class="odometer-ribbon"><span class="odometer-ribbon-inner"><span class="odometer-value"></span></span></span></span></span>`)}insertDigit(e,t){return t?this.inside.insertBefore(e,t):this.inside.children.length?this.inside.insertBefore(e,this.inside.children[0]):this.inside.appendChild(e)}addSpacer(e,t,n){let r=i(`<span class="odometer-formatting-mark"></span>`);return r.innerHTML=e,n&&o(r,n),this.insertDigit(r,t)}addDigit(e,t){if(t!=null||(t=!0),e===`-`)return this.addSpacer(e,null,`odometer-negation-mark`);if(e===`.`){var n;return this.addSpacer((n=this.format.radix)==null?`.`:n,null,`odometer-radix-mark`)}if(t){let e=!1;for(;;){if(!this.format.repeating.length){if(e)throw Error(`Bad odometer format without digits`);this.resetFormat(),e=!0}let t=this.format.repeating[this.format.repeating.length-1];if(this.format.repeating=this.format.repeating.substring(0,this.format.repeating.length-1),t===`d`)break;this.addSpacer(t)}}let r=this.renderDigit();return r.querySelector(`.odometer-value`).innerHTML=e,this.digits.push(r),this.insertDigit(r)}animate(e){!t||this.options.animation===`count`?this.animateCount(e):this.animateSlide(e)}animateCount(e){let t=e-this.value;if(!t)return;let r=c(),i=r,a=this.value,o=()=>{if(c()-r>(this.options.duration||0)){this.value=e,this.render(),s(this.el,`odometerdone`);return}let l=c()-i;if(l>50){i=c();let e=l/(this.options.duration||0),n=t*e;a+=n,this.render(Math.round(a))}n?n(o):setTimeout(o,50)};o()}getDigitCount(...e){for(let t=0;t<e.length;t++)e[t]=Math.abs(e[t]);let t=Math.max(...e);return Math.ceil(Math.log(t+1)/Math.log(10))}getFractionalDigitCount(...e){let t=/^-?\d*\.(\d*?)0*$/;for(let n=0;n<e.length;n++){let r=e[n].toString(),i=t.exec(r);e[n]=i?i[1].length:0}return Math.max(...e)}resetDigits(){this.digits=[],this.ribbons={},this.inside.innerHTML=``,this.resetFormat()}createRange(e,t,n){let r=e<t,i=Math.abs(t-e)+(n?1:0);return Array.from({length:i},(t,n)=>r?e+n:e-n)}animateSlide(e){let t=this.value,n=this.format.precision;n&&(e*=10**n,t*=10**n);let r=e-t;if(!r)return;this.bindTransitionEnd();let i=[],a=this.getDigitCount(t,e),s=0,c=t;for(let n=0;n<a;n++){c=u(t/10**(a-n-1));let r=u(e/10**(a-n-1)),o=r-c,l;if(Math.abs(o)>this.MAX_VALUES){l=[];let e=o/(this.MAX_VALUES+this.MAX_VALUES*s*.5),t=c;for(;o>0&&t<r||o<0&&t>r;)l.push(Math.round(t)),t+=e;l[l.length-1]!==r&&l.push(r),s++}else l=this.createRange(c,r,!0);for(let e=0;e<l.length;e++)l[e]=Math.abs(l[e]%10);i.push(l)}this.resetDigits();let l=i.toReversed();for(let e=0;e<l.length;e++){let t=l[e];this.digits[e]||this.addDigit(` `,e>=n),this.ribbons[e]===void 0&&(this.ribbons[e]=this.digits[e].querySelector(`.odometer-ribbon-inner`)),this.ribbons[e].innerHTML=``,r<0&&(t=t.toReversed());for(let n=0;n<t.length;n++){let r=t[n],i=document.createElement(`div`);i.className=`odometer-value`,i.innerHTML=r.toString(),this.ribbons[e].appendChild(i),n===t.length-1&&o(i,`odometer-last-value`),n===0&&o(i,`odometer-first-value`)}}c<0&&this.addDigit(`-`);let d=this.inside.querySelector(`.odometer-radix-mark`);if(d&&d.parentNode.removeChild(d),n){var f;this.addSpacer((f=this.format.radix)==null?`.`:f,this.digits[n-1],`odometer-radix-mark`)}}static init(){if(!document.querySelectorAll)return[];let e=document.querySelectorAll(d.options.selector||`.odometer`);return Array.from(e,e=>{var t;return e.odometer=new d({el:e,value:(t=e.innerText)==null?e.textContent:t})})}};g(v,`options`,(_=window.odometerOptions)==null?{}:_),d(v),f(v);export{v as TmOdometer};
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": "EDM115 <npmjs@edm115.dev> (https://edm115.dev)",
|
|
3
|
+
"bugs": {
|
|
4
|
+
"email": "npmjs@edm115.dev",
|
|
5
|
+
"url": "https://github.com/EDM115/light-odometer/issues"
|
|
6
|
+
},
|
|
7
|
+
"contributors": [
|
|
8
|
+
"Adam Schwartz <adam.flynn.schwartz@gmail.com>",
|
|
9
|
+
"Marco Trinastich <mt.marco87@gmail.com>",
|
|
10
|
+
"Zack Bloom <zackbloom@gmail.com>"
|
|
11
|
+
],
|
|
12
|
+
"description": "for personal use only, see EDM115/website",
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@stylistic/eslint-plugin": "~5.3.1",
|
|
15
|
+
"@types/node": "latest",
|
|
16
|
+
"@typescript-eslint/parser": "~8.44.0",
|
|
17
|
+
"eslint": "~9.35.0",
|
|
18
|
+
"oxlint": "~1.15.0",
|
|
19
|
+
"oxlint-tsgolint": "~0.2.0",
|
|
20
|
+
"tsdown": "~0.15.1",
|
|
21
|
+
"typescript": "~5.9.2",
|
|
22
|
+
"unplugin-unused": "~0.5.3"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"funding": [
|
|
28
|
+
{
|
|
29
|
+
"type": "paypal",
|
|
30
|
+
"url": "https://www.paypal.me/8EDM115"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"type": "buymeacoffee",
|
|
34
|
+
"url": "https://www.buymeacoffee.com/edm115"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"type": "github",
|
|
38
|
+
"url": "https://github.com/sponsors/EDM115"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"type": "telegram",
|
|
42
|
+
"url": "https://t.me/EDM115bots/698"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"homepage": "https://github.com/EDM115/light-odometer#readme",
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"name": "light-odometer",
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "git+https://github.com/EDM115/light-odometer.git"
|
|
54
|
+
},
|
|
55
|
+
"type": "module",
|
|
56
|
+
"version": "0.0.1",
|
|
57
|
+
"main": "./dist/main.js",
|
|
58
|
+
"module": "./dist/main.js",
|
|
59
|
+
"types": "./dist/main.d.ts",
|
|
60
|
+
"exports": {
|
|
61
|
+
".": "./dist/main.js",
|
|
62
|
+
"./package.json": "./package.json"
|
|
63
|
+
},
|
|
64
|
+
"scripts": {
|
|
65
|
+
"build": "tsdown",
|
|
66
|
+
"lint": "oxlint --type-aware .",
|
|
67
|
+
"lint:fix": "oxlint --fix --type-aware .",
|
|
68
|
+
"format": "eslint -c eslint.stylistic.config.ts --concurrency=auto --fix .",
|
|
69
|
+
"release": "pnpm publish",
|
|
70
|
+
"typecheck": "tsc --noEmit"
|
|
71
|
+
}
|
|
72
|
+
}
|