@tombcato/smart-ticker 1.1.0 → 1.2.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/README.md CHANGED
@@ -6,20 +6,22 @@
6
6
  <h1 align="center">Smart Ticker</h1>
7
7
 
8
8
  <p align="center">
9
- 高性能智能文本差异滚动组件,支持中英、数字、字母、符号、Emoji等多种字符集,基于 Levenshtein diff 算法,适用于React/Vue,<a href="https://tombcato.github.io/smart-ticker/">官网演示></a>
9
+ <a href="./README.md">🇨🇳 简体中文</a> &nbsp;|&nbsp; <strong>🇬🇧 English</strong>
10
10
  </p>
11
-
11
+ High-Performance Text Diff Motion Component based on Levenshtein diff algorithm. Make your text flow like water. <a href="https://tombcato.github.io/smart-ticker/?lang=en">Live Demo ></a> <br />
12
12
  <p align="center">
13
- <strong>简体中文</strong> | <a href="./README_EN.md">English</a>
13
+ Supports any characters<br />
14
+ <img src="./smartticker2.gif" alt="Demo" width="600" />
14
15
  </p>
15
-
16
16
  <p align="center">
17
- <img src="./smartticker.gif" alt="Demo" width="600" />
17
+ Supports Prefix/Suffix, Intl Formatting, Auto-Scale, Fading Edges<br />
18
+ <img src="./smartticker3.gif" alt="Demo" width="600" />
18
19
  </p>
19
20
  <p align="center">
20
- <img src="./smartticker2.gif" alt="Demo" width="600" />
21
+ <img src="./smartticker.gif" alt="Demo" width="600" />
21
22
  </p>
22
23
 
24
+
23
25
  <p align="center">
24
26
  <img src="https://img.shields.io/badge/React-18+-61DAFB?logo=react" alt="React" />
25
27
  <img src="https://img.shields.io/badge/Vue-3+-4FC08D?logo=vuedotjs" alt="Vue" />
@@ -28,55 +30,54 @@
28
30
  </p>
29
31
 
30
32
 
31
- ## ✨ 特性
32
33
  | | |
33
34
  | :--- | :--- |
34
- | **🌏 多字符集支持**<br>支持中英、数字、Emoji等混合滚动,基于 Unicode 宽度自动调整间距 | **🧠 智能差异动画**<br>Levenshtein 算法计算最小变更路径,相同的字符保持静止 |
35
- | **⚡ 平滑中断**<br>动画过程中值突变时,从当前动态位置无缝流向新目标 | **📈 丰富动效**<br>内置 `linear`, `bounce`, `easeInOut` 等缓动,支持 `charWidth` 微调 |
36
- | **🦄 双框架支持**<br>提供 React (Hooks) Vue 3 (Composition) 组件,API 统一 | **🚀 极致性能**<br>基于 `RAF` 驱动,无多余 DOM 操作,适合高频数据流场景 |
35
+ | **🌏 Multi-Charset Support**<br>Supports CJK, Numbers, Emojis, and mixed text rolling. Auto-adjusts spacing based on Unicode width. | **🧠 Smart Diff Animation**<br>Uses Levenshtein algorithm to find the shortest change path; identical characters remain static. |
36
+ | **⚡ Smooth Interruption**<br>Seamlessly transitions to new targets if the value changes dynamically during animation. | **📈 Rich Motion**<br>Built-in variety of easings.Supports custom easing function. Supports `charWidth` fine-tuning. |
37
+ | **🦄 Dual Framework**<br>Provides both React (Hooks) and Vue 3 (Composition) components with a unified API. | **🚀 High Performance**<br>Powered by `RAF`, supporting **Auto-scale**, **Fading Edge**, and **Disable Animation**. |
37
38
 
38
- ## 📦 安装
39
+ ## 📦 Installation
39
40
 
40
- ### NPM 安装(推荐)
41
+ ### NPM (Recommended)
41
42
 
42
43
  ```bash
43
44
  npm install @tombcato/smart-ticker
44
45
  ```
45
46
 
46
- ### 从源码安装
47
+ ### From Source
47
48
 
48
49
  ```bash
49
- # 克隆仓库
50
+ # Clone repository
50
51
  git clone https://github.com/tombcato/smart-ticker.git
51
52
 
52
- # 安装依赖
53
+ # Install dependencies
53
54
  cd smart-ticker
54
55
  npm install
55
56
 
56
- # 启动开发服务器
57
+ # Start dev server
57
58
  npm run dev
58
59
  ```
59
60
 
60
- ## 🚀 使用方法
61
+ ## 🚀 Usage
61
62
 
62
- ### 📦 引入样式 (Import Styles)
63
+ ### 📦 Import Styles
63
64
 
64
- **NPM 安装**时,**必须**显式引入样式文件组件才能正常工作。
65
+ When using **NPM**, you **MUST** explicitly import the style file for the component to work.
65
66
 
66
67
  ```javascript
67
68
  import '@tombcato/smart-ticker/style.css'
68
69
  ```
69
70
 
70
- > **源码集成**:如果您直接复制组件源码,React 版本需确保引入同目录的 `Ticker.css`,Vue 版本样式已内置在单文件组件中。
71
+ > **Source Integration**: If copying source code, ensure React version imports `Ticker.css` and Vue version uses the built-in styles.
71
72
 
72
73
  ### React
73
74
 
74
75
  ```tsx
75
- // NPM 方式
76
+ // NPM Usage
76
77
  import { Ticker } from '@tombcato/smart-ticker';
77
78
  import '@tombcato/smart-ticker/style.css';
78
79
 
79
- // 源码方式
80
+ // Source Usage
80
81
  // import { Ticker } from './components/Ticker';
81
82
 
82
83
  function App() {
@@ -98,11 +99,11 @@ function App() {
98
99
 
99
100
  ```vue
100
101
  <script setup>
101
- // NPM 方式
102
+ // NPM Usage
102
103
  import { Ticker } from '@tombcato/smart-ticker/vue';
103
104
  import '@tombcato/smart-ticker/style.css';
104
105
 
105
- // 源码方式
106
+ // Source Usage
106
107
  // import Ticker from './components/vue/Ticker.vue';
107
108
 
