@financial-times/custom-code-component 2.0.14 → 2.0.16

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.
@@ -1,7 +1,7 @@
1
- function l(o) {
2
- this.listenerMap = [{}, {}], o && this.root(o), this.handle = l.prototype.handle.bind(this), this._removedListeners = [];
1
+ function m(o) {
2
+ this.listenerMap = [{}, {}], o && this.root(o), this.handle = m.prototype.handle.bind(this), this._removedListeners = [];
3
3
  }
4
- l.prototype.root = function(o) {
4
+ m.prototype.root = function(o) {
5
5
  const t = this.listenerMap;
6
6
  let e;
7
7
  if (this.rootElement) {
@@ -19,23 +19,23 @@ l.prototype.root = function(o) {
19
19
  t[0].hasOwnProperty(e) && this.rootElement.addEventListener(e, this.handle, !1);
20
20
  return this;
21
21
  };
22
- l.prototype.captureForType = function(o) {
22
+ m.prototype.captureForType = function(o) {
23
23
  return ["blur", "error", "focus", "load", "resize", "scroll"].indexOf(o) !== -1;
24
24
  };
25
- l.prototype.on = function(o, t, e, n) {
25
+ m.prototype.on = function(o, t, e, n) {
26
26
  let r, s, i, c;
27
27
  if (!o)
28
28
  throw new TypeError("Invalid event type: " + o);
29
29
  if (typeof t == "function" && (n = e, e = t, t = null), n === void 0 && (n = this.captureForType(o)), typeof e != "function")
30
30
  throw new TypeError("Handler must be a type of Function");
31
- return r = this.rootElement, s = this.listenerMap[n ? 1 : 0], s[o] || (r && r.addEventListener(o, this.handle, n), s[o] = []), t ? /^[a-z]+$/i.test(t) ? (c = t, i = P) : /^#[a-z0-9\-_]+$/i.test(t) ? (c = t.slice(1), i = I) : (c = t, i = Element.prototype.matches) : (c = null, i = U.bind(this)), s[o].push({
31
+ return r = this.rootElement, s = this.listenerMap[n ? 1 : 0], s[o] || (r && r.addEventListener(o, this.handle, n), s[o] = []), t ? /^[a-z]+$/i.test(t) ? (c = t, i = U) : /^#[a-z0-9\-_]+$/i.test(t) ? (c = t.slice(1), i = D) : (c = t, i = Element.prototype.matches) : (c = null, i = _.bind(this)), s[o].push({
32
32
  selector: t,
33
33
  handler: e,
34
34
  matcher: i,
35
35
  matcherParam: c
36
36
  }), this;
37
37
  };
38
- l.prototype.off = function(o, t, e, n) {
38
+ m.prototype.off = function(o, t, e, n) {
39
39
  let r, s, i, c, a;
40
40
  if (typeof t == "function" && (n = e, e = t, t = null), n === void 0)
41
41
  return this.off(o, t, e, !0), this.off(o, t, e, !1), this;
@@ -50,12 +50,12 @@ l.prototype.off = function(o, t, e, n) {
50
50
  s = c[r], (!t || t === s.selector) && (!e || e === s.handler) && (this._removedListeners.push(s), c.splice(r, 1));
51
51
  return c.length || (delete i[o], this.rootElement && this.rootElement.removeEventListener(o, this.handle, n)), this;
52
52
  };
53
- l.prototype.handle = function(o) {
53
+ m.prototype.handle = function(o) {
54
54
  let t, e;
55
55
  const n = o.type;
56
56
  let r, s, i, c, a = [], h;
57
- const p = "ftLabsDelegateIgnore";
58
- if (o[p] === !0)
57
+ const l = "ftLabsDelegateIgnore";
58
+ if (o[l] === !0)
59
59
  return;
60
60
  switch (h = o.target, h.nodeType === 3 && (h = h.parentNode), h.correspondingUseElement && (h = h.correspondingUseElement), r = this.rootElement, s = o.eventPhase || (o.target !== o.currentTarget ? 3 : 2), s) {
61
61
  case 1:
@@ -75,21 +75,21 @@ l.prototype.handle = function(o) {
75
75
  if (h === r || (e = a.length, h = h.parentElement || h.parentNode, h instanceof HTMLDocument))
76
76
  break;
77
77
  }
78
- let L;
78
+ let $;
79
79
  for (t = 0; t < u.length; t++)
80
80
  if (!(this._removedListeners.indexOf(u[t][2]) > -1) && (c = this.fire.apply(this, u[t]), c === !1)) {
81
- u[t][0][p] = !0, u[t][0].preventDefault(), L = !1;
81
+ u[t][0][l] = !0, u[t][0].preventDefault(), $ = !1;
82
82
  break;
83
83
  }
84
- return L;
84
+ return $;
85
85
  };
86
- l.prototype.fire = function(o, t, e) {
86
+ m.prototype.fire = function(o, t, e) {
87
87
  return e.handler.call(t, o, t);
88
88
  };
89
- function P(o, t) {
89
+ function U(o, t) {
90
90
  return o.toLowerCase() === t.tagName.toLowerCase();
91
91
  }
92
- function U(o, t) {
92
+ function _(o, t) {
93
93
  return this.rootElement === window ? (
94
94
  // Match the outer document (dispatched from document)
95
95
  t === document || // The <html> element (dispatched from document.body or document.documentElement)
@@ -97,48 +97,51 @@ function U(o, t) {
97
97
  t === window
98
98
  ) : this.rootElement === t;
99
99
  }
100
- function I(o, t) {
100
+ function D(o, t) {
101
101
  return o === t.id;
102
102
  }
103
- l.prototype.destroy = function() {
103
+ m.prototype.destroy = function() {
104
104
  this.off(), this.root();
105
105
  };
106
- function C(o) {
106
+ function N(o) {
107
107
  return typeof o == "string" ? o.trim() : o;
108
108
  }
109
- function N(o, t) {
109
+ function I(o, t) {
110
110
  for (const e in o)
111
111
  t[e] ? console.warn(`You can't set a custom property called ${e}`) : t[e] = o[e];
112
112
  }
113
- const m = Object.freeze({
113
+ const p = Object.freeze({
114
114
  DEBUG: 0,
115
115
  INFO: 1,
116
116
  WARN: 2,
117
117
  ERROR: 3,
118
118
  TEST: 4,
119
119
  DEFAULT: 2
120
- });
121
- function D(o) {
120
+ }), b = "CCC:";
121
+ function S(o) {
122
122
  const t = o == null ? void 0 : o.toLowerCase();
123
- return t === "debug" ? m.DEBUG : t === "info" ? m.INFO : t === "warn" ? m.WARN : t === "error" ? m.ERROR : t === "test" ? m.TEST : m.DEFAULT;
123
+ return t === "debug" ? p.DEBUG : t === "info" ? p.INFO : t === "warn" ? p.WARN : t === "error" ? p.ERROR : t === "test" ? p.TEST : p.DEFAULT;
124
124
  }
125
- class O {
126
- constructor({ level: t = m.DEFAULT } = {
127
- level: m.DEFAULT
125
+ class P {
126
+ constructor({ level: t = p.DEFAULT } = {
127
+ level: p.DEFAULT
128
128
  }) {
129
- this.log = this.debug, this.level = t;
129
+ this.log = this.debug, this.level = localStorage.getItem("CCC_LOG_LEVEL") ? S(localStorage.getItem("CCC_LOG_LEVEL")) : t;
130
130
  }
131
131
  debug(...t) {
132
- this.level <= m.DEBUG && console.info(...t);
132
+ this.level <= p.DEBUG && console.info(b, ...t);
133
133
  }
134
134
  info(...t) {
135
- this.level <= m.INFO && console.info(...t);
135
+ this.level <= p.INFO && console.info(b, ...t);
136
136
  }
137
137
  warn(...t) {
138
- this.level <= m.WARN && console.warn(...t);
138
+ this.level <= p.WARN && console.warn(b, ...t);
139
139
  }
140
140
  error(...t) {
141
- this.level <= m.ERROR && console.error(...t);
141
+ this.level <= p.ERROR && console.error(b, ...t);
142
+ }
143
+ setLogLevel(t) {
144
+ localStorage.getItem("CCC_LOG_LEVEL") ? this.level = S(localStorage.getItem("CCC_LOG_LEVEL")) : typeof t == "number" ? this.level = t : this.level = S(t);
142
145
  }
143
146
  }
144
147
  const M = (o, t, e) => {
@@ -155,51 +158,51 @@ const M = (o, t, e) => {
155
158
  "href",
156
159
  "text",
157
160
  "role"
158
- ], j = (o) => {
161
+ ], F = (o) => {
159
162
  const t = {};
160
163
  for (const e of x) {
161
164
  const n = o[e] || o.getAttribute(e) || o.hasAttribute(e);
162
- n !== void 0 && (typeof n == "boolean" ? t[e] = n : t[e] = C(n));
165
+ n !== void 0 && (typeof n == "boolean" ? t[e] = n : t[e] = N(n));
163
166
  }
164
167
  return t;
165
- }, F = (o) => {
168
+ }, j = (o) => {
166
169
  try {
167
170
  const t = JSON.parse(o), e = Object.prototype.toString.call(t);
168
171
  return [e === "[object Object]" || e === "[object Array]", t];
169
172
  } catch {
170
173
  return [!1, null];
171
174
  }
172
- }, _ = (o) => {
173
- const [t, e] = F(o);
175
+ }, H = (o) => {
176
+ const [t, e] = j(o);
174
177
  return t ? e : o;
175
- }, H = (o, t) => (o.filter(
178
+ }, V = (o, t) => (o.filter(
176
179
  (e) => e.name.match(/^data-trackable|^data-o-|^aria-/i)
177
180
  ).forEach((e) => {
178
181
  t[e.name] = e.value;
179
- }), t), z = (o, t, e) => {
182
+ }), t), Y = (o, t, e) => {
180
183
  const n = {};
181
184
  return e && x.forEach((r) => {
182
185
  typeof t[r] < "u" && r !== "id" && (n[r] = t[r]);
183
186
  }), o.filter((r) => r.name.match(/^data-trackable-context-/i)).forEach((r) => {
184
- n[r.name.replace("data-trackable-context-", "")] = _(r.value);
187
+ n[r.name.replace("data-trackable-context-", "")] = H(r.value);
185
188
  }), n;
186
189
  };
187
- function q(o, t) {
190
+ function z(o, t) {
188
191
  const e = o, n = e != null && e.getAttribute("data-trackable") ? `[data-trackable="${e.getAttribute("data-trackable")}"]` : e == null ? void 0 : e.nodeName, r = [], s = {};
189
192
  for (; o && o !== t; ) {
190
- const i = j(o), c = Array.from(o.attributes);
191
- let a = H(c, i);
193
+ const i = F(o), c = Array.from(o.attributes);
194
+ let a = V(c, i);
192
195
  a["data-trackable"] && (a = Object.assign(
193
196
  a,
194
197
  M(o, e, n)
195
198
  )), r.push(a);
196
- const h = z(c, i, o === e);
197
- N(h, s), o = o.parentNode;
199
+ const h = Y(c, i, o === e);
200
+ I(h, s), o = o.parentNode;
198
201
  }
199
202
  return { trace: r, customContext: s };
200
203
  }
201
- const V = ["ctrlKey", "altKey", "shiftKey", "metaKey"];
202
- class Y {
204
+ const q = ["ctrlKey", "altKey", "shiftKey", "metaKey"];
205
+ class G {
203
206
  constructor({
204
207
  id: t = "00000000-0000-0000-0000-000000000000",
205
208
  name: e = "ccc-component",
@@ -210,15 +213,15 @@ class Y {
210
213
  elements: c = 'a, button, input, [role="button"]',
211
214
  logger: a
212
215
  }) {
213
- this.cccId = t, this.cccName = e, this.subtype = n, this.teamName = r, this.shadowRoot = s, this.category = i, this.elements = c, this.isInitialised = !1, this.log = a ?? new O();
216
+ this.cccId = t, this.cccName = e, this.subtype = n, this.teamName = r, this.shadowRoot = s, this.category = i, this.elements = c, this.isInitialised = !1, this.log = a ?? new P();
214
217
  }
215
218
  // Get properties for the event (as opposed to properties of the clicked element)
216
219
  getEventProperties(t) {
217
220
  const e = {};
218
- for (const n of V)
221
+ for (const n of q)
219
222
  if (t[n])
220
223
  try {
221
- e[n] = C(t[n]);
224
+ e[n] = N(t[n]);
222
225
  } catch (r) {
223
226
  this.log.info(r);
224
227
  }
@@ -227,13 +230,13 @@ class Y {
227
230
  // Controller for handling click events
228
231
  handleClickEvent(t, e) {
229
232
  return (n, r) => {
230
- const s = this.getEventProperties(n), { trace: i, customContext: c } = q(r, e);
233
+ const s = this.getEventProperties(n), { trace: i, customContext: c } = z(r, e);
231
234
  s.custom = r.dataset && r.dataset.custom ? JSON.parse(r.dataset.custom) : null, s.domPathTokens = i, s.component = {
232
235
  id: this.cccId,
233
236
  name: this.cccName,
234
237
  type: "custom-code-component",
235
238
  subtype: this.subtype
236
- }, s.teamName = this.teamName, s.url = document.URL, N(c, s), s.method = "ftCustomAnalytics", t = { ...t, ...s }, document.body.dispatchEvent(
239
+ }, s.teamName = this.teamName, s.url = document.URL, I(c, s), s.method = "ftCustomAnalytics", t = { ...t, ...s }, document.body.dispatchEvent(
237
240
  new CustomEvent("oTracking.event", {
238
241
  detail: t,
239
242
  bubbles: !0,
@@ -273,7 +276,7 @@ class Y {
273
276
  action: "click",
274
277
  category: this.category
275
278
  }, r = (e = this.shadowRoot) == null ? void 0 : e.querySelector("[data-component-root]");
276
- r && new l(r).on(
279
+ r && new m(r).on(
277
280
  "click",
278
281
  this.elements,
279
282
  this.handleClickEvent(n, r),
@@ -282,14 +285,14 @@ class Y {
282
285
  }
283
286
  }
284
287
  }
285
- class f {
288
+ class d {
286
289
  constructor(t) {
287
290
  this.org = "local", this.repo = "dev";
288
- const { org: e, repo: n, name: r, versionRange: s } = S(t) ? t : f.fromString(t);
291
+ const { org: e, repo: n, name: r, versionRange: s } = L(t) ? t : d.fromString(t);
289
292
  e && (this.org = e), n && (this.repo = n), this.name = r, this.versionRange = s;
290
293
  }
291
294
  set path(t) {
292
- const { org: e, repo: n, name: r, versionRange: s } = S(t) ? t : f.fromString(t);
295
+ const { org: e, repo: n, name: r, versionRange: s } = L(t) ? t : d.fromString(t);
293
296
  this.org = e, this.repo = n, this.name = r, this.versionRange = s;
294
297
  }
295
298
  get path() {
@@ -306,42 +309,42 @@ class f {
306
309
  static fromString(t, e) {
307
310
  var a;
308
311
  const n = t ?? "unknown/unknown/unknown", [r, s, i] = n.replace(/@[^\/]+/, "").split("/").reverse(), c = e ?? ((a = n.match(/@[^\/]+/)) == null ? void 0 : a.toString().replace("@", "")) ?? "unknown";
309
- if (s && !c) throw new d("No version specified");
310
- return new f({ org: i, repo: s, name: r, versionRange: c });
312
+ if (s && !c) throw new f("No version specified");
313
+ return new d({ org: i, repo: s, name: r, versionRange: c });
311
314
  }
312
315
  }
313
- function S(o) {
316
+ function L(o) {
314
317
  return typeof o == "object" && o !== null ? "org" in o && "repo" in o && "name" in o : !1;
315
318
  }
316
- class d extends Error {
319
+ class f extends Error {
317
320
  constructor(t, e) {
318
321
  var n;
319
322
  !e && t ? (super(t), this.component = null) : typeof (e == null ? void 0 : e.component) == "string" ? (super(
320
323
  t ?? `${e.cause ?? "Unknown error"} in ${e.component} imported from ${e.source ?? "an undefined source"}.`
321
- ), this.component = f.fromString(e.component)) : S(e == null ? void 0 : e.component) ? (super(
324
+ ), this.component = d.fromString(e.component)) : L(e == null ? void 0 : e.component) ? (super(
322
325
  t ?? `${e.cause ?? "Unknown error"} in ${e.component.org}/${e.component.repo}/${e.component.name}@${e.component.versionRange} imported from ${e.source ?? "an undefined source"}.`
323
- ), this.component = new f(e.component)) : (super(
326
+ ), this.component = new d(e.component)) : (super(
324
327
  `${(e == null ? void 0 : e.cause) ?? "Unknown error"} in unknown component imported from ${(e == null ? void 0 : e.source) ?? "unknown source"}.`
325
- ), this.component = null), this.source = (e == null ? void 0 : e.source) ?? "unknown source", this.errors = [], e != null && e.error && ((n = this.errors) == null || n.push(e == null ? void 0 : e.error)), Error.captureStackTrace && Error.captureStackTrace(this, d), this.name = "CCCError";
328
+ ), this.component = null), this.source = (e == null ? void 0 : e.source) ?? "unknown source", this.errors = [], e != null && e.error && ((n = this.errors) == null || n.push(e == null ? void 0 : e.error)), Error.captureStackTrace && Error.captureStackTrace(this, f), this.name = "CCCError";
326
329
  }
327
330
  }
328
- class w extends d {
331
+ class w extends f {
329
332
  constructor(t, e) {
330
333
  super(t, { ...e, cause: "Import error" }), this.name = "CCCImportError";
331
334
  }
332
335
  }
333
- class $ extends d {
336
+ class O extends f {
334
337
  constructor(t, e) {
335
338
  super(t, { ...e, cause: "Render error" }), this.name = "CCCRenderError";
336
339
  }
337
340
  }
338
- class J extends d {
341
+ class J extends f {
339
342
  constructor(t) {
340
343
  super(null, { ...t, cause: "Timeout error" }), this.name = "CCCTimeoutError";
341
344
  }
342
345
  }
343
- const b = class b extends Event {
344
- constructor(t = b.eventType, e, n) {
346
+ const E = class E extends Event {
347
+ constructor(t = E.eventType, e, n) {
345
348
  super(t, {
346
349
  bubbles: !0,
347
350
  cancelable: !1,
@@ -350,48 +353,48 @@ const b = class b extends Event {
350
353
  }), this.component = e.component, this.source = e.source;
351
354
  }
352
355
  };
353
- b.eventType = "ccc:event";
354
- let g = b;
355
- const E = class E extends g {
356
- constructor(t, e) {
357
- super(E.eventType, t, e);
358
- }
359
- };
360
- E.eventType = "ccc:connected";
361
- let T = E;
356
+ E.eventType = "ccc:event";
357
+ let g = E;
362
358
  const y = class y extends g {
363
359
  constructor(t, e) {
364
360
  super(y.eventType, t, e);
365
361
  }
366
362
  };
367
- y.eventType = "ccc:ready";
368
- let k = y;
363
+ y.eventType = "ccc:connected";
364
+ let T = y;
369
365
  const v = class v extends g {
370
366
  constructor(t, e) {
371
- super(v.eventType, t, e), this.intersecting = !1, this.intersecting = t.intersecting, this.entry = t.entry;
367
+ super(v.eventType, t, e);
372
368
  }
373
369
  };
374
- v.eventType = "ccc:viewport";
375
- let R = v;
370
+ v.eventType = "ccc:ready";
371
+ let k = v;
372
+ const C = class C extends g {
373
+ constructor(t, e) {
374
+ super(C.eventType, t, e), this.intersecting = !1, this.intersecting = t.intersecting, this.entry = t.entry;
375
+ }
376
+ };
377
+ C.eventType = "ccc:viewport";
378
+ let R = C;
376
379
  const W = (o) => o.replace(
377
380
  /[A-Z]+(?![a-z])|[A-Z]/g,
378
381
  (t, e) => (e ? "-" : "") + t.toLowerCase()
379
382
  );
380
- function G(o) {
383
+ function K(o) {
381
384
  return A([
382
385
  "localhost",
383
386
  "local.ft.com",
384
387
  /^.*\.apps\.in\.ft\.com$/
385
388
  ], o);
386
389
  }
387
- function K() {
390
+ function B() {
388
391
  return A([
389
392
  "localhost",
390
393
  "local.ft.com",
391
394
  /^.*\.in\.ft\.com$/
392
395
  ], window.location.hostname);
393
396
  }
394
- function B() {
397
+ function Z() {
395
398
  return A([
396
399
  "spark.ft.com",
397
400
  "spark-staging.ft.com"
@@ -400,18 +403,18 @@ function B() {
400
403
  function A(o, t) {
401
404
  return t ? o.some((e) => typeof e == "string" ? e === t : e.test(t)) : !1;
402
405
  }
403
- function Z(o) {
406
+ function X(o) {
404
407
  if (o === null)
405
408
  return;
406
409
  let t;
407
410
  const e = new URL("http://localhost:5173");
408
411
  try {
409
412
  if (typeof o == "string") {
410
- if ((o === "" || o.toLowerCase() === "true") && K())
413
+ if ((o === "" || o.toLowerCase() === "true") && B())
411
414
  t = e;
412
- else if (t = o.startsWith("http://") || o.startsWith("https://") ? new URL(o) : void 0, t && !G(t == null ? void 0 : t.hostname))
415
+ else if (t = o.startsWith("http://") || o.startsWith("https://") ? new URL(o) : void 0, t && !K(t == null ? void 0 : t.hostname))
413
416
  throw new Error("Unsafe testing host override");
414
- } else B() && (t = e);
417
+ } else Z() && (t = e);
415
418
  } catch {
416
419
  return t;
417
420
  }
@@ -425,8 +428,14 @@ async function Q(o, t) {
425
428
  }
426
429
  ).then(() => !0).catch(() => !1) : !1;
427
430
  }
428
- const X = ":host{width:var(--ccc-root-width, 100%);margin:var(--ccc-root-margin);padding:var(--ccc-root-padding);display:var(--ccc-root-display, block);font-size:var(--ccc-root-fontSize);box-sizing:var(--ccc-root-boxSizing);border:var(--ccc-root-border);grid:var(--ccc-root-grid);line-height:var(--ccc-root-lineHeight)}";
429
- class tt extends HTMLElement {
431
+ const tt = ":host{width:var(--ccc-root-width, 100%);margin:var(--ccc-root-margin);padding:var(--ccc-root-padding);display:var(--ccc-root-display, block);font-size:var(--ccc-root-fontSize);box-sizing:var(--ccc-root-boxSizing);border:var(--ccc-root-border);grid:var(--ccc-root-grid);line-height:var(--ccc-root-lineHeight)}";
432
+ class et extends HTMLElement {
433
+ /**
434
+ * Custom Element constructor.
435
+ *
436
+ * n.b., attributes and ShadowDOM aren't available in custom element constructors.
437
+ * Use connectedCallback() and other lifecycle methods if you want to eg. this.getAttribute()
438
+ */
430
439
  constructor() {
431
440
  super(), this.mode = "open", this.RESERVED_ATTRS = /* @__PURE__ */ new Set([
432
441
  "iframe",
@@ -437,8 +446,8 @@ class tt extends HTMLElement {
437
446
  "shadow-open",
438
447
  "env",
439
448
  "load-timeout"
440
- ]), this.component = new f(), this.observer = new IntersectionObserver((e) => {
441
- e.forEach((n) => {
449
+ ]), this.component = new d(), this.observer = new IntersectionObserver((e) => {
450
+ this.log.debug("Intersection Observer callback", { entries: e }), e.forEach((n) => {
442
451
  this.dispatchEvent(
443
452
  new R({
444
453
  component: this.component,
@@ -450,6 +459,7 @@ class tt extends HTMLElement {
450
459
  });
451
460
  }), this.channel = new MessageChannel(), this.initTracking = async () => {
452
461
  var e;
462
+ this.log.debug("initTracking", { cccId: this.id });
453
463
  try {
454
464
  (e = this.tracking) == null || e.init(this.id);
455
465
  } catch (n) {
@@ -471,9 +481,7 @@ class tt extends HTMLElement {
471
481
  `.trim(), document.head.appendChild(e);
472
482
  const n = document.createElement("script");
473
483
  n.type = "module", n.src = `${(s = this.testUrl) == null ? void 0 : s.origin}/@vite/client`, document.head.appendChild(n);
474
- }, this.log = new O({
475
- level: D(this.getAttribute("log"))
476
- });
484
+ }, this.log = new P();
477
485
  const t = HTMLElement.prototype.hasOwnProperty("attachInternals");
478
486
  try {
479
487
  const e = t && this.attachInternals();
@@ -481,18 +489,29 @@ class tt extends HTMLElement {
481
489
  this.log.error(e);
482
490
  }
483
491
  }
492
+ /**
493
+ * connectedCallback() CE lifecycle callback
494
+ *
495
+ * Called whenever a <custom-code-component> element is mounted to the DOM.
496
+ */
484
497
  async connectedCallback() {
485
498
  try {
499
+ this.log.setLogLevel(this.getAttribute("log")), this.log.debug("connectedCallback");
486
500
  const t = this.getAttribute("path"), e = this.getAttribute("version");
487
- this.component = f.fromString(t, e), this.app = await this.load(), await this.mount(), await this.initTracking();
501
+ this.component = d.fromString(t, e), this.app = await this.load(), await this.mount(), await this.initTracking();
488
502
  } catch (t) {
489
503
  t instanceof Error && requestAnimationFrame(() => {
490
504
  this.emitError(t);
491
505
  }), this.unmount(t);
492
506
  }
493
507
  }
508
+ /**
509
+ * Error handler. Decorates errors for easier ingestion.
510
+ *
511
+ * @param error
512
+ */
494
513
  emitError(t) {
495
- if (console.debug("ccc#emitError", t), t instanceof d)
514
+ if (this.log.debug("emitError", { error: t }), t instanceof f)
496
515
  this.dispatchEvent(
497
516
  new ErrorEvent("ccc:error", {
498
517
  bubbles: !0,
@@ -503,7 +522,7 @@ class tt extends HTMLElement {
503
522
  })
504
523
  );
505
524
  else {
506
- const e = new d(t.message, {
525
+ const e = new f(t.message, {
507
526
  component: this.component,
508
527
  error: t
509
528
  });
@@ -518,15 +537,33 @@ class tt extends HTMLElement {
518
537
  );
519
538
  }
520
539
  }
540
+ /**
541
+ * disconnectedCallback() CE lifecycle event.
542
+ *
543
+ * Called when a <custom-code-component> element is removed from DOM.
544
+ */
521
545
  disconnectedCallback() {
546
+ this.log.debug("disconnectedCallback");
522
547
  const t = this.getAttribute("path");
523
548
  this.log.info(`<custom-code-component:${t}> disconnected`), this.observer.disconnect();
524
549
  }
525
- onmessage() {
526
- }
550
+ /**
551
+ * MessageChannel postMessage callback
552
+ *
553
+ * @param e
554
+ */
555
+ onmessage(t) {
556
+ this.log.debug("onmessage", { event: t });
557
+ }
558
+ /**
559
+ * This error handler is called by the child component on e.g. unrecoverable error.
560
+ * It then calls unmount(), which restores the fallback.
561
+ *
562
+ * @param e
563
+ */
527
564
  onunmount(t) {
528
- if (t instanceof Error) {
529
- const e = new $(t.message, {
565
+ if (this.log.debug("onunmount", { error: t }), t instanceof Error) {
566
+ const e = new O(t.message, {
530
567
  error: t,
531
568
  component: this.component
532
569
  });
@@ -535,17 +572,23 @@ class tt extends HTMLElement {
535
572
  });
536
573
  }
537
574
  }
575
+ /**
576
+ * onready event callback.
577
+ * Called by mount() after kicking off initial component render.
578
+ *
579
+ * @param app
580
+ */
538
581
  async onready(t) {
539
582
  try {
540
- await t, this.dispatchEvent(
583
+ await t, this.log.debug("onready", { app: t }), this.dispatchEvent(
541
584
  new k({
542
585
  component: this.component,
543
586
  source: this.source
544
587
  })
545
588
  ), this.dataset.cccReady = "true", delete this.dataset.cccError, this.observer.observe(this);
546
589
  } catch (e) {
547
- if (e instanceof Error) {
548
- const n = new $(e.message, {
590
+ if (this.log.debug("onready caught error", { error: e }), e instanceof Error) {
591
+ const n = new O(e.message, {
549
592
  error: e,
550
593
  component: this.component
551
594
  });
@@ -555,11 +598,26 @@ class tt extends HTMLElement {
555
598
  }
556
599
  }
557
600
  }
601
+ /**
602
+ * MessageChannel postMessage handler.
603
+ * This can be used for inter-CCC communication.
604
+ * @param event
605
+ */
558
606
  postMessage(t) {
559
- this.channel.port1.postMessage(t);
560
- }
607
+ this.log.debug("postmessage", { event: t }), this.channel.port1.postMessage(t);
608
+ }
609
+ /**
610
+ * Initial mounting behaviour.
611
+ *
612
+ * Attaches ShadowDOM if needed, dispatches ccc:connected event, adds component base styles,
613
+ * generates fallback template element if one doesn't exist already, initialises tracking,
614
+ * then kicks off component rendering. Passes component render promise to onready().
615
+ *
616
+ * @param prerendered
617
+ */
561
618
  async mount(t) {
562
619
  var e, n;
620
+ this.log.debug("mount", t);
563
621
  try {
564
622
  if (this.mode = this.getAttribute("shadow-open") == "false" ? "closed" : "open", this.component) {
565
623
  if (!this.app)
@@ -570,16 +628,17 @@ class tt extends HTMLElement {
570
628
  component: this.component,
571
629
  source: this.source
572
630
  })
573
- ), !s.querySelector('link[href~="custom-code-component.css"]') && !s.adoptedStyleSheets.length && (window.CCC_LAYOUT_STYLESHEET || (window.CCC_LAYOUT_STYLESHEET = new CSSStyleSheet(), window.CCC_LAYOUT_STYLESHEET.replaceSync(X)), s.adoptedStyleSheets = [window.CCC_LAYOUT_STYLESHEET]), !r) {
574
- const p = document.createElement("template");
575
- p.innerHTML = "<div data-component-root><slot></slot></div>", this.appendChild(p), s.appendChild(p.content.cloneNode(!0));
631
+ ), !s.querySelector('link[href~="custom-code-component.css"]') && !s.adoptedStyleSheets.length && (window.CCC_LAYOUT_STYLESHEET || (this.log.debug("mount generating CCC_LAYOUT_STYLESHEET"), window.CCC_LAYOUT_STYLESHEET = new CSSStyleSheet(), window.CCC_LAYOUT_STYLESHEET.replaceSync(tt)), s.adoptedStyleSheets = [window.CCC_LAYOUT_STYLESHEET]), !r) {
632
+ this.log.debug("mount generating fallback template");
633
+ const l = document.createElement("template");
634
+ l.innerHTML = "<div data-component-root><slot></slot></div>", this.appendChild(l), s.appendChild(l.content.cloneNode(!0));
576
635
  }
577
636
  const i = JSON.parse(this.getAttribute("data-component-props")), c = Object.fromEntries(
578
637
  [...this.attributes].filter(
579
- (p) => !this.RESERVED_ATTRS.has(p.name) && !p.name.startsWith("data-")
580
- ).map((p) => [p.name, p.value])
638
+ (l) => !this.RESERVED_ATTRS.has(l.name) && !l.name.startsWith("data-")
639
+ ).map((l) => [l.name, l.value])
581
640
  );
582
- this.tracking = new Y({
641
+ this.tracking = new G({
583
642
  name: (e = this.component) == null ? void 0 : e.toString(),
584
643
  subtype: "interactive",
585
644
  teamName: "djd",
@@ -598,6 +657,7 @@ class tt extends HTMLElement {
598
657
  s,
599
658
  {
600
659
  ...i ?? c,
660
+ log: this.log,
601
661
  data: i ?? c,
602
662
  port: this.channel.port2,
603
663
  tracking: this.tracking,
@@ -615,31 +675,41 @@ class tt extends HTMLElement {
615
675
  ), this.log.error(r), r;
616
676
  }
617
677
  }
618
- // Called in top-level error handler
619
- // Replace shadow root with either <slot> or template[data-component-fallback]
620
- // slot on failure
678
+ /**
679
+ * Called in top-level error handler or by child component on unhandled error.
680
+ * Replace shadow root with either <slot> or template[data-component-fallback]
681
+ * slot on failure
682
+ *
683
+ * @param e
684
+ */
621
685
  unmount(t) {
622
686
  var n;
687
+ this.log.debug("unmount", { error: t });
623
688
  const e = this.querySelector(
624
689
  "template[data-component-fallback]"
625
690
  ) ?? this.querySelector("template");
626
- e && ((n = this.shadowRoot) == null || n.replaceChildren(e.content.cloneNode(!0))), this.dataset.cccError || (this.dataset.cccError = W(t.name.replace("CCC", ""))), delete this.dataset.cccReady, this.observer.disconnect();
691
+ e && (this.log.debug("unmount replacing shadowRoot with fallback"), (n = this.shadowRoot) == null || n.replaceChildren(e.content.cloneNode(!0))), this.dataset.cccError || (this.dataset.cccError = W(t.name.replace("CCC", ""))), delete this.dataset.cccReady, this.observer.disconnect();
627
692
  }
693
+ /**
694
+ * Asynchronously loads the CCC child component.
695
+ *
696
+ * @returns Promise resolving to component renderer function
697
+ */
628
698
  async load() {
629
699
  var c;
630
- if (!this.component.isValid)
700
+ if (this.log.debug("load"), !this.component.isValid)
631
701
  throw new Error("No path found");
632
702
  const t = this.getAttribute("path"), e = this.getAttribute("version"), n = Number(this.getAttribute("load-timeout") || 1e4), r = this.getAttribute("test-env");
633
- this.testUrl = Z(r);
703
+ this.testUrl = X(r);
634
704
  const s = await Q(
635
705
  this.component.name,
636
706
  this.testUrl
637
707
  ), i = this.getAttribute("id");
638
- s && this.testUrl && this.injectViteScripts(), this.source = s ? `${(c = this.testUrl) == null ? void 0 : c.origin}/src/${this.component.name}/index.jsx?id=${i}` : `https://www.ft.com/__component/${this.component.org}/${this.component.repo}${e ? `@${e}` : "@latest"}/${this.component.name}/${this.component.name}.js?id=${i}`;
708
+ s && this.testUrl && (this.log.debug("load adding Vite scripts"), this.injectViteScripts()), this.source = s ? `${(c = this.testUrl) == null ? void 0 : c.origin}/src/${this.component.name}/index.jsx?id=${i}` : `https://www.ft.com/__component/${this.component.org}/${this.component.repo}${e ? `@${e}` : "@latest"}/${this.component.name}/${this.component.name}.js?id=${i}`;
639
709
  try {
640
710
  return await new Promise(
641
711
  (a, h) => {
642
- const p = setTimeout(() => {
712
+ const l = setTimeout(() => {
643
713
  this.log.error("CCC import timeout error"), h(
644
714
  new J({
645
715
  component: this.component,
@@ -654,7 +724,7 @@ class tt extends HTMLElement {
654
724
  /* @vite-ignore */
655
725
  ).then(({ default: u }) => {
656
726
  if (u)
657
- clearTimeout(p), a(u);
727
+ clearTimeout(l), a(u);
658
728
  else
659
729
  throw new w(
660
730
  "No component renderer default export found",
@@ -664,7 +734,7 @@ class tt extends HTMLElement {
664
734
  }
665
735
  );
666
736
  }).catch((u) => {
667
- clearTimeout(p), this.log.error(u), u instanceof Error && !(u instanceof w) ? h(
737
+ clearTimeout(l), this.log.error(u), u instanceof Error && !(u instanceof w) ? h(
668
738
  new w(u.message, {
669
739
  component: this.component,
670
740
  source: this.source
@@ -672,7 +742,7 @@ class tt extends HTMLElement {
672
742
  ) : h(u);
673
743
  });
674
744
  else
675
- throw clearTimeout(p), new w(`Unable to mount ${t}`, {
745
+ throw clearTimeout(l), new w(`Unable to mount ${t}`, {
676
746
  component: this.component,
677
747
  source: this.source
678
748
  });
@@ -684,8 +754,26 @@ class tt extends HTMLElement {
684
754
  ), a;
685
755
  }
686
756
  }
757
+ /**
758
+ * Called whenever the <custom-code-component>'s attributes are changed.
759
+ * Currently only used to dynamically set log level.
760
+ *
761
+ * @param name
762
+ * @param oldValue
763
+ * @param newValue
764
+ */
765
+ attributeChangedCallback(t, e, n) {
766
+ switch (this.log.debug("attributeChangedCallback lifecycle method", {
767
+ name: t,
768
+ oldValue: e,
769
+ newValue: n
770
+ }), t) {
771
+ case "log":
772
+ this.log.setLogLevel(n);
773
+ }
774
+ }
687
775
  }
688
776
  export {
689
- tt as FTCustomCodeComponent
777
+ et as FTCustomCodeComponent
690
778
  };
691
779
  //# sourceMappingURL=custom-element.js.map