upwwwards 0.1.9-beta.1 → 0.1.10-beta.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.
@@ -783,11 +783,48 @@ declare abstract class Scroll extends Lazy {
783
783
  static to(target: HTMLElement | number | string, options?: ScrollToOptions): void;
784
784
  }
785
785
 
786
+ declare namespace Split {
787
+ /**
788
+ * Options for {@link Split.add}: GSAP `SplitText.Vars`, plus an optional `reconstruct` flag.
789
+ * By default, each target keeps one cached {@link Split.SPLIT}: a later `add` that only needs a
790
+ * **subset** of already split types (and a compatible `mask`) returns that same object; if new types
791
+ * or a new `mask` are required, types are **merged** and the existing `SplitText` is re-split in place.
792
+ * Set `reconstruct: true` to **replace** the cached types / mask with this call’s values and re-split
793
+ * (no merge). `reconstruct` is upwwwards-only and is not passed to GSAP.
794
+ */
795
+ type VARS = SplitText.Vars & {
796
+ reconstruct?: boolean;
797
+ };
798
+ /**
799
+ * A split kind accepted in `vars.type` (`'chars'`, `'lines'`, or `'words'`).
800
+ */
801
+ type TYPE = 'chars' | 'lines' | 'words';
802
+ /**
803
+ * Result of {@link Split.add}: one stable object per `target` on this helper.
804
+ * `chars` / `lines` / `words` / `masks` are the same array references across calls; their contents are
805
+ * updated in place when the underlying `SplitText` is re-split. `types` / `mask` reflect the current
806
+ * split definition; `splitText` is the single GSAP instance for that target.
807
+ */
808
+ type SPLIT = {
809
+ types: TYPE[];
810
+ mask: TYPE | undefined;
811
+ chars: Element[];
812
+ lines: Element[];
813
+ words: Element[];
814
+ masks: Element[];
815
+ splitText: SplitText;
816
+ };
817
+ }
786
818
  /**
787
- * Collection of GSAP `SplitText` instances owned by a private GSAP context, reverted together by `destroy`
788
- * (which restores the original markup).
819
+ * Helper that owns one GSAP `SplitText` per target in a private GSAP context, reverted together by {@link Split.destroy}
820
+ * (restoring the original markup).
821
+ * On the **same target**, {@link Split.add} returns the same {@link Split.SPLIT}: subset requests reuse it as-is;
822
+ * wider requests (or a new `mask`) merge into the cached types and call `splitText.split(…)`. Pass
823
+ * `reconstruct: true` to replace the definition instead of merging. Element arrays on the `SPLIT` are kept by
824
+ * reference and refreshed in place after a re-split — prefer that object over holding individual node refs across
825
+ * a reconstruct / expand (tweens already targeting old nodes stay stale).
789
826
  * When constructed inside an `Up.Anime.sub` callback, the instance pushes its `destroy` on the workspace's cleaning stack
790
- * (the list of destructors run by `Up.Anime.unsub`), so it is cleaned up automatically.
827
+ * (run by `Up.Anime.unsub`), so it is cleaned up automatically.
791
828
  * @note Requires `'SplitText'` in the Anime config (`plugins: ['SplitText']`).
792
829
  * @note Get the class from the Anime bucket (`bucket.Split`): it is only usable once Anime has loaded GSAP.
793
830
  * @example
@@ -816,15 +853,28 @@ declare class Split {
816
853
  */
817
854
  constructor();
818
855
  /**
819
- * Splits `target` with `SplitText.create` inside the managed context, so `destroy` reverts it.
820
- * @param target Element(s) to split.
821
- * @param vars `SplitText` options.
822
- * @returns The created `SplitText` instance.
856
+ * Splits `target` according to `vars.type` (and optional `mask`). Work is recorded in the managed GSAP context
857
+ * so {@link Split.destroy} can revert it.
858
+ * **Same target, default:** if the cached split already covers the requested types and `mask`, returns that
859
+ * {@link Split.SPLIT} unchanged; otherwise merges the new types (and updates `mask` when provided), re-splits
860
+ * via `splitText.split(…)`, and refreshes `chars` / `lines` / `words` / `masks` in place.
861
+ * **`reconstruct: true`:** replaces the cached types / mask with this call’s values, re-splits, then refreshes
862
+ * the arrays (still the same `SPLIT` object / `splitText` instance). Unknown tokens in `type` are ignored.
863
+ * @param target Element(s) to split (Map key for the per-target cache).
864
+ * @param vars GSAP `SplitText` options; `type` is required. Optional `reconstruct` is upwwwards-only and is not passed to GSAP.
865
+ * @returns The cached {@link Split.SPLIT} for `target` (created on first `add`).
866
+ * @example
867
+ * ```ts
868
+ * const lines = split.add('.title', { type: 'lines' })
869
+ * const both = split.add('.title', { type: 'lines,words' }) // same object; union + re-split
870
+ * const words = split.add('.title', { type: 'words' }) // same object; subset → no re-split
871
+ * const only = split.add('.title', { type: 'words', reconstruct: true }) // same object; replace + re-split
872
+ * ```
823
873
  */
824
- add(target: gsap.DOMTarget, vars?: SplitText.Vars): SplitText;
874
+ add(target: gsap.DOMTarget, { reconstruct, ...vars }: Split.VARS): Split.SPLIT;
825
875
  /**
826
- * Reverts every `SplitText` instance created through this helper, then starts over with an empty context.
827
- * The instance stays usable afterwards.
876
+ * Clears the per-target cache, reverts every `SplitText` owned by this helper, and starts over with an empty context.
877
+ * The instance stays usable afterwards (new `add` calls behave like on a fresh `Split`).
828
878
  */
829
879
  destroy(): void;
