queue.mjs 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. import { removeItem } from 'motion-utils';
  2. import { microtask } from '../frameloop/microtask.mjs';
  3. import { startViewAnimation } from './start.mjs';
  4. let builders = [];
  5. let current = null;
  6. function next() {
  7. current = null;
  8. const [nextBuilder] = builders;
  9. if (nextBuilder)
  10. start(nextBuilder);
  11. }
  12. function start(builder) {
  13. removeItem(builders, builder);
  14. current = builder;
  15. startViewAnimation(builder).then((animation) => {
  16. builder.notifyReady(animation);
  17. animation.finished.finally(next);
  18. });
  19. }
  20. function processQueue() {
  21. /**
  22. * Iterate backwards over the builders array. We can ignore the
  23. * "wait" animations. If we have an interrupting animation in the
  24. * queue then we need to batch all preceeding animations into it.
  25. * Currently this only batches the update functions but will also
  26. * need to batch the targets.
  27. */
  28. for (let i = builders.length - 1; i >= 0; i--) {
  29. const builder = builders[i];
  30. const { interrupt } = builder.options;
  31. if (interrupt === "immediate") {
  32. const batchedUpdates = builders.slice(0, i + 1).map((b) => b.update);
  33. const remaining = builders.slice(i + 1);
  34. builder.update = () => {
  35. batchedUpdates.forEach((update) => update());
  36. };
  37. // Put the current builder at the front, followed by any "wait" builders
  38. builders = [builder, ...remaining];
  39. break;
  40. }
  41. }
  42. if (!current || builders[0]?.options.interrupt === "immediate") {
  43. next();
  44. }
  45. }
  46. function addToQueue(builder) {
  47. builders.push(builder);
  48. microtask.render(processQueue);
  49. }
  50. export { addToQueue };