108
109
  import { ref } from 'vue';
@@ -120,133 +121,144 @@ const price = ref('73.18');
120
121
  </template>
121
122
  ```
122
123
 
123
- ### 💅 样式自定义
124
+ ### 💅 Customization
124
125
 
125
- #### 自定义字体
126
+ #### Custom Fonts
126
127
 
127
- 组件默认使用系统等宽字体栈。如果需要使用自定义字体(如 `JetBrains Mono`),请确保该字体是**等宽字体**,并使用 CSS 覆盖:
128
+ The component uses the system monospace stack by default. To use a custom font (e.g., `JetBrains Mono`), ensure it is **monospace** and override via CSS:
128
129
 
129
130
  ```css
130
- /* 全局样式或组件样式中 */
131
+ /* In global styles or component styles */
131
132
  .ticker {
132
133
  font-family: 'JetBrains Mono', monospace !important;
133
134
  }
134
135
  ```
135
136
 
136
- > **注意**:必须使用**等宽字体**,否则字符滚动动画的对齐可能会出现偏差。
137
-
137
+ > **Note**: Must be a **monospace font**, otherwise alignment issues may occur during scrolling animations.
138
138
 
139
139
  ## ⚙️ API
140
+
140
141
  ### Props
141
142
 
142
- | 属性 | 类型 | 默认值 | 说明 |
143
+ | Prop | Type | Default | Description |
143
144
  |------|------|--------|------|
144
- | `value` | `string` | - | 要显示的文本值(必填) |
145
- | `duration` | `number` | `500` | 动画持续时间(毫秒) |
146
- | `easing` | `EasingName \| function` | `'easeInOut'` | 缓动函数:`linear`、`easeIn`、`easeOut`、`easeInOut`、`bounce`,或自定义 `(t: number) => number` |
147
- | `direction` | `string` | `'ANY'` | 滚动方向:`UP`、`DOWN`、`ANY`(自动选择最短路径) |
148
- | `charWidth` | `number` | `1` | 字符宽度倍率(基准为 0.8em |
149
- | `characterLists` | `string[]` | `['0123456789']` | 支持的字符列表 |
150
- | `className` | `string` | `''` | 自定义 CSS 类名 |
151
- | `animateOnMount` | `boolean` | `false` | 首次加载时是否播放动画 |
152
- | `disabled` | `boolean` | `false` | 禁用动画,直接显示最终值 |
153
- | `prefix` | `string` | - | 静态前缀(不参与滚动动画) |
154
- | `suffix` | `string` | - | 静态后缀(不参与滚动动画) |
155
- | `onAnimationEnd` | `() => void` | - | 动画结束回调(Vue: `@animation-end`) |
156
-
157
- ### 内置字符列表
145
+ | `value` | `string`\|`number` | - | The text value to display (Required) |
146
+ | `duration` | `number` | `500` | Animation duration (ms) |
147
+ | `easing` | `EasingName \| function` | `'easeInOut'` | Easing: `linear`, `easeIn`, `easeOut`, `easeInOut`, `bounce`, or custom `(t: number) => number` |
148
+ | `direction` | `string` | `'ANY'` | Scroll direction: `UP`, `DOWN`, `ANY` (shortest path) |
149
+ | `charWidth` | `number` | `1` | Character width multiplier (base 0.8em) |
150
+ | `characterLists` | `string[]` | `['0123456789']` | Allowed character sets |
151
+ | `className` | `string` | `''` | Custom CSS class name |
152
+ | `animateOnMount` | `boolean` | `false` | Animate on initial render |
153
+ | `disableAnimation` | `boolean` | `false` | Disable animation, show final value immediately |
154
+ | `autoScale` | `boolean` | `false` | Enable auto-scaling to fit container width |
155
+ | `fadingEdge` | `boolean` | `false` | Enable top/bottom fading edge effect |
156
+ | `prefix` | `string` | - | Static prefix (not animated) |
157
+ | `suffix` | `string` | - | Static suffix (not animated) |
158
+ | `numberFormat` | `Intl.NumberFormat` | - | Intl formatter number `value` |
159
+ | `onAnimationEnd` | `() => void` | - | Callback when animation ends (Vue: `@animation-end`) |
160
+
161
+
162
+ ### 🧩 Character Configuration (characterLists)
163
+
164
+ `characterLists` controls the core animation logic. It accepts an array of strings, where each string represents a group of characters that can **scroll into each other**.
165
+
166
+ #### Presets (Common Character Lists)
167
+ For convenience, we provide built-in constants for common character sets:
158
168
 
159
169
  ```ts
160
- import { TickerUtils } from './components/Ticker';
170
+ import { Presets } from '@tombcato/smart-ticker';
161
171
 