830
880
  }
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import { W as Wait } from './Wait-C8AD49l9.js';
3
3
  import { T as Thread, a as App } from './Thread-5NGNyOJb.js';
4
4
  export { b as AppCache } from './Thread-5NGNyOJb.js';
5
5
  import { A as Adapter, a as AdapterConfig } from './index-BlwaDpQl.js';
6
- import { P as Plugin } from './index-Di5rQVjZ.js';
6
+ import { P as Plugin } from './index-ymMzfIlh.js';
7
7
  import 'lenis';
8
8
  import 'gsap/SplitText';
9
9
  import 'gsap/ScrollTrigger';
@@ -1,6 +1,6 @@
1
1
  import { Plugin as Plugin$1 } from 'vite';
2
2
  import { Up } from '../index.js';
3
- import { P as Plugin } from '../index-Di5rQVjZ.js';
3
+ import { P as Plugin } from '../index-ymMzfIlh.js';
4
4
  import { C as Classter } from '../Classter-BvYgmPAa.js';
5
5
  import '../symbols/index.js';
6
6
  import '../Wait-C8AD49l9.js';
@@ -4,12 +4,17 @@ import Logs from "../../scripts/Logs.js";
4
4
  class Split {
5
5
  // #PROPS
6
6
  // ##STATICS
7
+ static #RGX_TYPE = /\s*,\s*/;
8
+ static #TYPES = ["chars", "lines", "words"];
9
+ static #PROPS = [...Split.#TYPES, "masks"];
10
+ static #PROPS_LENGTH = Split.#PROPS.length;
7
11
  /**
8
12
  * Anime bucket shared by the Anime plugin once GSAP is loaded; includes `SplitText` when it is in the Anime config.
9
13
  * @internal
10
14
  */
11
15
  static [BUCKET];
12
16
  // ##PRIVATES
17
+ #CACHE = /* @__PURE__ */ new Map();
13
18
  #ctx = Split[BUCKET].gsap.context(Up.App.void);
14
19
  // ##PUBLICS
15
20
  // #MANAGERS
@@ -29,23 +34,75 @@ class Split {
29
34
  // ##GET
30
35
  // ##ADD
31
36
  /**
32
- * Splits `target` with `SplitText.create` inside the managed context, so `destroy` reverts it.
33
- * @param target Element(s) to split.
34
- * @param vars `SplitText` options.
35
- * @returns The created `SplitText` instance.
37
+ * Splits `target` according to `vars.type` (and optional `mask`). Work is recorded in the managed GSAP context
38
+ * so {@link Split.destroy} can revert it.
39
+ * **Same target, default:** if the cached split already covers the requested types and `mask`, returns that
40
+ * {@link Split.SPLIT} unchanged; otherwise merges the new types (and updates `mask` when provided), re-splits
41
+ * via `splitText.split(…)`, and refreshes `chars` / `lines` / `words` / `masks` in place.
42
+ * **`reconstruct: true`:** replaces the cached types / mask with this call’s values, re-splits, then refreshes
43
+ * the arrays (still the same `SPLIT` object / `splitText` instance). Unknown tokens in `type` are ignored.
44
+ * @param target Element(s) to split (Map key for the per-target cache).
45
+ * @param vars GSAP `SplitText` options; `type` is required. Optional `reconstruct` is upwwwards-only and is not passed to GSAP.
46
+ * @returns The cached {@link Split.SPLIT} for `target` (created on first `add`).
47
+ * @example
48
+ * ```ts
49
+ * const lines = split.add('.title', { type: 'lines' })
50
+ * const both = split.add('.title', { type: 'lines,words' }) // same object; union + re-split
51
+ * const words = split.add('.title', { type: 'words' }) // same object; subset → no re-split
52
+ * const only = split.add('.title', { type: 'words', reconstruct: true }) // same object; replace + re-split
53
+ * ```
36
54
  */
37
- add(target, vars) {
38
- return this.#ctx.add(() => Split[BUCKET].SplitText.create(target, vars));
55
+ add(target, { reconstruct, ...vars }) {
56
+ return this.#ctx.add(() => {
57
+ const TYPES = vars.type.trim().split(Split.#RGX_TYPE);
58
+ for (let i = TYPES.length - 1; i > -1; i--) if (!Split.#TYPES.includes(TYPES[i])) TYPES.splice(i, 1);
59
+ let split = this.#CACHE.get(target);
60
+ if (split) {
61
+ if (reconstruct) {
62
+ split.types = TYPES;
63
+ split.mask = vars.mask;
64
+ vars.type = TYPES.join(",");
65
+ } else {
66
+ if (Split.#isIncluded(split.types, TYPES) && (!vars.mask || split.mask === vars.mask)) return split;
67
+ for (let i = 0, max = TYPES.length; i < max; i++) if (!split.types.includes(TYPES[i])) split.types.push(TYPES[i]);
68
+ vars.type = split.types.join(",");
69
+ if (vars.mask) split.mask = vars.mask;
70
+ }
71
+ split.splitText.split(vars);
72
+ } else this.#CACHE.set(target, split = {
73
+ types: TYPES,
74
+ mask: vars.mask,
75
+ chars: [],
76
+ lines: [],
77
+ words: [],
78
+ masks: [],
79
+ splitText: Split[BUCKET].SplitText.create(target, vars)
80
+ });
81
+ for (let i = 0; i < Split.#PROPS_LENGTH; i++) {
82
+ const TARGET = split[Split.#PROPS[i]], SOURCE = split.splitText[Split.#PROPS[i]], LENGTH = SOURCE.length;
83
+ TARGET.length = LENGTH;
84
+ for (let j = 0; j < LENGTH; j++) TARGET[j] = SOURCE[j];
85
+ }
86
+ return split;
87
+ });
39
88
  }
40
89
  // ##DESTROY
41
90
  /**
42
- * Reverts every `SplitText` instance created through this helper, then starts over with an empty context.
43
- * The instance stays usable afterwards.
91
+ * Clears the per-target cache, reverts every `SplitText` owned by this helper, and starts over with an empty context.
92
+ * The instance stays usable afterwards (new `add` calls behave like on a fresh `Split`).
44
93
  */
45
94
  destroy() {
95
+ if (this.#CACHE.size) this.#CACHE.clear();
46
96
  this.#ctx.revert();
47
97
  this.#ctx = Split[BUCKET].gsap.context(Up.App.void);
48
98
  }
99
+ // ##IS
100
+ static #isIncluded(target, source) {
101
+ const LENGTH = source.length;
102
+ if (LENGTH > target.length) return false;
103
+ for (let i = 0; i < LENGTH; i++) if (!target.includes(source[i])) return false;
104
+ return true;
105
+ }
49
106
  }
50
107
  var Split_default = Split;
51
108
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/plugins/@anime/Split.ts"],"sourcesContent":["/* [Split] */\r\n\r\n// #IMPORTS\r\n\r\n // ##SYMBOLS\r\nimport { BUCKET } from '../../symbols/index.js'\r\n\r\n // ##CORE\r\nimport Up from '../../core/Up.js'\r\n\r\n // ##SCRIPTS\r\nimport Logs from '../../scripts/Logs.js'\r\n\r\n // ##TYPES\r\nimport type SplitText from 'gsap/SplitText'\r\n\r\nimport type { AnimeBucket } from '../Anime.js'\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Collection of GSAP `SplitText` instances owned by a private GSAP context, reverted together by `destroy`\r\n * (which restores the original markup).\r\n * When constructed inside an `Up.Anime.sub` callback, the instance pushes its `destroy` on the workspace's cleaning stack\r\n * (the list of destructors run by `Up.Anime.unsub`), so it is cleaned up automatically.\r\n * @note Requires `'SplitText'` in the Anime config (`plugins: ['SplitText']`).\r\n * @note Get the class from the Anime bucket (`bucket.Split`): it is only usable once Anime has loaded GSAP.\r\n * @example\r\n * ```ts\r\n * Up.Anime.sub(KEY, (bucket: AnimeBucket): void =>\r\n * {\r\n * const SPLIT = new bucket.Split()\r\n * const TEXT = SPLIT.add('.hero__title', { type: 'lines,words' })\r\n *\r\n * bucket.gsap.from(TEXT.words, { yPercent: 100, stagger: 0.05 })\r\n * })\r\n * ```\r\n*/\r\nclass Split\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n /**\r\n * Anime bucket shared by the Anime plugin once GSAP is loaded; includes `SplitText` when it is in the Anime config.\r\n * @internal\r\n */\r\n static [BUCKET]: AnimeBucket & { SplitText?: typeof SplitText }\r\n\r\n // ##PRIVATES\r\n #ctx: gsap.Context = Split[BUCKET].gsap.context(Up.App.void)\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##CONSTRUCTOR\r\n /**\r\n * Creates an empty collection and, inside a `sub` callback, registers `destroy` on the workspace's cleaning stack.\r\n * @throws If `'SplitText'` is not in the Anime config.\r\n */\r\n constructor ()\r\n {\r\n if (!Split[BUCKET].SplitText) Logs.throw('SPLIT', '\"SplitText\" (GSAP PLUGIN) IS REQUIRED TO USE THIS CLASS (ADD \"SplitText\" TO THE \"Anime\" CONFIGURATION).')\r\n\r\n Split[BUCKET].workspace.cleaningStack?.push(this.destroy.bind(this))\r\n }\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n\r\n // ##GET\r\n\r\n // ##ADD\r\n /**\r\n * Splits `target` with `SplitText.create` inside the managed context, so `destroy` reverts it.\r\n * @param target Element(s) to split.\r\n * @param vars `SplitText` options.\r\n * @returns The created `SplitText` instance.\r\n */\r\n add(target: gsap.DOMTarget, vars?: SplitText.Vars): SplitText { return this.#ctx.add((): SplitText => Split[BUCKET].SplitText!.create(target, vars)) }\r\n\r\n // ##DESTROY\r\n /**\r\n * Reverts every `SplitText` instance created through this helper, then starts over with an empty context.\r\n * The instance stays usable afterwards.\r\n */\r\n destroy(): void\r\n {\r\n this.#ctx.revert()\r\n\r\n this.#ctx = Split[BUCKET].gsap.context(Up.App.void)\r\n }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Split"],"mappings":"AAKA,SAAS,cAAc;AAGvB,OAAO,QAAQ;AAGf,OAAO,UAAU;AA4BjB,MAAM,MACN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASI,QAAQ,MAAM;AAAA;AAAA,EAGd,OAAqB,MAAM,MAAM,EAAE,KAAK,QAAQ,GAAG,IAAI,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW3D,cACA;AACI,QAAI,CAAC,MAAM,MAAM,EAAE,UAAW,MAAK,MAAM,SAAS,yGAAyG;AAE3J,UAAM,MAAM,EAAE,UAAU,eAAe,KAAK,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,IAAI,QAAwB,MAAkC;AAAE,WAAO,KAAK,KAAK,IAAI,MAAiB,MAAM,MAAM,EAAE,UAAW,OAAO,QAAQ,IAAI,CAAC;AAAA,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrJ,UACA;AACI,SAAK,KAAK,OAAO;AAEjB,SAAK,OAAO,MAAM,MAAM,EAAE,KAAK,QAAQ,GAAG,IAAI,IAAI;AAAA,EACtD;AAEJ;AAKA,IAAO,gBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../../src/plugins/@anime/Split.ts"],"sourcesContent":["/* [Split] */\r\n\r\n// #IMPORTS\r\n\r\n // ##SYMBOLS\r\nimport { BUCKET } from '../../symbols/index.js'\r\n\r\n // ##CORE\r\nimport Up from '../../core/Up.js'\r\n\r\n // ##SCRIPTS\r\nimport Logs from '../../scripts/Logs.js'\r\n\r\n // ##TYPES\r\nimport type SplitText from 'gsap/SplitText'\r\n\r\nimport type { AnimeBucket } from '../Anime.js'\r\n\r\n// #TYPES\r\n\r\n // ##THIS\r\nnamespace Split\r\n{\r\n /**\r\n * Options for {@link Split.add}: GSAP `SplitText.Vars`, plus an optional `reconstruct` flag.\r\n * By default, each target keeps one cached {@link Split.SPLIT}: a later `add` that only needs a\r\n * **subset** of already split types (and a compatible `mask`) returns that same object; if new types\r\n * or a new `mask` are required, types are **merged** and the existing `SplitText` is re-split in place.\r\n * Set `reconstruct: true` to **replace** the cached types / mask with this call’s values and re-split\r\n * (no merge). `reconstruct` is upwwwards-only and is not passed to GSAP.\r\n */\r\n export type VARS = SplitText.Vars & { reconstruct?: boolean }\r\n\r\n /**\r\n * A split kind accepted in `vars.type` (`'chars'`, `'lines'`, or `'words'`).\r\n */\r\n export type TYPE = 'chars' | 'lines' | 'words'\r\n\r\n /**\r\n * Result of {@link Split.add}: one stable object per `target` on this helper.\r\n * `chars` / `lines` / `words` / `masks` are the same array references across calls; their contents are\r\n * updated in place when the underlying `SplitText` is re-split. `types` / `mask` reflect the current\r\n * split definition; `splitText` is the single GSAP instance for that target.\r\n */\r\n export type SPLIT =\r\n {\r\n types : TYPE[],\r\n mask : TYPE | undefined,\r\n chars : Element[],\r\n lines : Element[],\r\n words : Element[],\r\n masks : Element[],\r\n splitText: SplitText\r\n }\r\n}\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Helper that owns one GSAP `SplitText` per target in a private GSAP context, reverted together by {@link Split.destroy}\r\n * (restoring the original markup).\r\n * On the **same target**, {@link Split.add} returns the same {@link Split.SPLIT}: subset requests reuse it as-is;\r\n * wider requests (or a new `mask`) merge into the cached types and call `splitText.split(…)`. Pass\r\n * `reconstruct: true` to replace the definition instead of merging. Element arrays on the `SPLIT` are kept by\r\n * reference and refreshed in place after a re-split — prefer that object over holding individual node refs across\r\n * a reconstruct / expand (tweens already targeting old nodes stay stale).\r\n * When constructed inside an `Up.Anime.sub` callback, the instance pushes its `destroy` on the workspace's cleaning stack\r\n * (run by `Up.Anime.unsub`), so it is cleaned up automatically.\r\n * @note Requires `'SplitText'` in the Anime config (`plugins: ['SplitText']`).\r\n * @note Get the class from the Anime bucket (`bucket.Split`): it is only usable once Anime has loaded GSAP.\r\n * @example\r\n * ```ts\r\n * Up.Anime.sub(KEY, (bucket: AnimeBucket): void =>\r\n * {\r\n * const SPLIT = new bucket.Split()\r\n * const TEXT = SPLIT.add('.hero__title', { type: 'lines,words' })\r\n *\r\n * bucket.gsap.from(TEXT.words, { yPercent: 100, stagger: 0.05 })\r\n * })\r\n * ```\r\n*/\r\nclass Split\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n static #RGX_TYPE = /\\s*,\\s*/\r\n\r\n static #TYPES: Split.TYPE[] = ['chars', 'lines', 'words']\r\n static #PROPS = [...Split.#TYPES, 'masks'] satisfies (keyof Split.SPLIT)[]\r\n\r\n static #PROPS_LENGTH = Split.#PROPS.length\r\n\r\n /**\r\n * Anime bucket shared by the Anime plugin once GSAP is loaded; includes `SplitText` when it is in the Anime config.\r\n * @internal\r\n */\r\n static [BUCKET]: AnimeBucket & { SplitText?: typeof SplitText }\r\n\r\n // ##PRIVATES\r\n #CACHE = new Map<gsap.DOMTarget, Split.SPLIT>()\r\n\r\n #ctx: gsap.Context = Split[BUCKET].gsap.context(Up.App.void)\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##CONSTRUCTOR\r\n /**\r\n * Creates an empty collection and, inside a `sub` callback, registers `destroy` on the workspace's cleaning stack.\r\n * @throws If `'SplitText'` is not in the Anime config.\r\n */\r\n constructor ()\r\n {\r\n if (!Split[BUCKET].SplitText) Logs.throw('SPLIT', '\"SplitText\" (GSAP PLUGIN) IS REQUIRED TO USE THIS CLASS (ADD \"SplitText\" TO THE \"Anime\" CONFIGURATION).')\r\n\r\n Split[BUCKET].workspace.cleaningStack?.push(this.destroy.bind(this))\r\n }\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n\r\n // ##GET\r\n\r\n // ##ADD\r\n /**\r\n * Splits `target` according to `vars.type` (and optional `mask`). Work is recorded in the managed GSAP context\r\n * so {@link Split.destroy} can revert it.\r\n * **Same target, default:** if the cached split already covers the requested types and `mask`, returns that\r\n * {@link Split.SPLIT} unchanged; otherwise merges the new types (and updates `mask` when provided), re-splits\r\n * via `splitText.split(…)`, and refreshes `chars` / `lines` / `words` / `masks` in place.\r\n * **`reconstruct: true`:** replaces the cached types / mask with this call’s values, re-splits, then refreshes\r\n * the arrays (still the same `SPLIT` object / `splitText` instance). Unknown tokens in `type` are ignored.\r\n * @param target Element(s) to split (Map key for the per-target cache).\r\n * @param vars GSAP `SplitText` options; `type` is required. Optional `reconstruct` is upwwwards-only and is not passed to GSAP.\r\n * @returns The cached {@link Split.SPLIT} for `target` (created on first `add`).\r\n * @example\r\n * ```ts\r\n * const lines = split.add('.title', { type: 'lines' })\r\n * const both = split.add('.title', { type: 'lines,words' }) // same object; union + re-split\r\n * const words = split.add('.title', { type: 'words' }) // same object; subset → no re-split\r\n * const only = split.add('.title', { type: 'words', reconstruct: true }) // same object; replace + re-split\r\n * ```\r\n */\r\n add(target: gsap.DOMTarget, {reconstruct, ...vars}: Split.VARS): Split.SPLIT\r\n {\r\n return this.#ctx.add((): Split.SPLIT =>\r\n {\r\n const TYPES = vars.type.trim().split(Split.#RGX_TYPE) as Split.TYPE[]\r\n\r\n for (let i = TYPES.length - 1; i > -1; i--) if (!Split.#TYPES.includes(TYPES[i])) TYPES.splice(i, 1)\r\n\r\n let split = this.#CACHE.get(target)\r\n\r\n if (split)\r\n {\r\n if (reconstruct)\r\n {\r\n split.types = TYPES\r\n split.mask = vars.mask\r\n vars.type = TYPES.join(',')\r\n }\r\n else\r\n {\r\n if (Split.#isIncluded(split.types, TYPES) && (!vars.mask || split.mask === vars.mask)) return split\r\n\r\n for (let i = 0, max = TYPES.length; i < max; i++) if (!split.types.includes(TYPES[i])) split.types.push(TYPES[i])\r\n\r\n vars.type = split.types.join(',')\r\n\r\n if (vars.mask) split.mask = vars.mask\r\n }\r\n\r\n split.splitText.split(vars)\r\n }\r\n else this.#CACHE.set(target, split =\r\n {\r\n types : TYPES,\r\n mask : vars.mask,\r\n chars : [],\r\n lines : [],\r\n words : [],\r\n masks : [],\r\n splitText: Split[BUCKET].SplitText!.create(target, vars)\r\n })\r\n \r\n for (let i = 0; i < Split.#PROPS_LENGTH; i++)\r\n {\r\n const\r\n TARGET = split[Split.#PROPS[i]],\r\n SOURCE = split.splitText[Split.#PROPS[i]],\r\n LENGTH = SOURCE.length\r\n\r\n TARGET.length = LENGTH\r\n\r\n for (let j = 0; j < LENGTH; j++) TARGET[j] = SOURCE[j]\r\n }\r\n\r\n return split\r\n })\r\n }\r\n\r\n // ##DESTROY\r\n /**\r\n * Clears the per-target cache, reverts every `SplitText` owned by this helper, and starts over with an empty context.\r\n * The instance stays usable afterwards (new `add` calls behave like on a fresh `Split`).\r\n */\r\n destroy(): void\r\n {\r\n if (this.#CACHE.size) this.#CACHE.clear()\r\n\r\n this.#ctx.revert()\r\n\r\n this.#ctx = Split[BUCKET].gsap.context(Up.App.void)\r\n }\r\n\r\n // ##IS\r\n static #isIncluded(target: Split.TYPE[], source: Split.TYPE[]): boolean\r\n {\r\n const LENGTH = source.length\r\n\r\n if (LENGTH > target.length) return false\r\n \r\n for (let i = 0; i < LENGTH; i++) if (!target.includes(source[i])) return false\r\n\r\n return true\r\n }\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Split\r\n\r\nexport type { Split }"],"mappings":"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","names":[]}
@@ -1,5 +1,5 @@
1
1
  import '../symbols/index.js';
2
- export { A as Anime, c as AnimeBucket, d as Split, e as Timeline, f as Tweens, A as default } from '../index-Di5rQVjZ.js';
2
+ export { A as Anime, c as AnimeBucket, d as Split, e as Timeline, f as Tweens, A as default } from '../index-ymMzfIlh.js';
3
3
  import 'gsap/all';
4
4
  import '../index-BlwaDpQl.js';
5
5
  import '../Thread-5NGNyOJb.js';
@@ -1,4 +1,4 @@
1
- export { M as Matrix4, g as Puppeteer, g as default } from '../index-Di5rQVjZ.js';
1
+ export { M as Matrix4, g as Puppeteer, g as default } from '../index-ymMzfIlh.js';
2
2
  import '../index-BlwaDpQl.js';
3
3
  import '../symbols/index.js';
4
4
  import '../Thread-5NGNyOJb.js';
@@ -1,5 +1,5 @@
1
1
  import '../symbols/index.js';
2
- export { S as Scroll, b as ScrollBucket, S as default } from '../index-Di5rQVjZ.js';
2
+ export { S as Scroll, b as ScrollBucket, S as default } from '../index-ymMzfIlh.js';
3
3
  import 'lenis';
4
4
  import '../Thread-5NGNyOJb.js';
5
5
  import '../index-BlwaDpQl.js';
@@ -1,5 +1,5 @@
1
1
  import '../symbols/index.js';
2
- export { B as Basic, h as Package, i as Plugin, j as Spider, k as Synthra, l as SynthraBucket, m as SynthraPlugins, n as SynthraThree, X as X3D, k as default } from '../index-Di5rQVjZ.js';
2
+ export { B as Basic, h as Package, i as Plugin, j as Spider, k as Synthra, l as SynthraBucket, m as SynthraPlugins, n as SynthraThree, X as X3D, k as default } from '../index-ymMzfIlh.js';
3
3
  import 'three';
4
4
  import '../Thread-5NGNyOJb.js';
5
5
  import '../index-BlwaDpQl.js';
@@ -1,5 +1,5 @@
1
1
  import '../symbols/index.js';
2
- export { T as Transmitter, a as TransmitterChannels, T as default } from '../index-Di5rQVjZ.js';
2
+ export { T as Transmitter, a as TransmitterChannels, T as default } from '../index-ymMzfIlh.js';
3
3
  import '../index-BlwaDpQl.js';
4
4
  import '../Thread-5NGNyOJb.js';
5
5
  import 'lenis';
@@ -1,4 +1,4 @@
1
- export { A as Anime, L as Lazy, O as Observer, P as Plugin, g as Puppeteer, o as Screen, S as Scroll, k as Synthra, T as Transmitter } from '../index-Di5rQVjZ.js';
1
+ export { A as Anime, L as Lazy, O as Observer, P as Plugin, g as Puppeteer, o as Screen, S as Scroll, k as Synthra, T as Transmitter } from '../index-ymMzfIlh.js';
2
2
  import '../symbols/index.js';
3
3
  import '../index-BlwaDpQl.js';
4
4
  import '../Thread-5NGNyOJb.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/scripts/Arrays.ts"],"sourcesContent":["/* [Arrays] */\r\n\r\n// #IMPORTS\r\n\r\n // ##THIS\r\nimport CallStack from './@arrays/Callstack.js'\r\n\r\n // ##TYPES\r\nimport type Maths from './Maths.js'\r\nimport type Strings from './Strings.js'\r\n\r\n// #TYPES\r\n\r\n // ##THIS\r\nnamespace Arrays\r\n{\r\n /**\r\n * Tuple with the same length as `T` where every element is `U` (e.g. `Fill<[1, 2, 3], 0>` is `[0, 0, 0]`).\r\n * @template T Source tuple (only its length is used).\r\n * @template U Element type to fill with.\r\n */\r\n export type Fill<T extends any[], U, V extends any[] = []> = T extends [any, ...infer W] ? Fill<W, U, [...V, U]> : V\r\n\r\n /**\r\n * String literal type obtained by joining the elements of `T` with separator `U`\r\n * (e.g. `Join<[1, 'a', true], ', '>` is `'1, a, true'`), like `Array.prototype.join` at the type level.\r\n * Elements must be stringifiable (`Strings.STRINGIFIABLE`).\r\n * @template T Tuple to join.\r\n * @template U Separator. Defaults to `','`.\r\n */\r\n export type Join<T extends any[], U extends string = ',', V extends string = ''> = T extends [infer W extends Strings.STRINGIFIABLE, ...infer X extends Strings.STRINGIFIABLE[]]\r\n ? Join<X, U, V extends '' ? `${W}` : `${V}${U}${W}`>\r\n : V\r\n\r\n /**\r\n * `true` if at least one element type of `T` is assignable to `U`, otherwise `false`\r\n * (e.g. `Includes<['a', 1], string>` is `true`, `Includes<[string], 'a'>` is `false`).\r\n * @template T Tuple or array to search (readonly accepted).\r\n * @template U Type to look for.\r\n */\r\n export type Includes<T extends Readonly<any[]>, U> = Extract<T[number], U> extends never ? false : true\r\n\r\n /**\r\n * Tuple `T` with `U` appended at the end.\r\n * @template T Source tuple.\r\n * @template U Element to append.\r\n */\r\n export type Push<T extends any[], U> = [...T, U]\r\n\r\n /**\r\n * Tuple `T` without its last element (`never` if `T` is empty).\r\n * @template T Source tuple.\r\n */\r\n export type Pop<T extends any[]> = T extends [...infer U, any] ? U : never\r\n\r\n /**\r\n * Tuple `T` with `U` inserted at the start.\r\n * @template T Source tuple.\r\n * @template U Element to prepend.\r\n */\r\n export type Unshift<T extends any[], U> = [U, ...T]\r\n\r\n /**\r\n * Tuple `T` without its first element (`never` if `T` is empty).\r\n * @template T Source tuple.\r\n */\r\n export type Shift<T extends any[]> = T extends [any, ...infer U] ? U : never\r\n\r\n /**\r\n * Tuple `T` padded with `U` until it has length `V` (e.g. `Pad<[1], 0, 3, true>` is `[1, 0, 0]`).\r\n * Tuples already at least `V` long are returned unchanged.\r\n * @template T Source tuple.\r\n * @template U Padding element.\r\n * @template V Target length.\r\n * @template W `true` to pad at the end; otherwise (default `false`) pad at the start.\r\n */\r\n export type Pad<T extends any[], U, V extends number, W extends boolean = false, X extends any[] = T, Y extends null[] = []> = V extends Y['length']\r\n ? X\r\n : T extends [unknown, ...infer Z]\r\n ? Pad<Z, U, V, W, X, [...Y, null]>\r\n : Pad<[], U, V, W, W extends true ? [...X, U] : [U, ...X], [...Y, null]>\r\n\r\n /**\r\n * Length of tuple `T` as a number literal type.\r\n * @template T Source tuple.\r\n */\r\n export type Length<T extends any[]> = T['length']\r\n\r\n /**\r\n * Tuple `T` with the element at index `U` replaced by `V` (e.g. `Set<[1, 2], 1, 'x'>` is `[1, 'x']`).\r\n * If `U` is past the end, the gap is filled with `undefined` (e.g. `Set<[1], 3, 'x'>` is `[1, undefined, undefined, 'x']`).\r\n * @template T Source tuple.\r\n * @template U Index to set.\r\n * @template V New element.\r\n */\r\n export type Set<T extends any[], U extends number, V, W extends any[] = []> = T extends [infer X, ...infer Y]\r\n ? U extends W['length']\r\n ? Set<Y, U, V, [...W, V]>\r\n : Set<Y, U, V, [...W, X]>\r\n : U extends W['length']\r\n ? [...W, V]\r\n : Maths.SmallerOrEqual<W['length'], U> extends true\r\n ? Set<T, U, V, [...W, undefined]>\r\n : W\r\n}\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Array utilities: compile-time tuple helper types (`Arrays.Fill`, `Arrays.Join`, `Arrays.Pad`, ...)\r\n * and the runtime {@link CallStack} class, exposed as `Arrays.CallStack`.\r\n * @example\r\n * ```ts\r\n * import { Arrays } from 'upwwwards/scripts'\r\n *\r\n * type T = Arrays.Push<[1, 2], 3> // [1, 2, 3]\r\n *\r\n * const STACK = new Arrays.CallStack<(dt: number) => void>()\r\n *\r\n * STACK.add((dt): void => console.log(dt))\r\n * STACK.loop(16)\r\n * ```\r\n*/\r\nabstract class Arrays\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n\r\n // ##PRIVATES\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n /**\r\n * The {@link CallStack} class: an ordered list of callbacks that can be run all at once (`loop`)\r\n * or one at a time through a generator (`gen`).\r\n * @returns The `CallStack` constructor.\r\n */\r\n static get CallStack(): typeof CallStack { return CallStack }\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n\r\n // ##GET\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Arrays\r\n\r\nexport type { Arrays, CallStack }"],"mappings":"AAKA,OAAO,eAAe;AAuHtB,MAAe,OACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBI,WAAW,YAA8B;AAAE,WAAO;AAAA,EAAU;AAAA;AAAA;AAAA;AAQhE;AAKA,IAAO,iBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../src/scripts/Arrays.ts"],"sourcesContent":["/* [Arrays] */\r\n\r\n// #IMPORTS\r\n\r\n // ##THIS\r\nimport CallStack from './@arrays/Callstack.js'\r\n\r\n // ##TYPES\r\nimport type Maths from './Maths.js'\r\nimport type Strings from './Strings.js'\r\n\r\n// #TYPES\r\n\r\n // ##THIS\r\nnamespace Arrays\r\n{\r\n /**\r\n * Tuple with the same length as `T` where every element is `U` (e.g. `Fill<[1, 2, 3], 0>` is `[0, 0, 0]`).\r\n * @template T Source tuple (only its length is used).\r\n * @template U Element type to fill with.\r\n */\r\n export type Fill<T extends any[], U, V extends any[] = []> = T extends [any, ...infer W] ? Fill<W, U, [...V, U]> : V\r\n\r\n /**\r\n * String literal type obtained by joining the elements of `T` with separator `U`\r\n * (e.g. `Join<[1, 'a', true], ', '>` is `'1, a, true'`), like `Array.prototype.join` at the type level.\r\n * Elements must be stringifiable (`Strings.STRINGIFIABLE`).\r\n * @template T Tuple to join.\r\n * @template U Separator. Defaults to `','`.\r\n */\r\n export type Join<T extends any[], U extends string = ',', V extends string = ''> = T extends [infer W extends Strings.STRINGIFIABLE, ...infer X extends Strings.STRINGIFIABLE[]]\r\n ? Join<X, U, V extends '' ? `${W}` : `${V}${U}${W}`>\r\n : V\r\n\r\n /**\r\n * `true` if at least one element type of `T` is assignable to `U`, otherwise `false`\r\n * (e.g. `Includes<['a', 1], string>` is `true`, `Includes<[string], 'a'>` is `false`).\r\n * @template T Tuple or array to search (readonly accepted).\r\n * @template U Type to look for.\r\n */\r\n export type Includes<T extends Readonly<any[]>, U> = Extract<T[number], U> extends never ? false : true\r\n\r\n /**\r\n * Tuple `T` with `U` appended at the end.\r\n * @template T Source tuple.\r\n * @template U Element to append.\r\n */\r\n export type Push<T extends any[], U> = [...T, U]\r\n\r\n /**\r\n * Tuple `T` without its last element (`never` if `T` is empty).\r\n * @template T Source tuple.\r\n */\r\n export type Pop<T extends any[]> = T extends [...infer U, any] ? U : never\r\n\r\n /**\r\n * Tuple `T` with `U` inserted at the start.\r\n * @template T Source tuple.\r\n * @template U Element to prepend.\r\n */\r\n export type Unshift<T extends any[], U> = [U, ...T]\r\n\r\n /**\r\n * Tuple `T` without its first element (`never` if `T` is empty).\r\n * @template T Source tuple.\r\n */\r\n export type Shift<T extends any[]> = T extends [any, ...infer U] ? U : never\r\n\r\n /**\r\n * Tuple `T` padded with `U` until it has length `V` (e.g. `Pad<[1], 0, 3, true>` is `[1, 0, 0]`).\r\n * Tuples already at least `V` long are returned unchanged.\r\n * @template T Source tuple.\r\n * @template U Padding element.\r\n * @template V Target length.\r\n * @template W `true` to pad at the end; otherwise (default `false`) pad at the start.\r\n */\r\n export type Pad<T extends any[], U, V extends number, W extends boolean = false, X extends any[] = T, Y extends null[] = []> = V extends Y['length']\r\n ? X\r\n : T extends [unknown, ...infer Z]\r\n ? Pad<Z, U, V, W, X, [...Y, null]>\r\n : Pad<[], U, V, W, W extends true ? [...X, U] : [U, ...X], [...Y, null]>\r\n\r\n /**\r\n * Length of tuple `T` as a number literal type.\r\n * @template T Source tuple.\r\n */\r\n export type Length<T extends any[]> = T['length']\r\n\r\n /**\r\n * Tuple `T` with the element at index `U` replaced by `V` (e.g. `Set<[1, 2], 1, 'x'>` is `[1, 'x']`).\r\n * If `U` is past the end, the gap is filled with `undefined` (e.g. `Set<[1], 3, 'x'>` is `[1, undefined, undefined, 'x']`).\r\n * @template T Source tuple.\r\n * @template U Index to set.\r\n * @template V New element.\r\n */\r\n export type Set<T extends any[], U extends number, V, W extends any[] = []> = T extends [infer X, ...infer Y]\r\n ? U extends W['length']\r\n ? Set<Y, U, V, [...W, V]>\r\n : Set<Y, U, V, [...W, X]>\r\n : U extends W['length']\r\n ? [...W, V]\r\n : Maths.SmallerOrEqual<W['length'], U> extends true\r\n ? Set<T, U, V, [...W, undefined]>\r\n : W\r\n}\r\n\r\n// #CLASS\r\n\r\n // ##THIS\r\n/**\r\n * Array utilities: compile-time tuple helper types (`Arrays.Fill`, `Arrays.Join`, `Arrays.Pad`, ...)\r\n * and the runtime {@link CallStack} class, exposed as `Arrays.CallStack`.\r\n * @example\r\n * ```ts\r\n * import { Arrays } from 'upwwwards/scripts'\r\n *\r\n * type T = Arrays.Push<[1, 2], 3> // [1, 2, 3]\r\n *\r\n * const STACK = new Arrays.CallStack<(dt: number) => void>()\r\n *\r\n * STACK.add((dt): void => console.log(dt))\r\n * STACK.loop(16)\r\n * ```\r\n*/\r\nabstract class Arrays\r\n{\r\n\r\n// #PROPS\r\n\r\n // ##STATICS\r\n\r\n // ##PRIVATES\r\n\r\n // ##PUBLICS\r\n\r\n// #MANAGERS\r\n\r\n // ##SETTER\r\n\r\n // ##GETTER\r\n /**\r\n * The {@link CallStack} class: an ordered list of callbacks that can be run all at once (`loop`)\r\n * or one at a time through a generator (`gen`).\r\n * @returns The `CallStack` constructor.\r\n */\r\n static get CallStack(): typeof CallStack { return CallStack }\r\n\r\n// #METHODS\r\n\r\n // ##SET\r\n\r\n // ##GET\r\n\r\n}\r\n\r\n// #EXPORTS\r\n\r\n // ##THIS\r\nexport default Arrays\r\n\r\nexport type { Arrays, CallStack }\r\n\r\n"],"mappings":"AAKA,OAAO,eAAe;AAuHtB,MAAe,OACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBI,WAAW,YAA8B;AAAE,WAAO;AAAA,EAAU;AAAA;AAAA;AAAA;AAQhE;AAKA,IAAO,iBAAQ;","names":[]}
@@ -116,13 +116,32 @@ Up.Anime.sub(KEY, ({ Tweens }) => {
116
116
 
117
117
  ### Helper: `Split`
118
118
 
119
- Requires `'SplitText'` in Anime `plugins`. Collection of `SplitText` instances; `destroy` restores markup. Auto-cleaned inside `sub`.
119
+ Requires `'SplitText'` in Anime `plugins`. Owns **one** `SplitText` per target in a private GSAP context; `destroy` restores markup. Auto-cleaned inside `sub`.
120
+
121
+ `add(target, vars)` always returns a **`Split.SPLIT`** (`types`, `mask`, `chars` / `lines` / `words` / `masks`, `splitText`) — not a raw `SplitText`. On the **same target**, it is the **same object**: element arrays keep their references and are refreshed in place after a re-split.
122
+
123
+ | Call | Behavior |
124
+ | --- | --- |
125
+ | Subset of cached types (+ compatible `mask`) | Return cache, no re-split |
126
+ | New types and/or new `mask` | **Merge** types, `splitText.split(…)`, refresh arrays |
127
+ | `reconstruct: true` | **Replace** cached types / mask, re-split, refresh arrays |
128
+
129
+ `reconstruct` is upwwwards-only (not forwarded to GSAP). Tweens already targeting old DOM nodes stay stale after an expand / reconstruct — re-read `text.lines` / `text.words` (or rebuild tweens) if needed.
120
130
 
121
131
  ```ts
122
132
  Up.Anime.sub(KEY, ({ gsap, Split }) => {
123
133
  const split = new Split()
124
134
  const text = split.add('.hero__title', { type: 'lines,words' })
125
135
  gsap.from(text.words, { yPercent: 100, stagger: 0.05 })
136
+
137
+ // same object: union types + re-split in place
138
+ split.add('.hero__title', { type: 'lines,words,chars' })
139
+
140
+ // same object: subset → reuse, no re-split
141
+ split.add('.hero__title', { type: 'words' })
142
+
143
+ // same object: replace definition + re-split
144
+ split.add('.hero__title', { type: 'words', reconstruct: true })
126
145
  })
127
146
  ```
128
147
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "upwwwards",
3
- "version": "0.1.9-beta.1",
3
+ "version": "0.1.10-beta.1",
4
4
  "license": "SEE LICENSE IN LICENSE",
5
5
  "description": "Shared page lifecycle, frame loop, and opt-in plugins (GSAP, Lenis, Three.js) for Nuxt 4 and SvelteKit 2.",
6
6
  "author": "Morgan LE THUAUT <morgan@upwwwards.com>",