@weasel-js/animator 1.15.2 → 1.16.0

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.
@@ -722,12 +722,11 @@ function createTargetTable(opts) {
722
722
  tables.set(table, rows);
723
723
  return table;
724
724
  }
725
-
726
- // src/colorRegistry.ts
727
725
  var ColorOverrideRegistry = class {
728
726
  map = /* @__PURE__ */ new Map();
729
727
  slots = /* @__PURE__ */ new Map();
730
728
  tables = /* @__PURE__ */ new Map();
729
+ listeners = createEmitter();
731
730
  _version = 0;
732
731
  set(id, channel, override) {
733
732
  let entry = this.map.get(id);
@@ -736,7 +735,7 @@ var ColorOverrideRegistry = class {
736
735
  this.map.set(id, entry);
737
736
  }
738
737
  entry[channel] = override;
739
- this._version++;
738
+ this.changed();
740
739
  }
741
740
  /** Drops `id`'s override on `channel`, and the colors a finished or canceled animation on its
742
741
  * {@link target} left painted. An animation still running goes on. */
@@ -747,7 +746,7 @@ var ColorOverrideRegistry = class {
747
746
  if (!(channel in entry)) return;
748
747
  delete entry[channel];
749
748
  if (!entry.fill && !entry.stroke) this.map.delete(id);
750
- this._version++;
749
+ this.changed();
751
750
  }
752
751
  clearAll() {
753
752
  for (const [id, node] of this.slots) {
@@ -755,7 +754,7 @@ var ColorOverrideRegistry = class {
755
754
  }
756
755
  if (this.map.size === 0) return;
757
756
  this.map.clear();
758
- this._version++;
757
+ this.changed();
759
758
  }
760
759
  /** What `set` stored for `id`'s `channel`; failing that, the colors its {@link target} paints. */
761
760
  get(id, channel) {
@@ -764,9 +763,12 @@ var ColorOverrideRegistry = class {
764
763
  const slot = this.slots.get(id)?.[channel];
765
764
  return slot?.painted ? shownOf(slot) : void 0;
766
765
  }
767
- /** Whether anything overrides `id`, on either channel. */
766
+ /** Whether anything paints over `id`, on either channel: an override from `set`, or a target
767
+ * an animation has committed. A target asked for and never moved does not count. */
768
768
  has(id) {
769
- return this.map.has(id) || this.slots.has(id);
769
+ if (this.map.has(id)) return true;
770
+ const node = this.slots.get(id);
771
+ return node !== void 0 && (node.fill?.painted === true || node.stroke?.painted === true);
770
772
  }
771
773
  /**
772
774
  * The {@link Target} for `id`'s colors on `channel`: `length` numbers, flat RGBA per anchor.
@@ -811,7 +813,8 @@ var ColorOverrideRegistry = class {
811
813
  set: (row) => {
812
814
  const slot = rows[row];
813
815
  if (slot) slot.painted = true;
814
- this._version++;
816
+ if (table.target(row).active) this._version++;
817
+ else this.changed();
815
818
  },
816
819
  show: () => {
817
820
  this._version++;
@@ -836,7 +839,7 @@ var ColorOverrideRegistry = class {
836
839
  delete node[channel];
837
840
  if (!node.fill && !node.stroke) this.slots.delete(id);
838
841
  this.drop(slot);
839
- if (slot.painted) this._version++;
842
+ if (slot.painted) this.changed();
840
843
  }
841
844
  /**
842
845
  * The colors to paint on `id`'s `channel`, given the colors the painter would
@@ -859,9 +862,18 @@ var ColorOverrideRegistry = class {
859
862
  const result = override(base, tMs);
860
863
  return result.length === base.length ? result : base;
861
864
  }
865
+ /** Calls `listener` after a `set`, `clear`, or release changes what paints; an animation's
866
+ * frames reach a painter through `animator.onTick` instead. Returns an unsubscribe. */
867
+ subscribe(listener) {
868
+ return this.listeners.subscribe(listener);
869
+ }
862
870
  version() {
863
871
  return this._version;
864
872
  }
873
+ changed() {
874
+ this._version++;
875
+ this.listeners.emit();
876
+ }
865
877
  };
866
878
  function shownOf(slot) {
867
879
  const { shown } = slot.table;
@@ -870,6 +882,119 @@ function shownOf(slot) {
870
882
  for (let i = 0; i < out.length; i++) out[i] = shown[at + i];
871
883
  return out;
872
884
  }
885
+ var EDGES = ["start", "end"];
886
+ var TrimOverrideRegistry = class {
887
+ map = /* @__PURE__ */ new Map();
888
+ slots = /* @__PURE__ */ new Map();
889
+ listeners = createEmitter();
890
+ _version = 0;
891
+ set(id, override) {
892
+ this.map.set(id, { ...override });
893
+ this.changed();
894
+ }
895
+ /** Drops `id`'s override, and the edges a finished or canceled animation on its
896
+ * {@link target}s left painted. An animation still running goes on. */
897
+ clear(id) {
898
+ for (const edge of EDGES) this.release(id, edge);
899
+ if (this.map.delete(id)) this.changed();
900
+ }
901
+ clearAll() {
902
+ for (const [id, node] of [...this.slots]) {
903
+ for (const edge of Object.keys(node)) this.release(id, edge);
904
+ }
905
+ if (this.map.size === 0) return;
906
+ this.map.clear();
907
+ this.changed();
908
+ }
909
+ /** What paints on `id`'s edges now: see {@link resolve}. */
910
+ get(id) {
911
+ return this.resolve(id);
912
+ }
913
+ /** Whether anything paints over `id`'s trim: an override from `set`, or a target an
914
+ * animation has committed. A target asked for and never moved does not count. */
915
+ has(id) {
916
+ if (this.map.has(id)) return true;
917
+ const node = this.slots.get(id);
918
+ return node !== void 0 && (node.start?.painted === true || node.end?.painted === true);
919
+ }
920
+ /**
921
+ * The {@link Target} for `id`'s `edge`, committed at the whole stroke's (`start` 0, `end` 1)
922
+ * until something moves it. Every caller for one node and edge gets the same one, so their
923
+ * animations add. The registry holds its committed value and nothing writes the scene.
924
+ *
925
+ * What it paints, on its own edge only: with no override from `set` on that edge, its value in
926
+ * place of the stroke's own; over one, only what its animations have left to travel, added on
927
+ * top. Ask again for each animation rather than keeping it: {@link release} and {@link clear}
928
+ * drop a resting one, and the target it had throws from then on.
929
+ */
930
+ target(id, edge) {
931
+ let node = this.slots.get(id);
932
+ const held = node?.[edge];
933
+ if (held) return held.target;
934
+ const state = { value: edge === "start" ? 0 : 1, painted: false, released: false };
935
+ const target = createTarget({
936
+ get: () => state.value,
937
+ set: (value) => {
938
+ if (state.released) throw new Error(`trim overrides: ${id}'s ${edge} target was released`);
939
+ state.value = value;
940
+ state.painted = true;
941
+ if (target.active) this._version++;
942
+ else this.changed();
943
+ },
944
+ show: () => {
945
+ this._version++;
946
+ }
947
+ });
948
+ if (!node) {
949
+ node = {};
950
+ this.slots.set(id, node);
951
+ }
952
+ node[edge] = Object.assign(state, { target });
953
+ return target;
954
+ }
955
+ /** Drops the value `id`'s {@link target} on `edge` left painted, unless an animation is still
956
+ * moving it. An override from `set` stays. */
957
+ release(id, edge) {
958
+ const node = this.slots.get(id);
959
+ const slot = node?.[edge];
960
+ if (!node || !slot || slot.target.active) return;
961
+ delete node[edge];
962
+ if (!node.start && !node.end) this.slots.delete(id);
963
+ slot.released = true;
964
+ if (slot.painted) this.changed();
965
+ }
966
+ /**
967
+ * The edges to paint on `id`'s stroke, each on its own: the override from `set` for that
968
+ * edge plus what its {@link target} has left to travel; failing a `set` value, the target's
969
+ * value once an animation has committed it. An edge with neither is left out, so the stroke's
970
+ * own stands. `undefined` when neither edge is overridden.
971
+ */
972
+ resolve(id) {
973
+ const override = this.map.get(id);
974
+ const node = this.slots.get(id);
975
+ const start = edgeOf(override?.start, node?.start);
976
+ const end = edgeOf(override?.end, node?.end);
977
+ if (start === void 0 && end === void 0) return void 0;
978
+ return { ...start !== void 0 ? { start } : {}, ...end !== void 0 ? { end } : {} };
979
+ }
980
+ /** Calls `listener` after a `set`, `clear`, or release changes what paints; an animation's
981
+ * frames reach a painter through `animator.onTick` instead. Returns an unsubscribe. */
982
+ subscribe(listener) {
983
+ return this.listeners.subscribe(listener);
984
+ }
985
+ version() {
986
+ return this._version;
987
+ }
988
+ changed() {
989
+ this._version++;
990
+ this.listeners.emit();
991
+ }
992
+ };
993
+ function edgeOf(set, slot) {
994
+ const painted = slot?.painted === true;
995
+ if (set === void 0) return painted ? slot.target.read() : void 0;
996
+ return painted && slot.target.active ? set + slot.target.read() - slot.value : set;
997
+ }
873
998
  function axesFor(axes, value, what) {
874
999
  const a = axes.to(value);
875
1000
  if (a.length !== axes.count || !a.every((x) => typeof x === "number" && !Number.isNaN(x))) {
@@ -1609,6 +1734,6 @@ function createTimeline(register, id, opts, report, hold) {
1609
1734
  };
1610
1735
  }
1611
1736
 
1612
- export { ColorOverrideRegistry, absorb, axesFor, axesOf, axisIndexes, bump, bumpOn, comeOut, commitOffset, committedInto, createHoldStore, createTarget, createTargetBook, createTargetTable, createTimeline, goBehind, isTarget, minus, norm, plus, rowTableOf, runsOn, sampleTrack, seat, setBeside, shareBehind, stateOf, takeUp, times, travel };
1613
- //# sourceMappingURL=chunk-7TTE4JM6.js.map
1614
- //# sourceMappingURL=chunk-7TTE4JM6.js.map
1737
+ export { ColorOverrideRegistry, TrimOverrideRegistry, absorb, axesFor, axesOf, axisIndexes, bump, bumpOn, comeOut, commitOffset, committedInto, createHoldStore, createTarget, createTargetBook, createTargetTable, createTimeline, goBehind, isTarget, minus, norm, plus, rowTableOf, runsOn, sampleTrack, seat, setBeside, shareBehind, stateOf, takeUp, times, travel };
1738
+ //# sourceMappingURL=chunk-TXKTFZIW.js.map
1739
+ //# sourceMappingURL=chunk-TXKTFZIW.js.map