162
- TickerUtils.provideNumberList() // '0123456789'
163
- TickerUtils.provideAlphabeticalList() // 'abc...zABC...Z'
164
-
165
- ### 🧩 字符集配置详解
166
-
167
- `characterLists` 是控制 Ticker 动画逻辑的核心配置。它接受一个字符串数组,数组的每一项代表一组**“可以互相滚动”**的字符。
168
-
169
- **基本规则:**
170
- 1. **同组滚动**:如果旧字符和新字符在同一个字符串中(例如 `0` 变 `9` 在 `'0123456789'` 中),它们会产生滚动动画。
171
- 2. **跨组替换**:如果它们不在同一组(例如 `a` 变 `1`),或者任何一个字符不在配置列表中(例如汉字),它们会原地切换(Switch),不会产生滚动。
172
+ Presets.NUMBER // '0123456789'
173
+ Presets.ALPHABET // 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
174
+ Presets.ALPHANUMERIC // '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
175
+ Presets.CURRENCY // '0123456789.,'
176
+ ```
172
177
 
173
- **配置技巧:**
178
+ #### Animation Rules
179
+ 1. **Scroll**: If both the old and new characters belong to the same group string (e.g., `0` to `9` in `Presets.NUMBER`), they will scroll.
180
+ 2. **Switch**: If they are in different groups, or if a character is not in any list (e.g., Chinese characters), they will switch instantly (fade/flip) without scrolling.
174
181
 
175
- * **默认全字母**:`TickerUtils.provideAlphabeticalList()` 默认包含 `a-z` 和 `A-Z`。如果你希望大小写之间可以滚动(如 `a` -> `A`),使用它即可。
176
- * **由于物理隔离**:如果你不希望小写字母滚动变成大写字母(希望它们直接切换),请将它们配置为两个独立的字符串,例如 `['abc...', 'ABC...']`。
182
+ #### Configuration Tips
183
+ * **Common Use Case**: Simply use `Presets.ALPHANUMERIC` to support most alphanumeric scrolling.
184
+ * **Case Isolation**: To prevent scrolling between cases (e.g., `a` -> `A`), list them as separate groups: `[Presets.NUMBER, 'abc...', 'ABC...']`.
177
185
 
178
- **示例:**
186
+ **Code Example:**
179
187
 
180
- ```javascript
181
- // 场景:数字、字母(大小写隔离)、符号
182
- characterLists={[
183
- 'abcdefghijklmnopqrstuvwxyz', // 小写组
184
- 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', // 大写组
185
- '0123456789', // 数字组
186
- '.,!@#$%^&*' // 符号组
187
- ]}
188
- ```
188
+ ```tsx
189
+ <Ticker
190
+ value={val}
191
+ characterLists={[
192
+ Presets.NUMBER, // Numbers
193
+ 'abcdefghijklmnopqrstuvwxyz', // Lowercase Group
194
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', // Uppercase Group
195
+ '.,!@#$%^&*' // Symbols
196
+ ]}
197
+ />
189
198
  ```
190
199
 
191
- ## 💻 运行演示
200
+ ## 💻 Running Demos
192
201
 
193
- 本项目提供了完整基于 NPM React Vue 示例工程,位于 `examples` 目录下。
202
+ This project includes complete NPM-based user examples for React and Vue in the `examples` directory.
194
203
 
195
- ### 启动 React Demo
204
+ ### Start React Demo
196
205
 
197
206
  ```bash
198
207
  cd examples/react-demo
199
208
  npm install
200
209
  npm run dev
210
+ # Demo runs at http://localhost:5179
201
211
  ```
202
212
 
203
- ### 启动 Vue Demo
213
+ ### Start Vue Demo
204
214
 
205
215
  ```bash
206
216
  cd examples/vue-demo
207
217
  npm install
208
218
  npm run dev
219
+ # Demo runs at http://localhost:5180
209
220
  ```
210
221
 
211
- ## 📁 项目结构
222
+ ## 📁 Project Structure
212
223
 
213
224
  ```
214
225
  smart-ticker/
215
226
  ├── src/
216
227
  │ ├── components/
217
- │ │ ├── Ticker.tsx # React 组件源码
218
- │ │ ├── Ticker.css # 组件核心样式
228
+ │ │ ├── Ticker.tsx # React Component Source
229
+ │ │ ├── Ticker.css # Component Core Styles
219
230
  │ │ └── vue/
220
- │ │ └── Ticker.vue # Vue 组件源码
231
+ │ │ └── Ticker.vue # Vue Component Source
221
232
  │ ├── core/
222
- │ │ └── TickerCore.ts # 核心逻辑(Levenshtein diff 算法)
233
+ │ │ └── TickerCore.ts # Core Logic (Levenshtein diff algo)
223
234
  │ └── ...
224
- ├── examples/ # 独立示例工程
235
+ ├── examples/ # Standalone Example Projects
225
236
  │ ├── react-demo/ # React Demo (Vite + React + TS)
226
237
  │ └── vue-demo/ # Vue Demo (Vite + Vue + TS)
227
238
  ├── public/
228
- │ └── vue-demo.html # 单文件 CDN 引用示例
239
+ │ └── vue-demo.html # Single File CDN Demo
229
240
  └── package.json
