@searchspring/snap-toolbox 0.77.0 → 0.78.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.
@@ -9,6 +9,7 @@ export type Target = {
9
9
  autoRetarget?: boolean;
10
10
  unsetTargetMinHeight?: boolean;
11
11
  clickRetarget?: boolean | string;
12
+ navigationRetarget?: boolean;
12
13
  [any: string]: unknown;
13
14
  };
14
15
  export type OnTarget = (target: Target, elem: Element, originalElem?: Element, targeter?: DomTargeter) => void | Promise<void>;
@@ -18,9 +19,12 @@ export declare class DomTargeter {
18
19
  private document;
19
20
  private styleBlockRefs;
20
21
  private targetedElems;
22
+ private abortController?;
21
23
  constructor(targets: Array<Target>, onTarget: OnTarget, document?: Document);
22
24
  getTargets(): Array<Target>;
23
25
  getTargetedElems(): ReadonlyArray<Element>;
26
+ releaseTargets(elems?: ReadonlyArray<Element>): void;
27
+ destroy(): void;
24
28
  retarget(): void;
25
29
  unhideTarget: (selector: string) => void;
26
30
  hideTarget: (selector: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"DomTargeter.d.ts","sourceRoot":"","sources":["../../../src/DomTargeter/DomTargeter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE;QACR,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;QAC9D,OAAO,EAAE,OAAO,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC;KACnE,CAAC;IACF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAG/H,qBAAa,WAAW;IACvB,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,aAAa,CAAsB;gBAE/B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,QAAQ;IA0D3E,UAAU,IAAI,KAAK,CAAC,MAAM,CAAC;IAI3B,gBAAgB,IAAI,aAAa,CAAC,OAAO,CAAC;IAK1C,QAAQ,IAAI,IAAI;IAuEhB,YAAY,aAAc,MAAM,KAAG,IAAI,CASrC;IAEF,UAAU,aAAc,MAAM,KAAG,IAAI,CASnC;IAEF,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,MAAM;CA2Cd"}
1
+ {"version":3,"file":"DomTargeter.d.ts","sourceRoot":"","sources":["../../../src/DomTargeter/DomTargeter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE;QACR,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;QAC9D,OAAO,EAAE,OAAO,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC;KACnE,CAAC;IACF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACjC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAI/H,qBAAa,WAAW;IACvB,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,eAAe,CAAC,CAAkB;gBAE9B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,QAAQ;IA6F3E,UAAU,IAAI,KAAK,CAAC,MAAM,CAAC;IAI3B,gBAAgB,IAAI,aAAa,CAAC,OAAO,CAAC;IAK1C,cAAc,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI;IAepD,OAAO,IAAI,IAAI;IAMf,QAAQ,IAAI,IAAI;IAuEhB,YAAY,aAAc,MAAM,KAAG,IAAI,CASrC;IAEF,UAAU,aAAc,MAAM,KAAG,IAAI,CASnC;IAEF,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,MAAM;CA2Cd"}
@@ -39,12 +39,25 @@ var DomTargeter = /** @class */ (function () {
39
39
  _this.styleBlockRefs[selector] = styleBlock;
40
40
  };
41
41
  this.document = document || window.document;
42
+ // use the document's own window AbortController to ensure realm compatibility (e.g., JSDOM)
43
+ // and gracefully handle environments where AbortController is not available (e.g., IE11)
44
+ try {
45
+ this.abortController = new (this.document.defaultView || window).AbortController();
46
+ }
47
+ catch (e) {
48
+ // AbortController not available - listeners won't auto-cleanup on destroy()
49
+ }
42
50
  this.targets = targets;
43
51
  this.onTarget = onTarget;
44
52
  this.retarget();
45
53
  this.targets.forEach(function (target) {
54
+ var _a, _b, _c, _d;
46
55
  var timeoutTime = 100;
47
56
  var checker = function () {
57
+ var _a;
58
+ if ((_a = _this.abortController) === null || _a === void 0 ? void 0 : _a.signal.aborted) {
59
+ return;
60
+ }
48
61
  // lets not just keep trying forever - this waits roughly 12 seconds before giving up.
49
62
  if (timeoutTime < 2000) {
50
63
  // increase the time till next check
@@ -67,12 +80,25 @@ var DomTargeter = /** @class */ (function () {
67
80
  clickElems = Array.from(_this.document.querySelectorAll(target.clickRetarget));
68
81
  }
69
82
  clickElems.map(function (elem) {
83
+ var _a;
70
84
  elem.addEventListener('click', function () {
71
85
  timeoutTime = 100;
72
- checker();
73
- });
86
+ setTimeout(checker); // allow the click to complete
87
+ }, { capture: true, signal: (_a = _this.abortController) === null || _a === void 0 ? void 0 : _a.signal });
74
88
  });
75
89
  }
90
+ // listen for SPA navigations via the Navigation API to restart retargeting
91
+ if (target.navigationRetarget) {
92
+ try {
93
+ (_b = (_a = _this.document.defaultView) === null || _a === void 0 ? void 0 : _a.navigation) === null || _b === void 0 ? void 0 : _b.addEventListener('navigate', function () {
94
+ timeoutTime = 100;
95
+ checker();
96
+ }, { signal: (_c = _this.abortController) === null || _c === void 0 ? void 0 : _c.signal });
97
+ }
98
+ catch (e) {
99
+ // Navigation API not available
100
+ }
101
+ }
76
102
  if (target.autoRetarget) {
77
103
  // do initial retargeting check
78
104
  checker();
@@ -86,7 +112,7 @@ var DomTargeter = /** @class */ (function () {
86
112
  _this.document.addEventListener('DOMContentLoaded', function () {
87
113
  _this.retarget();
88
114
  target.hideTarget && _this.unhideTarget(target.selector);
89
- });
115
+ }, { signal: (_d = _this.abortController) === null || _d === void 0 ? void 0 : _d.signal });
90
116
  }
91
117
  });
92
118
  }
@@ -97,6 +123,28 @@ var DomTargeter = /** @class */ (function () {
97
123
  this.targetedElems = this.targetedElems.filter(function (elem) { return elem.isConnected; });
98
124
  return __spreadArray([], this.targetedElems, true);
99
125
  };
126
+ DomTargeter.prototype.releaseTargets = function (elems) {
127
+ var toRelease = elems || this.targetedElems;
128
+ toRelease.forEach(function (elem) {
129
+ var idx = globallyTargetedElems.indexOf(elem);
130
+ if (idx !== -1) {
131
+ globallyTargetedElems.splice(idx, 1);
132
+ }
133
+ });
134
+ if (elems) {
135
+ this.targetedElems = this.targetedElems.filter(function (elem) { return !elems.includes(elem); });
136
+ }
137
+ else {
138
+ this.targetedElems = [];
139
+ }
140
+ };
141
+ DomTargeter.prototype.destroy = function () {
142
+ var _this = this;
143
+ var _a;
144
+ (_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort();
145
+ this.releaseTargets();
146
+ Object.keys(this.styleBlockRefs).forEach(function (selector) { return _this.unhideTarget(selector); });
147
+ };
100
148
  DomTargeter.prototype.retarget = function () {
101
149
  var _this = this;
102
150
  var _a, _b;
@@ -124,9 +172,10 @@ var DomTargeter = /** @class */ (function () {
124
172
  for (var _i = 0, targetElemPairs_1 = targetElemPairs; _i < targetElemPairs_1.length; _i++) {
125
173
  var _c = targetElemPairs_1[_i], target = _c.target, elem = _c.elem;
126
174
  try {
175
+ // track targeted elements
176
+ this.targetedElems = this.targetedElems.concat(elem);
127
177
  if (target.inject) {
128
178
  var injectedElem = this.inject(elem, target);
129
- this.targetedElems = this.targetedElems.concat(elem);
130
179
  // handle both sync and async onTarget functions
131
180
  var result = this.onTarget(target, injectedElem, elem, this);
132
181
  if (result && typeof result.then === 'function') {
@@ -137,7 +186,6 @@ var DomTargeter = /** @class */ (function () {
137
186
  }
138
187
  }
139
188
  else {
140
- this.targetedElems = this.targetedElems.concat(elem);
141
189
  // empty target selector by default
142
190
  target.emptyTarget = (_a = target.emptyTarget) !== null && _a !== void 0 ? _a : true;
143
191
  if (target.emptyTarget)
@@ -9,6 +9,7 @@ export type Target = {
9
9
  autoRetarget?: boolean;
10
10
  unsetTargetMinHeight?: boolean;
11
11
  clickRetarget?: boolean | string;
12
+ navigationRetarget?: boolean;
12
13
  [any: string]: unknown;
13
14
  };
14
15
  export type OnTarget = (target: Target, elem: Element, originalElem?: Element, targeter?: DomTargeter) => void | Promise<void>;
@@ -18,9 +19,12 @@ export declare class DomTargeter {
18
19
  private document;
19
20
  private styleBlockRefs;
20
21
  private targetedElems;
22
+ private abortController?;
21
23
  constructor(targets: Array<Target>, onTarget: OnTarget, document?: Document);
22
24
  getTargets(): Array<Target>;
23
25
  getTargetedElems(): ReadonlyArray<Element>;
26
+ releaseTargets(elems?: ReadonlyArray<Element>): void;
27
+ destroy(): void;
24
28
  retarget(): void;
25
29
  unhideTarget: (selector: string) => void;
26
30
  hideTarget: (selector: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"DomTargeter.d.ts","sourceRoot":"","sources":["../../../src/DomTargeter/DomTargeter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE;QACR,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;QAC9D,OAAO,EAAE,OAAO,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC;KACnE,CAAC;IACF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAG/H,qBAAa,WAAW;IACvB,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,aAAa,CAAsB;gBAE/B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,QAAQ;IA0D3E,UAAU,IAAI,KAAK,CAAC,MAAM,CAAC;IAI3B,gBAAgB,IAAI,aAAa,CAAC,OAAO,CAAC;IAK1C,QAAQ,IAAI,IAAI;IAuEhB,YAAY,aAAc,MAAM,KAAG,IAAI,CASrC;IAEF,UAAU,aAAc,MAAM,KAAG,IAAI,CASnC;IAEF,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,MAAM;CA2Cd"}
1
+ {"version":3,"file":"DomTargeter.d.ts","sourceRoot":"","sources":["../../../src/DomTargeter/DomTargeter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE;QACR,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;QAC9D,OAAO,EAAE,OAAO,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC;KACnE,CAAC;IACF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACjC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAI/H,qBAAa,WAAW;IACvB,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,eAAe,CAAC,CAAkB;gBAE9B,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,QAAQ;IA6F3E,UAAU,IAAI,KAAK,CAAC,MAAM,CAAC;IAI3B,gBAAgB,IAAI,aAAa,CAAC,OAAO,CAAC;IAK1C,cAAc,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI;IAepD,OAAO,IAAI,IAAI;IAMf,QAAQ,IAAI,IAAI;IAuEhB,YAAY,aAAc,MAAM,KAAG,IAAI,CASrC;IAEF,UAAU,aAAc,MAAM,KAAG,IAAI,CASnC;IAEF,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,MAAM;CA2Cd"}
@@ -26,12 +26,23 @@ export class DomTargeter {
26
26
  this.styleBlockRefs[selector] = styleBlock;
27
27
  };
28
28
  this.document = document || window.document;
29
+ // use the document's own window AbortController to ensure realm compatibility (e.g., JSDOM)
30
+ // and gracefully handle environments where AbortController is not available (e.g., IE11)
31
+ try {
32
+ this.abortController = new (this.document.defaultView || window).AbortController();
33
+ }
34
+ catch (e) {
35
+ // AbortController not available - listeners won't auto-cleanup on destroy()
36
+ }
29
37
  this.targets = targets;
30
38
  this.onTarget = onTarget;
31
39
  this.retarget();
32
40
  this.targets.forEach((target) => {
33
41
  let timeoutTime = 100;
34
42
  const checker = () => {
43
+ if (this.abortController?.signal.aborted) {
44
+ return;
45
+ }
35
46
  // lets not just keep trying forever - this waits roughly 12 seconds before giving up.
36
47
  if (timeoutTime < 2000) {
37
48
  // increase the time till next check
@@ -56,10 +67,22 @@ export class DomTargeter {
56
67
  clickElems.map((elem) => {
57
68
  elem.addEventListener('click', () => {
58
69
  timeoutTime = 100;
59
- checker();
60
- });
70
+ setTimeout(checker); // allow the click to complete
71
+ }, { capture: true, signal: this.abortController?.signal });
61
72
  });
62
73
  }
74
+ // listen for SPA navigations via the Navigation API to restart retargeting
75
+ if (target.navigationRetarget) {
76
+ try {
77
+ this.document.defaultView?.navigation?.addEventListener('navigate', () => {
78
+ timeoutTime = 100;
79
+ checker();
80
+ }, { signal: this.abortController?.signal });
81
+ }
82
+ catch (e) {
83
+ // Navigation API not available
84
+ }
85
+ }
63
86
  if (target.autoRetarget) {
64
87
  // do initial retargeting check
65
88
  checker();
@@ -73,7 +96,7 @@ export class DomTargeter {
73
96
  this.document.addEventListener('DOMContentLoaded', () => {
74
97
  this.retarget();
75
98
  target.hideTarget && this.unhideTarget(target.selector);
76
- });
99
+ }, { signal: this.abortController?.signal });
77
100
  }
78
101
  });
79
102
  }
@@ -84,6 +107,26 @@ export class DomTargeter {
84
107
  this.targetedElems = this.targetedElems.filter((elem) => elem.isConnected);
85
108
  return [...this.targetedElems];
86
109
  }
110
+ releaseTargets(elems) {
111
+ const toRelease = elems || this.targetedElems;
112
+ toRelease.forEach((elem) => {
113
+ const idx = globallyTargetedElems.indexOf(elem);
114
+ if (idx !== -1) {
115
+ globallyTargetedElems.splice(idx, 1);
116
+ }
117
+ });
118
+ if (elems) {
119
+ this.targetedElems = this.targetedElems.filter((elem) => !elems.includes(elem));
120
+ }
121
+ else {
122
+ this.targetedElems = [];
123
+ }
124
+ }
125
+ destroy() {
126
+ this.abortController?.abort();
127
+ this.releaseTargets();
128
+ Object.keys(this.styleBlockRefs).forEach((selector) => this.unhideTarget(selector));
129
+ }
87
130
  retarget() {
88
131
  // prune references to elements no longer in the DOM
89
132
  globallyTargetedElems = globallyTargetedElems.filter((elem) => elem.isConnected);
@@ -107,9 +150,10 @@ export class DomTargeter {
107
150
  });
108
151
  for (const { target, elem } of targetElemPairs) {
109
152
  try {
153
+ // track targeted elements
154
+ this.targetedElems = this.targetedElems.concat(elem);
110
155
  if (target.inject) {
111
156
  const injectedElem = this.inject(elem, target);
112
- this.targetedElems = this.targetedElems.concat(elem);
113
157
  // handle both sync and async onTarget functions
114
158
  const result = this.onTarget(target, injectedElem, elem, this);
115
159
  if (result && typeof result.then === 'function') {
@@ -120,7 +164,6 @@ export class DomTargeter {
120
164
  }
121
165
  }
122
166
  else {
123
- this.targetedElems = this.targetedElems.concat(elem);
124
167
  // empty target selector by default
125
168
  target.emptyTarget = target.emptyTarget ?? true;
126
169
  if (target.emptyTarget)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@searchspring/snap-toolbox",
3
- "version": "0.77.0",
3
+ "version": "0.78.0",
4
4
  "description": "Snap Toolbox",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -23,5 +23,5 @@
23
23
  "files": [
24
24
  "dist/**/*"
25
25
  ],
26
- "gitHead": "d7a25a5ade47e4561f49af70f6f929b7331cd15e"
26
+ "gitHead": "9d17504d1ba3b5131c4edeb0cb1edb6ff65ec1b0"
27
27
  }