* @param {T} new_value * @param {SpringUpdateOptions} opts * @returns {Promise<void>}
(new_value, opts = {})
| 87 | * @returns {Promise<void>} |
| 88 | */ |
| 89 | function set(new_value, opts = {}) { |
| 90 | target_value = new_value; |
| 91 | const token = (current_token = {}); |
| 92 | if (value == null || opts.hard || (spring.stiffness >= 1 && spring.damping >= 1)) { |
| 93 | cancel_task = true; // cancel any running animation |
| 94 | last_time = raf.now(); |
| 95 | last_value = new_value; |
| 96 | store.set((value = target_value)); |
| 97 | return Promise.resolve(); |
| 98 | } else if (opts.soft) { |
| 99 | const rate = opts.soft === true ? 0.5 : +opts.soft; |
| 100 | inv_mass_recovery_rate = 1 / (rate * 60); |
| 101 | inv_mass = 0; // infinite mass, unaffected by spring forces |
| 102 | } |
| 103 | if (!task) { |
| 104 | last_time = raf.now(); |
| 105 | cancel_task = false; |
| 106 | task = loop((now) => { |
| 107 | if (cancel_task) { |
| 108 | cancel_task = false; |
| 109 | task = null; |
| 110 | return false; |
| 111 | } |
| 112 | inv_mass = Math.min(inv_mass + inv_mass_recovery_rate, 1); |
| 113 | |
| 114 | // clamp elapsed time to 1/30th of a second, so that longer pauses |
| 115 | // (blocked thread or inactive tab) don't cause the spring to go haywire |
| 116 | const elapsed = Math.min(now - last_time, 1000 / 30); |
| 117 | |
| 118 | /** @type {TickContext} */ |
| 119 | const ctx = { |
| 120 | inv_mass, |
| 121 | opts: spring, |
| 122 | settled: true, |
| 123 | dt: (elapsed * 60) / 1000 |
| 124 | }; |
| 125 | // @ts-ignore |
| 126 | const next_value = tick_spring(ctx, last_value, value, target_value); |
| 127 | last_time = now; |
| 128 | last_value = /** @type {T} */ (value); |
| 129 | store.set((value = /** @type {T} */ (next_value))); |
| 130 | if (ctx.settled) { |
| 131 | task = null; |
| 132 | } |
| 133 | return !ctx.settled; |
| 134 | }); |
| 135 | } |
| 136 | return new Promise((fulfil) => { |
| 137 | /** @type {Task} */ (task).promise.then(() => { |
| 138 | if (token === current_token) fulfil(); |
| 139 | }); |
| 140 | }); |
| 141 | } |
| 142 | /** @type {SpringStore<T>} */ |
| 143 | // @ts-expect-error - class-only properties are missing |
| 144 | const spring = { |