230
241
  ```
231
242
 
232
- ## 🎨 示例场景
243
+ ## 🎨 Example Scenarios
233
244
 
234
- - **金融数据** - 股票价格、加密货币行情
235
- - **计数器** - 访问量、点赞数
236
- - **比分牌** - 体育比赛实时比分
237
- - **机场信息牌** - 航班号、登机口
238
- - **隐私模式** - 余额隐藏/显示切换
245
+ - **Financial Data** - Stock prices, crypto rates
246
+ - **Counters** - Page views, likes
247
+ - **Scoreboards** - Real-time sports scores
248
+ - **Airport Info** - Flight numbers, gates
249
+ - **Privacy Mode** - Balance hide/show toggle
239
250
 
240
- ## 🔧 技术栈
251
+ ## 🔧 Tech Stack
241
252
 
242
- - **构建工具**: Vite
243
- - **语言**: TypeScript
244
- - **框架**: React 18 / Vue 3
245
- - **样式**: CSS Variables + 响应式设计
253
+ - **Build Tool**: Vite
254
+ - **Language**: TypeScript
255
+ - **Frameworks**: React 18 / Vue 3
256
+ - **Styling**: CSS Variables + Responsive Design
246
257
 
247
- ## 📝 更新日志
258
+ ## 📝 Changelog
248
259
 
249
- 查看 [CHANGELOG.md](./CHANGELOG.md) 了解版本更新详情。
260
+ See [CHANGELOG_EN.md](./CHANGELOG_EN.md) for version history.
250
261
 
251
262
  ## 📄 License
263
+
252
264
  MIT
@@ -3,10 +3,35 @@ var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  const EMPTY_CHAR = "\0";
6
- const TickerUtils = {
7
- provideNumberList: () => "0123456789",
8
- provideAlphabeticalList: () => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
6
+ const Presets = {
7
+ NUMBER: "0123456789",
8
+ ALPHABET: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
9
+ ALPHANUMERIC: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
10
+ // 常用货币字符:数字 + 标点 货币符号不穿滚动不加
11
+ CURRENCY: "0123456789.,"
9
12
  };
13
+ const TickerConstants = {
14
+ CHAR_HEIGHT: 1.2,
15
+ // em
16
+ DEFAULT_DURATION: 500,
17
+ // ms
18
+ DEFAULT_MIN_SCALE: 0.1,
19
+ FW_RATIO: 1.25,
20
+ // 中文字符宽度1.25em
21
+ HW_RATIO: 0.75
22
+ // 英文字符宽度0.75em
23
+ };
24
+ const isFW = (c) => {
25
+ if (!c || c.length === 0) return false;
26
+ const code = c.codePointAt(0) || 0;
27
+ return code >= 12288 && code <= 40959 || // CJK 标点 + 汉字
28
+ code >= 44032 && code <= 55215 || // 韩文
29
+ code >= 65280 && code <= 65519 || // 全角 ASCII
30
+ code >= 127744 && code <= 129791 || // Emoji 范围
31
+ code >= 9728 && code <= 10175 || // Misc Symbols (e.g. ☀, ☂, ☁) & Dingbats
32
+ code >= 11008 && code <= 11263;
33
+ };
34
+ const getW = (c) => isFW(c) ? TickerConstants.FW_RATIO : TickerConstants.HW_RATIO;
10
35
  class TickerCharacterList {
11
36
  constructor(characterList) {
12
37
  __publicField(this, "numOriginalCharacters");
@@ -227,17 +252,26 @@ const easingFunctions = {
227
252
  } else {
228
253
  return n1 * (t -= 2.625 / d1) * t + 0.984375;
229
254
  }
255
+ },
256
+ easeOutCubic: (t) => 1 - Math.pow(1 - t, 3),
257
+ easeOutExpo: (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),
258
+ backOut: (t) => {
259
+ const c1 = 1.70158;
260
+ const c3 = c1 + 1;
261
+ return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
230
262
  }
231
263
  };
232
264
  exports.ACTION_DELETE = ACTION_DELETE;
233
265
  exports.ACTION_INSERT = ACTION_INSERT;
234
266
  exports.ACTION_SAME = ACTION_SAME;
235
267
  exports.EMPTY_CHAR = EMPTY_CHAR;
268
+ exports.Presets = Presets;
236
269
  exports.TickerCharacterList = TickerCharacterList;
237
- exports.TickerUtils = TickerUtils;
270
+ exports.TickerConstants = TickerConstants;
238
271
  exports.applyProgress = applyProgress;
239
272
  exports.computeColumnActions = computeColumnActions;
240
273
  exports.createColumn = createColumn;
241
274
  exports.easingFunctions = easingFunctions;
275
+ exports.getW = getW;
242
276
  exports.setTarget = setTarget;
243
- //# sourceMappingURL=TickerCore-BAsdPrD1.cjs.map
277
+ //# sourceMappingURL=TickerCore-D-qtiXMY.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TickerCore-D-qtiXMY.cjs","sources":["../src/core/TickerCore.ts"],"sourcesContent":["// ============================================================================\r\n// Constants\r\n// ============================================================================\r\nexport const EMPTY_CHAR = '\\0';\r\n\r\nexport const Presets = {\r\n NUMBER: '0123456789',\r\n ALPHABET: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',\r\n ALPHANUMERIC: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',\r\n // 常用货币字符:数字 + 标点 货币符号不穿滚动不加\r\n CURRENCY: '0123456789.,',\r\n};\r\n\r\nexport type ScrollingDirection = 'ANY' | 'UP' | 'DOWN';\r\n\r\n// ============================================================================\r\n// Defaults & Helpers\r\n// ============================================================================\r\nexport const TickerConstants = {\r\n CHAR_HEIGHT: 1.2, // em\r\n DEFAULT_DURATION: 500, // ms\r\n DEFAULT_MIN_SCALE: 0.1,\r\n FW_RATIO: 1.25, // 中文字符宽度1.25em\r\n HW_RATIO: 0.75, // 英文字符宽度0.75em\r\n};\r\n\r\n// Check if character is full-width (CJK, Emoji, etc.)\r\nexport const isFW = (c: string): boolean => {\r\n if (!c || c.length === 0) return false;\r\n const code = c.codePointAt(0) || 0;\r\n return (\r\n (code >= 0x3000 && code <= 0x9FFF) || // CJK 标点 + 汉字\r\n (code >= 0xAC00 && code <= 0xD7AF) || // 韩文\r\n (code >= 0xFF00 && code <= 0xFFEF) || // 全角 ASCII\r\n (code >= 0x1F300 && code <= 0x1FAFF) || // Emoji 范围\r\n (code >= 0x2600 && code <= 0x27BF) || // Misc Symbols (e.g. ☀, ☂, ☁) & Dingbats\r\n (code >= 0x2B00 && code <= 0x2BFF) // Misc Symbols and Arrows (e.g. ⭐ 0x2B50)\r\n );\r\n};\r\n\r\nexport const getW = (c: string): number => isFW(c) ? TickerConstants.FW_RATIO : TickerConstants.HW_RATIO;\r\n\r\n// ============================================================================\r\n// TickerCharacterList\r\n// ============================================================================\r\nexport class TickerCharacterList {\r\n private numOriginalCharacters: number;\r\n private characterList: string[];\r\n private characterIndicesMap: Map<string, number>;\r\n\r\n constructor(characterList: string) {\r\n const charsArray = [...characterList];\r\n const length = charsArray.length;\r\n this.numOriginalCharacters = length;\r\n this.characterIndicesMap = new Map();\r\n\r\n for (let i = 0; i < length; i++) {\r\n this.characterIndicesMap.set(charsArray[i], i);\r\n }\r\n\r\n this.characterList = new Array(length * 2 + 1);\r\n this.characterList[0] = EMPTY_CHAR;\r\n for (let i = 0; i < length; i++) {\r\n this.characterList[1 + i] = charsArray[i];\r\n this.characterList[1 + length + i] = charsArray[i];\r\n }\r\n }\r\n\r\n getCharacterIndices(\r\n start: string,\r\n end: string,\r\n direction: ScrollingDirection\r\n ): { startIndex: number; endIndex: number } | null {\r\n let startIndex = this.getIndexOfChar(start);\r\n let endIndex = this.getIndexOfChar(end);\r\n\r\n if (startIndex < 0 || endIndex < 0) return null;\r\n\r\n switch (direction) {\r\n case 'DOWN':\r\n if (end === EMPTY_CHAR) {\r\n endIndex = this.characterList.length;\r\n } else if (endIndex < startIndex) {\r\n endIndex += this.numOriginalCharacters;\r\n }\r\n break;\r\n case 'UP':\r\n if (startIndex < endIndex) {\r\n startIndex += this.numOriginalCharacters;\r\n }\r\n break;\r\n case 'ANY':\r\n if (start !== EMPTY_CHAR && end !== EMPTY_CHAR) {\r\n if (endIndex < startIndex) {\r\n const nonWrap = startIndex - endIndex;\r\n const wrap = this.numOriginalCharacters - startIndex + endIndex;\r\n if (wrap < nonWrap) endIndex += this.numOriginalCharacters;\r\n } else if (startIndex < endIndex) {\r\n const nonWrap = endIndex - startIndex;\r\n const wrap = this.numOriginalCharacters - endIndex + startIndex;\r\n if (wrap < nonWrap) startIndex += this.numOriginalCharacters;\r\n }\r\n }\r\n break;\r\n }\r\n return { startIndex, endIndex };\r\n }\r\n\r\n getSupportedCharacters(): Set<string> {\r\n return new Set(this.characterIndicesMap.keys());\r\n }\r\n\r\n getCharacterList(): string[] {\r\n return this.characterList;\r\n }\r\n\r\n private getIndexOfChar(c: string): number {\r\n if (c === EMPTY_CHAR) return 0;\r\n if (this.characterIndicesMap.has(c)) return this.characterIndicesMap.get(c)! + 1;\r\n return -1;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Levenshtein\r\n// ============================================================================\r\nexport const ACTION_SAME = 0;\r\nexport const ACTION_INSERT = 1;\r\nexport const ACTION_DELETE = 2;\r\n\r\nexport function computeColumnActions(source: string[], target: string[], supported: Set<string>): number[] {\r\n let si = 0, ti = 0;\r\n const actions: number[] = [];\r\n\r\n while (true) {\r\n const endS = si === source.length;\r\n const endT = ti === target.length;\r\n if (endS && endT) break;\r\n if (endS) { for (; ti < target.length; ti++) actions.push(ACTION_INSERT); break; }\r\n if (endT) { for (; si < source.length; si++) actions.push(ACTION_DELETE); break; }\r\n\r\n const sSupp = supported.has(source[si]);\r\n const tSupp = supported.has(target[ti]);\r\n\r\n if (sSupp && tSupp) {\r\n let se = si + 1, te = ti + 1;\r\n while (se < source.length && supported.has(source[se])) se++;\r\n while (te < target.length && supported.has(target[te])) te++;\r\n\r\n const sLen = se - si, tLen = te - ti;\r\n if (sLen === tLen) {\r\n for (let i = 0; i < sLen; i++) actions.push(ACTION_SAME);\r\n } else {\r\n const matrix: number[][] = Array(sLen + 1).fill(null).map(() => Array(tLen + 1).fill(0));\r\n for (let i = 0; i <= sLen; i++) matrix[i][0] = i;\r\n for (let j = 0; j <= tLen; j++) matrix[0][j] = j;\r\n for (let r = 1; r <= sLen; r++) {\r\n for (let c = 1; c <= tLen; c++) {\r\n const cost = source[si + r - 1] === target[ti + c - 1] ? 0 : 1;\r\n matrix[r][c] = Math.min(matrix[r - 1][c] + 1, matrix[r][c - 1] + 1, matrix[r - 1][c - 1] + cost);\r\n }\r\n }\r\n const result: number[] = [];\r\n let r = sLen, c = tLen;\r\n while (r > 0 || c > 0) {\r\n if (r === 0) { result.push(ACTION_INSERT); c--; }\r\n else if (c === 0) { result.push(ACTION_DELETE); r--; }\r\n else {\r\n const ins = matrix[r][c - 1], del = matrix[r - 1][c], rep = matrix[r - 1][c - 1];\r\n if (ins < del && ins < rep) { result.push(ACTION_INSERT); c--; }\r\n else if (del < rep) { result.push(ACTION_DELETE); r--; }\r\n else { result.push(ACTION_SAME); r--; c--; }\r\n }\r\n }\r\n for (let i = result.length - 1; i >= 0; i--) actions.push(result[i]);\r\n }\r\n si = se; ti = te;\r\n } else if (sSupp) { actions.push(ACTION_INSERT); ti++; }\r\n else if (tSupp) { actions.push(ACTION_DELETE); si++; }\r\n else { actions.push(ACTION_SAME); si++; ti++; }\r\n }\r\n return actions;\r\n}\r\n\r\n// ============================================================================\r\n// Column State\r\n// ============================================================================\r\nexport interface ColumnState {\r\n currentChar: string;\r\n targetChar: string;\r\n charList: string[] | null;\r\n startIndex: number;\r\n endIndex: number;\r\n sourceWidth: number;\r\n currentWidth: number;\r\n targetWidth: number;\r\n directionAdj: number;\r\n prevDelta: number;\r\n currDelta: number;\r\n}\r\n\r\nexport function createColumn(): ColumnState {\r\n return {\r\n currentChar: EMPTY_CHAR, targetChar: EMPTY_CHAR, charList: null,\r\n startIndex: 0, endIndex: 0, sourceWidth: 0, currentWidth: 0, targetWidth: 0,\r\n directionAdj: 1, prevDelta: 0, currDelta: 0,\r\n };\r\n}\r\n\r\nexport function setTarget(col: ColumnState, target: string, lists: TickerCharacterList[], dir: ScrollingDirection): ColumnState {\r\n const c = { ...col };\r\n c.targetChar = target;\r\n c.sourceWidth = c.currentWidth;\r\n c.targetWidth = target === EMPTY_CHAR ? 0 : 1;\r\n\r\n let found = false;\r\n for (const list of lists) {\r\n const indices = list.getCharacterIndices(c.currentChar, target, dir);\r\n if (indices) {\r\n c.charList = list.getCharacterList();\r\n c.startIndex = indices.startIndex;\r\n c.endIndex = indices.endIndex;\r\n found = true;\r\n break;\r\n }\r\n }\r\n if (!found) {\r\n c.charList = c.currentChar === target ? [c.currentChar] : [c.currentChar, target];\r\n c.startIndex = 0;\r\n c.endIndex = c.currentChar === target ? 0 : 1;\r\n }\r\n\r\n c.directionAdj = c.endIndex >= c.startIndex ? 1 : -1;\r\n c.prevDelta = c.currDelta;\r\n c.currDelta = 0;\r\n return c;\r\n}\r\n\r\nexport function applyProgress(col: ColumnState, progress: number, forceUpdate = false): { col: ColumnState; charIdx: number; delta: number } {\r\n const c = { ...col };\r\n const total = Math.abs(c.endIndex - c.startIndex);\r\n const pos = progress * total;\r\n const offset = pos - Math.floor(pos);\r\n const additional = c.prevDelta * (1 - progress);\r\n const delta = offset * c.directionAdj + additional;\r\n const charIdx = c.startIndex + Math.floor(pos) * c.directionAdj;\r\n\r\n if (progress >= 1) {\r\n c.currentChar = c.targetChar;\r\n c.currDelta = 0;\r\n c.prevDelta = 0;\r\n } else if (forceUpdate && c.charList && charIdx >= 0 && charIdx < c.charList.length) {\r\n c.currentChar = c.charList[charIdx];\r\n c.currDelta = delta;\r\n }\r\n\r\n c.currentWidth = c.sourceWidth + (c.targetWidth - c.sourceWidth) * progress;\r\n return { col: c, charIdx, delta };\r\n}\r\n\r\n// ============================================================================\r\n// Easing Functions\r\n// ============================================================================\r\nexport type EasingName = 'linear' | 'easeIn' | 'easeOut' | 'easeInOut' | 'bounce' | 'easeOutCubic' | 'easeOutExpo' | 'backOut';\r\n\r\nexport const easingFunctions: Record<EasingName, (t: number) => number> = {\r\n linear: (t) => t,\r\n easeIn: (t) => t * t,\r\n easeOut: (t) => 1 - (1 - t) * (1 - t),\r\n easeInOut: (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,\r\n bounce: (t) => {\r\n const n1 = 7.5625;\r\n const d1 = 2.75;\r\n if (t < 1 / d1) {\r\n return n1 * t * t;\r\n } else if (t < 2 / d1) {\r\n return n1 * (t -= 1.5 / d1) * t + 0.75;\r\n } else if (t < 2.5 / d1) {\r\n return n1 * (t -= 2.25 / d1) * t + 0.9375;\r\n } else {\r\n return n1 * (t -= 2.625 / d1) * t + 0.984375;\r\n }\r\n },\r\n easeOutCubic: (t) => 1 - Math.pow(1 - t, 3),\r\n easeOutExpo: (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),\r\n backOut: (t) => {\r\n const c1 = 1.70158;\r\n const c3 = c1 + 1;\r\n return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);\r\n },\r\n};\r\n"],"names":["r","c"],"mappings":"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"}
@@ -2,10 +2,35 @@ var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  const EMPTY_CHAR = "\0";
5
- const TickerUtils = {
6
- provideNumberList: () => "0123456789",
7
- provideAlphabeticalList: () => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
5
+ const Presets = {
6
+ NUMBER: "0123456789",
7
+ ALPHABET: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
8
+ ALPHANUMERIC: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
9
+ // 常用货币字符:数字 + 标点 货币符号不穿滚动不加
10
+ CURRENCY: "0123456789.,"
8
11
  };
12
+ const TickerConstants = {
13
+ CHAR_HEIGHT: 1.2,
14
+ // em
15
+ DEFAULT_DURATION: 500,
16
+ // ms
17
+ DEFAULT_MIN_SCALE: 0.1,
18
+ FW_RATIO: 1.25,
19
+ // 中文字符宽度1.25em
20
+ HW_RATIO: 0.75
21
+ // 英文字符宽度0.75em
22
+ };
23
+ const isFW = (c) => {
24
+ if (!c || c.length === 0) return false;
25
+ const code = c.codePointAt(0) || 0;
26
+ return code >= 12288 && code <= 40959 || // CJK 标点 + 汉字
27
+ code >= 44032 && code <= 55215 || // 韩文
28
+ code >= 65280 && code <= 65519 || // 全角 ASCII
29
+ code >= 127744 && code <= 129791 || // Emoji 范围
30
+ code >= 9728 && code <= 10175 || // Misc Symbols (e.g. ☀, ☂, ☁) & Dingbats
31
+ code >= 11008 && code <= 11263;
32
+ };
33
+ const getW = (c) => isFW(c) ? TickerConstants.FW_RATIO : TickerConstants.HW_RATIO;
9
34
  class TickerCharacterList {
10
35
  constructor(characterList) {
11
36
  __publicField(this, "numOriginalCharacters");
@@ -226,19 +251,28 @@ const easingFunctions = {
226
251
  } else {
227
252
  return n1 * (t -= 2.625 / d1) * t + 0.984375;
228
253
  }
254
+ },
255
+ easeOutCubic: (t) => 1 - Math.pow(1 - t, 3),
256
+ easeOutExpo: (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),
257
+ backOut: (t) => {
258
+ const c1 = 1.70158;
259
+ const c3 = c1 + 1;
260
+ return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
229
261
  }
230
262
  };
231
263
  export {
232
264
  ACTION_INSERT as A,
233
265
  EMPTY_CHAR as E,
234
- TickerUtils as T,
235
- TickerCharacterList as a,
236
- applyProgress as b,
266
+ Presets as P,
267
+ TickerCharacterList as T,
268
+ applyProgress as a,
269
+ TickerConstants as b,
237
270
  computeColumnActions as c,
238
271
  createColumn as d,
239
272
  ACTION_SAME as e,
240
273
  easingFunctions as f,
241
- ACTION_DELETE as g,
274
+ getW as g,
275
+ ACTION_DELETE as h,
242
276
  setTarget as s
243
277
  };
244
- //# sourceMappingURL=TickerCore-C7Ejc9kB.js.map
278
+ //# sourceMappingURL=TickerCore-D5-49bZ3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TickerCore-D5-49bZ3.js","sources":["../src/core/TickerCore.ts"],"sourcesContent":["// ============================================================================\r\n// Constants\r\n// ============================================================================\r\nexport const EMPTY_CHAR = '\\0';\r\n\r\nexport const Presets = {\r\n NUMBER: '0123456789',\r\n ALPHABET: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',\r\n ALPHANUMERIC: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',\r\n // 常用货币字符:数字 + 标点 货币符号不穿滚动不加\r\n CURRENCY: '0123456789.,',\r\n};\r\n\r\nexport type ScrollingDirection = 'ANY' | 'UP' | 'DOWN';\r\n\r\n// ============================================================================\r\n// Defaults & Helpers\r\n// ============================================================================\r\nexport const TickerConstants = {\r\n CHAR_HEIGHT: 1.2, // em\r\n DEFAULT_DURATION: 500, // ms\r\n DEFAULT_MIN_SCALE: 0.1,\r\n FW_RATIO: 1.25, // 中文字符宽度1.25em\r\n HW_RATIO: 0.75, // 英文字符宽度0.75em\r\n};\r\n\r\n// Check if character is full-width (CJK, Emoji, etc.)\r\nexport const isFW = (c: string): boolean => {\r\n if (!c || c.length === 0) return false;\r\n const code = c.codePointAt(0) || 0;\r\n return (\r\n (code >= 0x3000 && code <= 0x9FFF) || // CJK 标点 + 汉字\r\n (code >= 0xAC00 && code <= 0xD7AF) || // 韩文\r\n (code >= 0xFF00 && code <= 0xFFEF) || // 全角 ASCII\r\n (code >= 0x1F300 && code <= 0x1FAFF) || // Emoji 范围\r\n (code >= 0x2600 && code <= 0x27BF) || // Misc Symbols (e.g. ☀, ☂, ☁) & Dingbats\r\n (code >= 0x2B00 && code <= 0x2BFF) // Misc Symbols and Arrows (e.g. ⭐ 0x2B50)\r\n );\r\n};\r\n\r\nexport const getW = (c: string): number => isFW(c) ? TickerConstants.FW_RATIO : TickerConstants.HW_RATIO;\r\n\r\n// ============================================================================\r\n// TickerCharacterList\r\n// ============================================================================\r\nexport class TickerCharacterList {\r\n private numOriginalCharacters: number;\r\n private characterList: string[];\r\n private characterIndicesMap: Map<string, number>;\r\n\r\n constructor(characterList: string) {\r\n const charsArray = [...characterList];\r\n const length = charsArray.length;\r\n this.numOriginalCharacters = length;\r\n this.characterIndicesMap = new Map();\r\n\r\n for (let i = 0; i < length; i++) {\r\n this.characterIndicesMap.set(charsArray[i], i);\r\n }\r\n\r\n this.characterList = new Array(length * 2 + 1);\r\n this.characterList[0] = EMPTY_CHAR;\r\n for (let i = 0; i < length; i++) {\r\n this.characterList[1 + i] = charsArray[i];\r\n this.characterList[1 + length + i] = charsArray[i];\r\n }\r\n }\r\n\r\n getCharacterIndices(\r\n start: string,\r\n end: string,\r\n direction: ScrollingDirection\r\n ): { startIndex: number; endIndex: number } | null {\r\n let startIndex = this.getIndexOfChar(start);\r\n let endIndex = this.getIndexOfChar(end);\r\n\r\n if (startIndex < 0 || endIndex < 0) return null;\r\n\r\n switch (direction) {\r\n case 'DOWN':\r\n if (end === EMPTY_CHAR) {\r\n endIndex = this.characterList.length;\r\n } else if (endIndex < startIndex) {\r\n endIndex += this.numOriginalCharacters;\r\n }\r\n break;\r\n case 'UP':\r\n if (startIndex < endIndex) {\r\n startIndex += this.numOriginalCharacters;\r\n }\r\n break;\r\n case 'ANY':\r\n if (start !== EMPTY_CHAR && end !== EMPTY_CHAR) {\r\n if (endIndex < startIndex) {\r\n const nonWrap = startIndex - endIndex;\r\n const wrap = this.numOriginalCharacters - startIndex + endIndex;\r\n if (wrap < nonWrap) endIndex += this.numOriginalCharacters;\r\n } else if (startIndex < endIndex) {\r\n const nonWrap = endIndex - startIndex;\r\n const wrap = this.numOriginalCharacters - endIndex + startIndex;\r\n if (wrap < nonWrap) startIndex += this.numOriginalCharacters;\r\n }\r\n }\r\n break;\r\n }\r\n return { startIndex, endIndex };\r\n }\r\n\r\n getSupportedCharacters(): Set<string> {\r\n return new Set(this.characterIndicesMap.keys());\r\n }\r\n\r\n getCharacterList(): string[] {\r\n return this.characterList;\r\n }\r\n\r\n private getIndexOfChar(c: string): number {\r\n if (c === EMPTY_CHAR) return 0;\r\n if (this.characterIndicesMap.has(c)) return this.characterIndicesMap.get(c)! + 1;\r\n return -1;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Levenshtein\r\n// ============================================================================\r\nexport const ACTION_SAME = 0;\r\nexport const ACTION_INSERT = 1;\r\nexport const ACTION_DELETE = 2;\r\n\r\nexport function computeColumnActions(source: string[], target: string[], supported: Set<string>): number[] {\r\n let si = 0, ti = 0;\r\n const actions: number[] = [];\r\n\r\n while (true) {\r\n const endS = si === source.length;\r\n const endT = ti === target.length;\r\n if (endS && endT) break;\r\n if (endS) { for (; ti < target.length; ti++) actions.push(ACTION_INSERT); break; }\r\n if (endT) { for (; si < source.length; si++) actions.push(ACTION_DELETE); break; }\r\n\r\n const sSupp = supported.has(source[si]);\r\n const tSupp = supported.has(target[ti]);\r\n\r\n if (sSupp && tSupp) {\r\n let se = si + 1, te = ti + 1;\r\n while (se < source.length && supported.has(source[se])) se++;\r\n while (te < target.length && supported.has(target[te])) te++;\r\n\r\n const sLen = se - si, tLen = te - ti;\r\n if (sLen === tLen) {\r\n for (let i = 0; i < sLen; i++) actions.push(ACTION_SAME);\r\n } else {\r\n const matrix: number[][] = Array(sLen + 1).fill(null).map(() => Array(tLen + 1).fill(0));\r\n for (let i = 0; i <= sLen; i++) matrix[i][0] = i;\r\n for (let j = 0; j <= tLen; j++) matrix[0][j] = j;\r\n for (let r = 1; r <= sLen; r++) {\r\n for (let c = 1; c <= tLen; c++) {\r\n const cost = source[si + r - 1] === target[ti + c - 1] ? 0 : 1;\r\n matrix[r][c] = Math.min(matrix[r - 1][c] + 1, matrix[r][c - 1] + 1, matrix[r - 1][c - 1] + cost);\r\n }\r\n }\r\n const result: number[] = [];\r\n let r = sLen, c = tLen;\r\n while (r > 0 || c > 0) {\r\n if (r === 0) { result.push(ACTION_INSERT); c--; }\r\n else if (c === 0) { result.push(ACTION_DELETE); r--; }\r\n else {\r\n const ins = matrix[r][c - 1], del = matrix[r - 1][c], rep = matrix[r - 1][c - 1];\r\n if (ins < del && ins < rep) { result.push(ACTION_INSERT); c--; }\r\n else if (del < rep) { result.push(ACTION_DELETE); r--; }\r\n else { result.push(ACTION_SAME); r--; c--; }\r\n }\r\n }\r\n for (let i = result.length - 1; i >= 0; i--) actions.push(result[i]);\r\n }\r\n si = se; ti = te;\r\n } else if (sSupp) { actions.push(ACTION_INSERT); ti++; }\r\n else if (tSupp) { actions.push(ACTION_DELETE); si++; }\r\n else { actions.push(ACTION_SAME); si++; ti++; }\r\n }\r\n return actions;\r\n}\r\n\r\n// ============================================================================\r\n// Column State\r\n// ============================================================================\r\nexport interface ColumnState {\r\n currentChar: string;\r\n targetChar: string;\r\n charList: string[] | null;\r\n startIndex: number;\r\n endIndex: number;\r\n sourceWidth: number;\r\n currentWidth: number;\r\n targetWidth: number;\r\n directionAdj: number;\r\n prevDelta: number;\r\n currDelta: number;\r\n}\r\n\r\nexport function createColumn(): ColumnState {\r\n return {\r\n currentChar: EMPTY_CHAR, targetChar: EMPTY_CHAR, charList: null,\r\n startIndex: 0, endIndex: 0, sourceWidth: 0, currentWidth: 0, targetWidth: 0,\r\n directionAdj: 1, prevDelta: 0, currDelta: 0,\r\n };\r\n}\r\n\r\nexport function setTarget(col: ColumnState, target: string, lists: TickerCharacterList[], dir: ScrollingDirection): ColumnState {\r\n const c = { ...col };\r\n c.targetChar = target;\r\n c.sourceWidth = c.currentWidth;\r\n c.targetWidth = target === EMPTY_CHAR ? 0 : 1;\r\n\r\n let found = false;\r\n for (const list of lists) {\r\n const indices = list.getCharacterIndices(c.currentChar, target, dir);\r\n if (indices) {\r\n c.charList = list.getCharacterList();\r\n c.startIndex = indices.startIndex;\r\n c.endIndex = indices.endIndex;\r\n found = true;\r\n break;\r\n }\r\n }\r\n if (!found) {\r\n c.charList = c.currentChar === target ? [c.currentChar] : [c.currentChar, target];\r\n c.startIndex = 0;\r\n c.endIndex = c.currentChar === target ? 0 : 1;\r\n }\r\n\r\n c.directionAdj = c.endIndex >= c.startIndex ? 1 : -1;\r\n c.prevDelta = c.currDelta;\r\n c.currDelta = 0;\r\n return c;\r\n}\r\n\r\nexport function applyProgress(col: ColumnState, progress: number, forceUpdate = false): { col: ColumnState; charIdx: number; delta: number } {\r\n const c = { ...col };\r\n const total = Math.abs(c.endIndex - c.startIndex);\r\n const pos = progress * total;\r\n const offset = pos - Math.floor(pos);\r\n const additional = c.prevDelta * (1 - progress);\r\n const delta = offset * c.directionAdj + additional;\r\n const charIdx = c.startIndex + Math.floor(pos) * c.directionAdj;\r\n\r\n if (progress >= 1) {\r\n c.currentChar = c.targetChar;\r\n c.currDelta = 0;\r\n c.prevDelta = 0;\r\n } else if (forceUpdate && c.charList && charIdx >= 0 && charIdx < c.charList.length) {\r\n c.currentChar = c.charList[charIdx];\r\n c.currDelta = delta;\r\n }\r\n\r\n c.currentWidth = c.sourceWidth + (c.targetWidth - c.sourceWidth) * progress;\r\n return { col: c, charIdx, delta };\r\n}\r\n\r\n// ============================================================================\r\n// Easing Functions\r\n// ============================================================================\r\nexport type EasingName = 'linear' | 'easeIn' | 'easeOut' | 'easeInOut' | 'bounce' | 'easeOutCubic' | 'easeOutExpo' | 'backOut';\r\n\r\nexport const easingFunctions: Record<EasingName, (t: number) => number> = {\r\n linear: (t) => t,\r\n easeIn: (t) => t * t,\r\n easeOut: (t) => 1 - (1 - t) * (1 - t),\r\n easeInOut: (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,\r\n bounce: (t) => {\r\n const n1 = 7.5625;\r\n const d1 = 2.75;\r\n if (t < 1 / d1) {\r\n return n1 * t * t;\r\n } else if (t < 2 / d1) {\r\n return n1 * (t -= 1.5 / d1) * t + 0.75;\r\n } else if (t < 2.5 / d1) {\r\n return n1 * (t -= 2.25 / d1) * t + 0.9375;\r\n } else {\r\n return n1 * (t -= 2.625 / d1) * t + 0.984375;\r\n }\r\n },\r\n easeOutCubic: (t) => 1 - Math.pow(1 - t, 3),\r\n easeOutExpo: (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),\r\n backOut: (t) => {\r\n const c1 = 1.70158;\r\n const c3 = c1 + 1;\r\n return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);\r\n },\r\n};\r\n"],"names":["r","c"],"mappings":"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"}