@pacem/pacem-core 1.0.0-bernoulli → 1.0.0-binet

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.
Files changed (40) hide show
  1. package/dist/browser/pacem-core.js +919 -32
  2. package/dist/browser/pacem-core.js.map +1 -1
  3. package/dist/browser/pacem-core.min.js +2 -3
  4. package/dist/bundle/pacem-core.min.mjs +6 -6
  5. package/dist/bundle/pacem-core.mjs +510 -22
  6. package/dist/bundle/pacem-core.mjs.map +2 -2
  7. package/dist/docs/pacem-core.json +40109 -0
  8. package/dist/esm/adapter.js +2 -1
  9. package/dist/esm/command.js +6 -1
  10. package/dist/esm/comparers.js +1 -1
  11. package/dist/esm/converters.js +6 -1
  12. package/dist/esm/decorators-next.js +1 -1
  13. package/dist/esm/decorators.js +94 -1
  14. package/dist/esm/defaults.js +2 -1
  15. package/dist/esm/events.js +55 -1
  16. package/dist/esm/eventtarget.js +11 -1
  17. package/dist/esm/expression.js +37 -1
  18. package/dist/esm/index-animations.js +1 -1
  19. package/dist/esm/index-behaviors.js +1 -1
  20. package/dist/esm/index-components.js +1 -1
  21. package/dist/esm/index-iife.js +1 -1
  22. package/dist/esm/index-logging.js +1 -1
  23. package/dist/esm/index-net.js +1 -1
  24. package/dist/esm/index-root.js +1 -1
  25. package/dist/esm/index-ui.js +1 -1
  26. package/dist/esm/index.js +1 -1
  27. package/dist/esm/logger.js +8 -1
  28. package/dist/esm/prefix.js +2 -1
  29. package/dist/esm/promise.js +11 -1
  30. package/dist/esm/regex.js +3 -1
  31. package/dist/esm/storage.js +14 -1
  32. package/dist/esm/template.js +2 -1
  33. package/dist/esm/transforms.js +53 -1
  34. package/dist/esm/types.js +6 -1
  35. package/dist/esm/utils-customelement.js +165 -6
  36. package/dist/esm/utils-customevent.js +27 -1
  37. package/dist/esm/utils.js +96 -1
  38. package/package.json +2 -1
  39. package/typings/index.d.ts +1105 -20
  40. package/dist/browser/pacem-core.min.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @pacem/pacem-core v1.0.0-bernoulli (https://js.pacem.it)
2
+ * @pacem/pacem-core v1.0.0-binet (https://js.pacem.it)
3
3
  * Pacem (https://pacem.it)
4
4
  * Licensed under Apache-2.0
5
5
  */
@@ -24,22 +24,39 @@
24
24
  output['css'] = css;
25
25
  return output;
26
26
  }
27
+ /**
28
+ * Collection of ready-made {@link Easing} functions, each paired with its CSS timing-function equivalent.
29
+ */
27
30
  const Easings = {
31
+ /** No easing: progress is proportional to elapsed time. */
28
32
  linear: assembleEasing(EASINGS.linear, "linear"),
33
+ /** Sine ease-in: starts slow, accelerates towards the end. */
29
34
  sineIn: assembleEasing(EASINGS.sineIn, 'cubic-bezier(0.12, 0, 0.39, 0)'),
35
+ /** Sine ease-out: starts fast, decelerates towards the end. */
30
36
  sineOut: assembleEasing(EASINGS.sineOut, 'cubic-bezier(0.61, 1, 0.88, 1)'),
37
+ /** Sine ease-in-out: accelerates then decelerates, symmetric around the midpoint. */
31
38
  sineInOut: assembleEasing(EASINGS.sineInOut, 'cubic-bezier(0.37, 0, 0.63, 1)'),
32
39
  // TODO: set correct pairing
40
+ /** Exponential ease-in: starts very slow, accelerates sharply towards the end. */
33
41
  expoIn: assembleEasing(EASINGS.expoIn, 'cubic-bezier(0.7, 0, 0.84, 0)'),
42
+ /** Exponential ease-out: starts very fast, decelerates sharply towards the end. */
34
43
  expoOut: assembleEasing(EASINGS.expoOut, 'cubic-bezier(0.16, 1, 0.3, 1)'),
44
+ /** Exponential ease-in-out: sharp acceleration then sharp deceleration, symmetric around the midpoint. */
35
45
  expoInOut: assembleEasing(EASINGS.expoInOut, 'cubic-bezier(0.87, 0, 0.13, 1)'),
36
46
  };
37
47
  //}
38
48
 
39
49
  // namespace Pacem {
50
+ /**
51
+ * Recursively clones plain objects, arrays, `Date`s and `RegExp`s, preserving reference cycles/shared
52
+ * references within a single `clone` call (via an internal `WeakMap`). DOM `Element`s, `FileSystemHandle`s
53
+ * and `File`s are returned as-is (not cloned) - they aren't meaningfully deep-cloneable and are typically
54
+ * meant to be referenced, not duplicated.
55
+ */
40
56
  class DeepCloner {
41
57
  constructor() {
42
58
  }
59
+ /** Deep-clones `obj`; see {@link DeepCloner} for what gets cloned vs. passed through by reference. */
43
60
  static clone(obj) {
44
61
  return new DeepCloner()._clone(obj);
45
62
  }
@@ -110,13 +127,27 @@
110
127
  this._jsonFnWeakMap.delete(fn);
111
128
  }
112
129
  }
130
+ /**
131
+ * A `JSON.stringify`/`JSON.parse` superset able to round-trip values plain JSON can't represent: circular/
132
+ * shared object references (`$#ref_N` markers), `RegExp` instances, DOM `Element`s (serialized by `id`
133
+ * and revived via `document.getElementById`, so they must have one), and - depending on
134
+ * {@link JsonSerializationOptions.functions} - functions themselves. The source object is deep-cloned
135
+ * first (via {@link DeepCloner}) so serialization never mutates the input.
136
+ */
113
137
  class Json {
114
138
  constructor(_options) {
115
139
  this._options = _options;
116
140
  }
141
+ /**
142
+ * Serializes `obj` to a JSON string, extended to support circular/shared references, `RegExp`s,
143
+ * `Element`s (by `id`) and, per `options`, functions.
144
+ * @param obj Value to serialize.
145
+ * @param options Controls how function-valued properties are handled.
146
+ */
117
147
  static serialize(obj, options) {
118
148
  return new Json(options)._serialize(obj);
119
149
  }
150
+ /** Deserializes a string produced by {@link serialize}, restoring references, `RegExp`s, `Element`s and functions. */
120
151
  static deserialize(json) {
121
152
  return new Json()._deserialize(json);
122
153
  }
@@ -240,6 +271,12 @@
240
271
  //}
241
272
 
242
273
  //namespace Pacem {
274
+ /**
275
+ * A `PromiseLike<T>` whose resolution is externalized: unlike a plain `Promise`, the executor isn't
276
+ * passed a callback up front - instead, `resolve`/`reject` are exposed for the caller to invoke later,
277
+ * via the {@link defer} static factory. Useful when the completion of an operation is driven by code
278
+ * that doesn't naturally live inside a `Promise` executor (e.g. event callbacks, decorator plumbing).
279
+ */
243
280
  class DeferPromise {
244
281
  constructor() {
245
282
  this.deferred = null;
@@ -248,6 +285,7 @@
248
285
  me.deferred = { 'resolve': resolve, 'reject': reject, 'promise': me };
249
286
  });
250
287
  }
288
+ /** Standard `PromiseLike.then`, delegating to the underlying native `Promise`. */
251
289
  then(onCompleted, onFailed) {
252
290
  return this.promise.then(onCompleted, onFailed);
253
291
  }
@@ -259,14 +297,17 @@
259
297
  this.promise.then(callback, callback);
260
298
  return this;
261
299
  }
300
+ /** Registers a fulfillment-only callback (fluent, chainable alternative to `then(callback)`). */
262
301
  success(callback) {
263
302
  this.promise.then(callback, null);
264
303
  return this;
265
304
  }
305
+ /** Registers a rejection-only callback (fluent, chainable alternative to `then(null, callback)`). */
266
306
  error(callback) {
267
307
  this.promise.then(null, callback);
268
308
  return this;
269
309
  }
310
+ /** Creates a new deferred promise and returns its controller: `{ resolve, reject, promise }`. */
270
311
  static defer() {
271
312
  var q = new DeferPromise();
272
313
  return q.deferred;
@@ -277,40 +318,56 @@
277
318
  // namespace Pacem {
278
319
  const PACEM_CORE_DEFAULT = 'pacem';
279
320
  const DEFAULT_DOWNLOAD_FILENAME = 'download';
321
+ /** Ready-to-use event listener that only calls `evt.stopPropagation()`; handy as an `addEventListener` callback without allocating a closure. */
280
322
  const stopPropagationHandler = (evt) => {
281
323
  evt.stopPropagation();
282
324
  };
325
+ /** Ready-to-use event listener that only calls `evt.preventDefault()`; handy as an `addEventListener` callback without allocating a closure. */
283
326
  const preventDefaultHandler = (evt) => {
284
327
  evt.preventDefault();
285
328
  };
329
+ /** Ready-to-use event listener that calls both `evt.preventDefault()` and `evt.stopPropagation()`. */
286
330
  const avoidHandler = (evt) => {
287
331
  evt.preventDefault();
288
332
  evt.stopPropagation();
289
333
  };
290
334
  const SEGMENT_PATTERN = /^\/[^\/]+/;
291
335
  const ROUTE_SEGMENT_PATTERN = /\/\{([a-z\$_][\w]*)\??\}/;
336
+ /**
337
+ * The framework's static utility grab-bag: general helpers plus namespaced sub-modules (`Json`, `Dates`,
338
+ * `Css`, `Strings`, `Blobs`, `Images`, `Browsers`, `Cookies`, `URIs`) re-exposing (and in some cases
339
+ * extending) functionality from `@pacem/pacem-foundation`. Also the home of `Utils.core`, the global
340
+ * registry object used for cross-cutting framework state (e.g. registered {@link Transformer}s).
341
+ */
292
342
  class Utils {
343
+ /** The framework's global scratch/registry object (`window[id]`, where `id` defaults to `'pacem'` and is configurable via `window.Pacem.Configuration.core`); created on first access. Used e.g. to store {@link Transformer}-registered transform functions. */
293
344
  static get core() {
294
345
  const root = window['Pacem'];
295
346
  var id = (root && root.Configuration && root.Configuration.core) || PACEM_CORE_DEFAULT;
296
347
  return window[id] = window[id] || {};
297
348
  }
349
+ /** The platform's (native or polyfilled) `customElements` registry. */
298
350
  static get customElements() {
299
351
  return window['customElements'];
300
352
  }
301
353
  // #region GENERAL
354
+ /** Generates a unique numeric-ish id string. */
302
355
  static uniqueId() {
303
356
  return pacemFoundation.Keys.uniqueId();
304
357
  }
358
+ /** Generates a unique short code string. */
305
359
  static uniqueCode() {
306
360
  return pacemFoundation.Keys.uniqueCode();
307
361
  }
362
+ /** Generates a random string of the given `length`. */
308
363
  static randomString(length) {
309
364
  return pacemFoundation.Keys.randomString(length);
310
365
  }
366
+ /** Parses a date-like value (ISO string, `Date`, or timestamp) into a `Date`. */
311
367
  static parseDate(input) {
312
368
  return pacemFoundation.Dates.parse(input);
313
369
  }
370
+ /** Writes `input` to the system clipboard, using the async Clipboard API when available and falling back to `document.execCommand('copy')` otherwise. */
314
371
  static copyToClipboard(input) {
315
372
  if (navigator.clipboard) {
316
373
  return navigator.clipboard.writeText(input);
@@ -378,6 +435,7 @@
378
435
  return filter;
379
436
  }
380
437
  }
438
+ /** Escapes `input` for safe use as a CSS identifier/selector fragment. */
381
439
  static cssEscape(input) {
382
440
  return escape(input).replace('%', '\\');
383
441
  }
@@ -385,9 +443,11 @@
385
443
  static { this.Css = {
386
444
  colorize: Utils.colorize,
387
445
  escape: Utils.cssEscape,
446
+ /** Reads a CSS custom property's current value off the document root (`:root`/`html`). */
388
447
  getVariableValue(name) {
389
448
  return getComputedStyle(document.documentElement).getPropertyValue(name);
390
449
  },
450
+ /** Sets a CSS custom property's value on the document root (`:root`/`html`). */
391
451
  setVariable(name, value) {
392
452
  getComputedStyle(document.documentElement).setProperty(name, value);
393
453
  },
@@ -417,6 +477,7 @@
417
477
  }
418
478
  return false;
419
479
  },
480
+ /** Parses an element's (or style declaration's) computed `transform: matrix(...)` CSS value into its 2D affine matrix components; identity if unset. */
420
481
  deserializeTransform(element) {
421
482
  const style = element instanceof Element ? getComputedStyle(element) : element;
422
483
  let a = 1, b = 0, c = 0, d = 1, x = 0, y = 0, matches = /^matrix\((.*)\)$/.exec(style.transform), mij;
@@ -443,6 +504,7 @@
443
504
  leftPad: pacemFoundation.Strings.leftPad,
444
505
  format: pacemFoundation.Strings.format,
445
506
  diff: pacemFoundation.Strings.diff,
507
+ /** Strips HTML markup from `html`, returning its plain-text content. */
446
508
  stripHTML: (html) => {
447
509
  let doc = new DOMParser().parseFromString(html, 'text/html');
448
510
  return doc.body.textContent || '';
@@ -461,6 +523,7 @@
461
523
  load: pacemFoundation.Imaging.loadImage,
462
524
  resize: pacemFoundation.Imaging.resizeImage
463
525
  }; }
526
+ /** Loads an image from `src` and resolves with the `HTMLImageElement` once ready (or rejects on error). */
464
527
  static loadImage(src) {
465
528
  return new Promise((resolve, reject) => {
466
529
  const img = new Image();
@@ -478,15 +541,19 @@
478
541
  }
479
542
  });
480
543
  }
544
+ /** Converts a `Blob` to a `data:` URL string. */
481
545
  static blobToDataURL(blob) {
482
546
  return Utils.Blobs.toDataURL(blob);
483
547
  }
548
+ /** Converts a `data:` URL string back into a `Blob`. */
484
549
  static dataURLToBlob(dataURL) {
485
550
  return Utils.Blobs.fromDataURL(dataURL);
486
551
  }
552
+ /** Reads a `Blob`'s content as text, using the given `encoding` (default UTF-8). */
487
553
  static blobToText(blob, encoding) {
488
554
  return Utils.Blobs.toText(blob, encoding);
489
555
  }
556
+ /** Wraps `content` in a `Blob` of the given MIME `type` (default `'text/plain'`). */
490
557
  static textToBlob(content, type = 'text/plain') {
491
558
  return Utils.Blobs.fromText(content, type);
492
559
  }
@@ -572,6 +639,7 @@
572
639
  el.src = url;
573
640
  return deferred.promise;
574
641
  }
642
+ /** Returns the list of vendor-prefixed `getUserMedia` implementations available on `navigator`, if any. */
575
643
  static getUserMediaFunctions() {
576
644
  var _getUserMedia = [];
577
645
  let methods = [navigator['getUserMedia'], navigator['webkitGetUserMedia'], navigator['msGetUserMedia'], navigator['mozGetUserMedia']];
@@ -818,10 +886,12 @@
818
886
  }
819
887
  // #endregion
820
888
  // #region DOM
889
+ /** Whether the document (including module scripts) has fully finished loading (`document.readyState === 'complete'`). */
821
890
  static isDOMReady() {
822
891
  // Must exclude 'interactive' state since module script haven't been processed yet.
823
892
  return /* document.readyState === 'interactive' ||*/ document.readyState === 'complete';
824
893
  }
894
+ /** Registers `listener` to run once the document (and its resources, e.g. images) has fully loaded (the `window` `'load'` event). */
825
895
  static onDOMReady(listener) {
826
896
  //window.addEventListener('DOMContentLoaded', listener, false);
827
897
  // window 'load' event fires after 'DOMCOntentLoaded' since includes images load.
@@ -850,13 +920,16 @@
850
920
  }
851
921
  return dom;
852
922
  }
923
+ /** Cross-browser `Element.matches(selector)`, falling back to vendor-prefixed variants. */
853
924
  static is(el, selector) {
854
925
  return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector)
855
926
  .call(el, selector);
856
927
  }
928
+ /** Resolves the effective language for `el`: its own `lang` attribute, else the document's, else the browser's. */
857
929
  static lang(el) {
858
930
  return el.lang || document.documentElement.lang || navigator.language;
859
931
  }
932
+ /** JSON-stringifies `obj` (via {@link Json}), or passes through `null`/`undefined` unchanged. */
860
933
  static jsonSortStringify(obj) {
861
934
  if (Utils.isNull(obj)) {
862
935
  return obj;
@@ -866,6 +939,7 @@
866
939
  static { this.Browsers = {
867
940
  detect: pacemFoundation.detect
868
941
  }; }
942
+ /** Parses a `document.cookie`-style string (or `document.cookie` itself, by default) into a name/value map. */
869
943
  static cookies(cookie) {
870
944
  const cookies = (cookie ?? document.cookie).split(';'), retval = {};
871
945
  for (var pair of cookies) {
@@ -881,7 +955,9 @@
881
955
  }
882
956
  return retval;
883
957
  }
958
+ /** Cookie helpers, preferring the native `cookieStore` API when available and falling back to `document.cookie` parsing otherwise. */
884
959
  static { this.Cookies = {
960
+ /** Retrieves all cookies (or just `cookieName`, if given) as {@link CookieData} entries. */
885
961
  getAll: async (cookieName) => {
886
962
  const store = 'cookieStore' in window ? window.cookieStore : null;
887
963
  const retval = [];
@@ -899,6 +975,7 @@
899
975
  return await store.getAll(cookieName);
900
976
  }
901
977
  },
978
+ /** Serializes a {@link CookieData} descriptor into a `document.cookie`-assignable string (including `domain`/`path`/`max-age`/`expires`/`Partitioned`/`SameSite`/`Secure` attributes, as provided). */
902
979
  stringify: (data) => {
903
980
  let retval = `${data.name}=${encodeURIComponent(data.value ?? '')}`;
904
981
  if (!Utils.isNullOrEmpty(data.domain)) {
@@ -925,6 +1002,7 @@
925
1002
  return retval;
926
1003
  }
927
1004
  }; }
1005
+ /** Tests whether `el` is currently visible (via the `checkVisibility` API when available, falling back to a CSS-visibility/size heuristic). */
928
1006
  static isVisible(el) {
929
1007
  if ('checkVisibility' in el) {
930
1008
  return el.checkVisibility({ checkOpacity: true, checkVisibilityCSS: true });
@@ -932,6 +1010,7 @@
932
1010
  return getComputedStyle(el).visibility !== 'hidden' && (el.clientWidth > 0 || el.clientHeight > 0);
933
1011
  }
934
1012
  //#region classList DOMTokenList (css)
1013
+ /** Tests whether `el` has `className` set, using `classList` when available (with a regex-based fallback). */
935
1014
  static hasClass(el, className) {
936
1015
  if (el.classList) {
937
1016
  return el.classList.contains(className);
@@ -940,6 +1019,7 @@
940
1019
  return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
941
1020
  }
942
1021
  }
1022
+ /** Adds one or more (space-separated) classes to `el`, using `classList` when available. */
943
1023
  static addClass(el, className) {
944
1024
  const css = className.trim();
945
1025
  if (el.classList) {
@@ -949,6 +1029,7 @@
949
1029
  el.setAttribute('class', el.className + ' ' + css);
950
1030
  }
951
1031
  }
1032
+ /** Removes one or more (space-separated) classes from `el`, using `classList` when available. */
952
1033
  static removeClass(el, className) {
953
1034
  const css = className.trim();
954
1035
  if (el.classList) {
@@ -958,6 +1039,7 @@
958
1039
  el.setAttribute('class', el.className.replace(new RegExp('(^|\\b)' + css.split(' ').join('|') + '(\\b|$)', 'gi'), ' '));
959
1040
  }
960
1041
  }
1042
+ /** Adds or removes `className` on `el` depending on `on`; see {@link addClass}/{@link removeClass}. */
961
1043
  static toggleClass(el, className, on) {
962
1044
  if (on) {
963
1045
  Utils.addClass(el, className);
@@ -968,15 +1050,19 @@
968
1050
  }
969
1051
  //#endregion
970
1052
  //#region part DOMTokenList (shadow-DOM)
1053
+ /** Tests whether `el`'s `part` attribute (CSS Shadow Parts) contains `partName`. */
971
1054
  static hasPart(el, partName) {
972
1055
  return el.part.contains(partName);
973
1056
  }
1057
+ /** Adds one or more (space-separated) shadow-part names to `el`'s `part` attribute. */
974
1058
  static addPart(el, partName) {
975
1059
  DOMTokenList.prototype.add.apply(el.part, partName.trim().split(' '));
976
1060
  }
1061
+ /** Removes one or more (space-separated) shadow-part names from `el`'s `part` attribute. */
977
1062
  static removePart(el, partName) {
978
1063
  DOMTokenList.prototype.remove.apply(el.part, partName.trim().split(' '));
979
1064
  }
1065
+ /** Adds or removes `partName` on `el`'s `part` attribute depending on `on`; see {@link addPart}/{@link removePart}. */
980
1066
  static togglePart(el, partName, on) {
981
1067
  if (on) {
982
1068
  Utils.addPart(el, partName);
@@ -1012,9 +1098,11 @@
1012
1098
  height: rect.height
1013
1099
  };
1014
1100
  }
1101
+ /** Sums `offsetTop` up the `offsetParent` chain, giving `el`'s vertical position relative to the document rather than just its nearest positioned ancestor. */
1015
1102
  static naturalOffsetTop(el) {
1016
1103
  return (el?.offsetTop ?? 0) + ((el?.offsetParent && el.offsetParent instanceof HTMLElement) ? this.naturalOffsetTop(el.offsetParent) : 0);
1017
1104
  }
1105
+ /** Sums `offsetTop` up the `offsetParent` chain (note: mirrors {@link naturalOffsetTop}'s calculation, not `offsetLeft`), giving `el`'s horizontal position relative to the document. */
1018
1106
  static naturalOffsetLeft(el) {
1019
1107
  return (el?.offsetTop ?? 0) + ((el?.offsetParent && el.offsetParent instanceof HTMLElement) ? this.naturalOffsetLeft(el.offsetParent) : 0);
1020
1108
  }
@@ -1042,18 +1130,30 @@
1042
1130
  static deserializeTransform(obj) {
1043
1131
  return Utils.Css.deserializeTransform(obj);
1044
1132
  }
1133
+ /** Sets the window's vertical scroll position, keeping the current horizontal position. */
1045
1134
  static set scrollTop(y) {
1046
1135
  window.scrollTo(Utils.scrollLeft, y);
1047
1136
  }
1137
+ /** Sets the window's horizontal scroll position, keeping the current vertical position. */
1048
1138
  static set scrollLeft(x) {
1049
1139
  window.scrollTo(x, Utils.scrollTop);
1050
1140
  }
1141
+ static scrollTo(x, y = true, smooth = true) {
1142
+ const yFirst = Utils.isNull(y) || typeof y === 'boolean';
1143
+ const left = yFirst ? Utils.scrollLeft : x;
1144
+ const top = yFirst ? x : y;
1145
+ const behavior = (yFirst ? y : smooth) ? 'smooth' : 'instant';
1146
+ window.scrollTo({ behavior, left, top });
1147
+ }
1148
+ /** The window's current vertical scroll position, with fallbacks for older browsers. */
1051
1149
  static get scrollTop() {
1052
1150
  return window.scrollY /*window.pageYOffset*/ || document.documentElement.scrollTop || document.body.scrollTop || 0;
1053
1151
  }
1152
+ /** The window's current horizontal scroll position, with fallbacks for older browsers. */
1054
1153
  static get scrollLeft() {
1055
1154
  return window.scrollX /*window.pageXOffset*/ || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
1056
1155
  }
1156
+ /** The window's current viewport size (`{ width, height }`), with fallbacks for older browsers. */
1057
1157
  static get windowSize() {
1058
1158
  let win = window;
1059
1159
  return {
@@ -1129,16 +1229,20 @@
1129
1229
  }
1130
1230
  // #endregion
1131
1231
  // #region other
1232
+ /** Tests whether `obj` is "empty" (per {@link NullChecker.isEmpty}: `null`/`undefined`/`''`/an empty array or object), excluding DOM `Node`s (which are never considered empty here). */
1132
1233
  static isEmpty(obj) {
1133
1234
  return pacemFoundation.NullChecker.isEmpty(obj) && !(obj instanceof Node);
1134
1235
  }
1236
+ /** Type-guarding test for `obj` being `null` or `undefined`. */
1135
1237
  static isNull(obj) {
1136
1238
  return pacemFoundation.NullChecker.isNull(obj);
1137
1239
  }
1138
1240
  // legacy
1241
+ /** Type-guarding test for `val` being an array. */
1139
1242
  static isArray(val) {
1140
1243
  return Array.isArray(val);
1141
1244
  }
1245
+ /** Tests whether `val` is `null`/`undefined` or "empty"; see {@link isNull}/{@link isEmpty}. */
1142
1246
  static isNullOrEmpty(val) {
1143
1247
  return Utils.isNull(val) || Utils.isEmpty(val);
1144
1248
  }
@@ -1157,6 +1261,7 @@
1157
1261
  }
1158
1262
  /** Legacy alias for Object.assign(). */
1159
1263
  static { this.extend = Object.assign; }
1264
+ /** Deep-clones `obj`; see {@link DeepCloner}. */
1160
1265
  static clone(obj) {
1161
1266
  if (obj === undefined)
1162
1267
  return undefined;
@@ -1166,6 +1271,7 @@
1166
1271
  static fromResult(v) {
1167
1272
  return Promise.resolve(v);
1168
1273
  }
1274
+ /** Runs `task` on the next animation frame and wraps its result in a `Promise`. */
1169
1275
  static fromResultAsync(task) {
1170
1276
  return new Promise(resolve => requestAnimationFrame(() => resolve(task())));
1171
1277
  }
@@ -1189,7 +1295,15 @@
1189
1295
  }
1190
1296
  //#endregion
1191
1297
  //#region Net
1298
+ /** URL/route parsing and formatting helpers, chiefly backing the router (`{segment}`/`{segment?}` template resolution, query-string parsing, route metadata). */
1192
1299
  static { this.URIs = {
1300
+ /**
1301
+ * Substitutes each `{name}`/`{name?}` template segment in `url` with the matching entry of `parameters`
1302
+ * (URL-encoded), then strips out any remaining unmatched *optional* segments.
1303
+ * @param url URL/route template containing `{name}`/`{name?}` segments.
1304
+ * @param parameters Values to substitute, keyed by segment name.
1305
+ * @param removeMatchedParameters When `true`, consumed entries are deleted from `parameters`.
1306
+ */
1193
1307
  format: function (url, parameters, removeMatchedParameters) {
1194
1308
  // replace segments
1195
1309
  for (let name in parameters || {}) {
@@ -1212,6 +1326,14 @@
1212
1326
  }
1213
1327
  return url;
1214
1328
  },
1329
+ /**
1330
+ * Appends `parameters` to `url`'s query string (or hash fragment, when `hash` is `true`), URL-encoding
1331
+ * names and values, and correctly choosing `?`/`&` (or `#`/`&`) as the joining separator.
1332
+ * @param url Base URL.
1333
+ * @param parameters Values to append, keyed by parameter name.
1334
+ * @param removeNullEntries When `true`, entries whose value is `null`/`undefined` are omitted instead of appended as empty.
1335
+ * @param hash When `true`, appends to the URL's hash fragment instead of its query string.
1336
+ */
1215
1337
  appendQuery: function (url, parameters, removeNullEntries = false, hash = false) {
1216
1338
  const char = hash ? '#' : '?', pattern = hash ? /#/ : /\?/;
1217
1339
  const query = (pattern.test(url) ? '&' : char) +
@@ -1220,6 +1342,7 @@
1220
1342
  .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(parameters[k] ?? '')).join('&');
1221
1343
  return url + (query.length > 1 ? query : '');
1222
1344
  },
1345
+ /** Parses a query string (or a `Location`'s `.search`, defaulting to `window.location`) into a name/value map. */
1223
1346
  parseQuery: (query = window.location) => {
1224
1347
  if (typeof query !== 'string') {
1225
1348
  query = query.search;
@@ -1230,9 +1353,11 @@
1230
1353
  });
1231
1354
  return obj;
1232
1355
  },
1356
+ /** Tests whether `url` contains at least one non-optional `{name}` template segment (as opposed to only `{name?}` ones). */
1233
1357
  hasMandatoryTemplateSegments: function (url) {
1234
1358
  return /(^|\/)\{\.*\}(\/|$)/.test(url);
1235
1359
  },
1360
+ /** Parses a route template's `{name}`/`{name?}` segments into an ordered list of {@link RouteMetadata} descriptors, consumed by {@link parseState}. */
1236
1361
  parseRoute: function (pathTemplate) {
1237
1362
  let tmpl = pathTemplate;
1238
1363
  const trunks = [];
@@ -1252,6 +1377,7 @@
1252
1377
  }
1253
1378
  return trunks;
1254
1379
  },
1380
+ /** Splits `url` into its `protocol`, `domain`, `path`, `query` (including leading `?`) and `hash` (including leading `#`) parts, or `null` if it can't be parsed. */
1255
1381
  split: function (url) {
1256
1382
  const URL_PATTERN = /^((https?:)?\/\/[^\/]+)?([^\?#]+)(\?[^#]*)?(#[^#]*)?$/;
1257
1383
  const regArr = URL_PATTERN.exec(url);
@@ -1260,6 +1386,16 @@
1260
1386
  }
1261
1387
  return { domain: regArr[2] ?? '', protocol: regArr[1] ?? '', path: regArr[3] ?? '', query: regArr[4] ?? '', hash: regArr[5] ?? '' };
1262
1388
  },
1389
+ /**
1390
+ * Builds a {@link RouterState} for `url`, extracting named route segments per `metadata` (see
1391
+ * {@link parseRoute}) as top-level properties, alongside the standard `$path`/`$pathname`/`$querystring`/
1392
+ * `$query`/`$hash` keys. Throws if a non-optional route segment declared in `metadata` isn't present in `path`.
1393
+ * @param metadata Route segment descriptors, as produced by {@link parseRoute}.
1394
+ * @param url Full URL/path being navigated to.
1395
+ * @param path Path component override; parsed out of `url` via {@link split} when omitted.
1396
+ * @param query Query-string override (including leading `?`); parsed out of `url` when omitted.
1397
+ * @param hash Hash-fragment override (including leading `#`); parsed out of `url` when omitted.
1398
+ */
1263
1399
  parseState: function (metadata, url, path, query, hash) {
1264
1400
  let fullPath = url;
1265
1401
  if (Utils.isNullOrEmpty(path)) {
@@ -1344,6 +1480,7 @@
1344
1480
  }
1345
1481
  // }
1346
1482
 
1483
+ /** String tokens accepted by {@link CustomEventUtils.matchModifiers} to describe a keyboard/mouse modifier. */
1347
1484
  var EventKeyModifier;
1348
1485
  (function (EventKeyModifier) {
1349
1486
  EventKeyModifier["AltKey"] = "Alt";
@@ -1351,11 +1488,24 @@
1351
1488
  EventKeyModifier["ShiftKey"] = "Shift";
1352
1489
  EventKeyModifier["MetaKey"] = "Cmd";
1353
1490
  })(EventKeyModifier || (EventKeyModifier = {}));
1491
+ /** Static helpers for inspecting and normalizing native/custom events (coordinates, keyboard modifiers, type checks). */
1354
1492
  class CustomEventUtils {
1493
+ /**
1494
+ * Type-guarding check for whether `evt` is an instance of the given event `type`.
1495
+ * @param evt Event to test.
1496
+ * @param type Event constructor to test against.
1497
+ * @returns `true` (narrowing `evt` to `TEvent`) if `evt instanceof type`.
1498
+ */
1355
1499
  static isInstanceOf(evt, type) {
1356
1500
  return evt instanceof type;
1357
1501
  // || CustomElementUtils.getAttachedPropertyValue(evt, 'pacem:custom-event') === evt.type;
1358
1502
  }
1503
+ /**
1504
+ * Extracts page/client/screen coordinates from a mouse or (single-)touch event, using the first
1505
+ * active touch (`touches[0]`, falling back to `changedTouches[0]`) for `TouchEvent`s.
1506
+ * @param evt Source mouse/touch event, or an already-extracted {@link UIEventLike}.
1507
+ * @returns The event's position in all three coordinate systems.
1508
+ */
1359
1509
  static getEventCoordinates(evt) {
1360
1510
  var src;
1361
1511
  if ('touches' in evt) {
@@ -1375,6 +1525,11 @@
1375
1525
  client: { x: src.clientX, y: src.clientY }
1376
1526
  };
1377
1527
  }
1528
+ /**
1529
+ * Extracts the keyboard-modifier flags (and, for mouse events, the pressed button as `which`) from a native event.
1530
+ * @param evt Source keyboard/mouse/touch event, or an already-extracted {@link KeyEventLike}.
1531
+ * @returns The captured modifier flags.
1532
+ */
1378
1533
  static getEventKeyModifiers(evt) {
1379
1534
  var which = evt.which;
1380
1535
  if (evt instanceof MouseEvent) {
@@ -1395,6 +1550,13 @@
1395
1550
  }
1396
1551
  return true;
1397
1552
  }
1553
+ /**
1554
+ * Works around a legacy Edge/ChakraCore bug (see {@link https://github.com/Microsoft/ChakraCore/issues/3952})
1555
+ * where an instance built via `super(...)` from a `CustomEvent` subclass constructor doesn't correctly
1556
+ * pass `instanceof` checks against that subclass; forcibly resets its prototype when so.
1557
+ * @param evt Event instance to fix up.
1558
+ * @param type The subclass constructor `evt` is supposed to be an instance of.
1559
+ */
1398
1560
  static fixEdgeCustomEventSubClassInstance(evt, type) {
1399
1561
  // this an optimistic BUGGED workaround due to a damn' Edge bug: https://github.com/Microsoft/ChakraCore/issues/3952
1400
1562
  if (!(evt instanceof type)) {
@@ -1406,7 +1568,17 @@
1406
1568
 
1407
1569
  /// <reference path="utils-customevent.ts" />
1408
1570
  // namespace Pacem {
1571
+ /**
1572
+ * Base class for framework custom events whose `detail` payload is strongly typed as `TDetail`.
1573
+ * Thin wrapper around the native `CustomEvent<TDetail>` that also works around an old Edge bug
1574
+ * (see {@link CustomEventUtils.fixEdgeCustomEventSubClassInstance}) affecting `CustomEvent` subclasses.
1575
+ */
1409
1576
  class CustomTypedEvent extends CustomEvent /* new in TypeScript v2.7.1 -> */ {
1577
+ /**
1578
+ * @param type Event name.
1579
+ * @param detail Strongly-typed payload, exposed as `event.detail`.
1580
+ * @param eventInit Standard `CustomEvent` initialization options (`bubbles`, `cancelable`, `composed`).
1581
+ */
1410
1582
  constructor(type, detail, eventInit) {
1411
1583
  super(type, Utils.extend({ detail: detail }, eventInit || {}));
1412
1584
  CustomEventUtils.fixEdgeCustomEventSubClassInstance(this, this.constructor);
@@ -1425,7 +1597,20 @@
1425
1597
  return false;
1426
1598
  }
1427
1599
  // TODO: make inherit from CustomTypedEvent
1600
+ /**
1601
+ * Base class for UI-originated custom events: like {@link CustomTypedEvent}, but additionally captures
1602
+ * the mouse/touch/keyboard modifiers and coordinates of the originating native event (when supplied),
1603
+ * exposing them through the {@link UIEventLike} surface (`which`, `altKey`, `pageX`, `clientY`, ...).
1604
+ * Useful for events that are re-dispatched/synthesized (e.g. drag & drop) from an original pointer or
1605
+ * keyboard event, so that consumers can still inspect that original event's modifiers/position.
1606
+ */
1428
1607
  class CustomUIEvent extends CustomEvent {
1608
+ /**
1609
+ * @param type Event name.
1610
+ * @param detail Either the strongly-typed payload, or (when it satisfies `CustomEventInit`, i.e. has a `detail` key) the full event-init object.
1611
+ * @param eventInit Either standard `CustomEvent` init options, or the original native event this custom event derives from (in which case its coordinates/modifiers get captured).
1612
+ * @param orig The original native mouse/touch/keyboard event this custom event derives from, when `eventInit` is itself the init options.
1613
+ */
1429
1614
  constructor(type, detail, eventInit, orig) {
1430
1615
  super(type, Utils.extend((isEventInit(detail || {}) ? detail : { detail: detail }), (!(eventInit instanceof Event) && eventInit) || {}));
1431
1616
  const originalEvent = orig || eventInit;
@@ -1478,30 +1663,70 @@
1478
1663
  return this.#coords?.screen.y;
1479
1664
  }
1480
1665
  }
1666
+ /** Event name dispatched whenever an observed attribute changes; see {@link AttributeChangeEvent}. */
1481
1667
  const AttributeChangeEventName = 'attributechange';
1668
+ /**
1669
+ * Dispatched by elements registered with the {@link CustomElement} decorator whenever one of their
1670
+ * observed attributes changes, mirroring the native `attributeChangedCallback` as a DOM event.
1671
+ */
1482
1672
  class AttributeChangeEvent extends CustomTypedEvent {
1483
1673
  constructor(args) {
1484
1674
  super(AttributeChangeEventName, args);
1485
1675
  }
1486
1676
  }
1677
+ /** Event name dispatched whenever a `@Watch`-decorated property changes value; see {@link PropertyChangeEvent}. */
1487
1678
  const PropertyChangeEventName = 'propertychange';
1679
+ /**
1680
+ * Dispatched whenever a property decorated with {@link Watch} changes value (unless that decorator's
1681
+ * `emit` option is set to `false`). This is the mechanism data-bound expressions listen to in order to
1682
+ * re-evaluate themselves when one of their dependencies changes.
1683
+ */
1488
1684
  class PropertyChangeEvent extends CustomTypedEvent {
1489
1685
  constructor(args) {
1490
1686
  super(PropertyChangeEventName, args);
1491
1687
  }
1492
1688
  }
1689
+ // #region NAVIGATING
1690
+ /** Event name dispatched by a router *before* a navigation is committed; see {@link RouterNavigatingEvent}. Cancelable: calling `preventDefault()` aborts the navigation. */
1691
+ const RouterNavigatingEventName = 'navigating';
1692
+ /** Event name dispatched by a router *after* a navigation has been committed; see {@link RouterNavigateEvent}. */
1693
+ const RouterNavigateEventName = 'navigate';
1694
+ /** Dispatched by a router once it has navigated to a new `path` (not cancelable — the navigation already happened). */
1695
+ class RouterNavigateEvent extends CustomTypedEvent {
1696
+ /** @param path Either the destination path alone, or the full navigation args (path, title, referrer). */
1697
+ constructor(path) {
1698
+ super(RouterNavigateEventName, typeof path === 'string' ? { path } : path, { cancelable: false, bubbles: false });
1699
+ }
1700
+ }
1701
+ /** Dispatched by a router right before navigating to `path`; cancelable, so a listener can call `preventDefault()` to abort the navigation. */
1702
+ class RouterNavigatingEvent extends CustomTypedEvent {
1703
+ /** @param path Destination path about to be navigated to. */
1704
+ constructor(path) {
1705
+ super(RouterNavigatingEventName, path, { cancelable: true, bubbles: false });
1706
+ }
1707
+ }
1708
+ // #endregion
1493
1709
  //}
1494
1710
 
1711
+ /**
1712
+ * `step` event dispatched on every animation frame of a running tween, carrying the current progress and value.
1713
+ */
1495
1714
  class AnimationEvent extends CustomTypedEvent {
1496
1715
  constructor(args) {
1497
1716
  super("step", args);
1498
1717
  }
1499
1718
  }
1719
+ /**
1720
+ * `end` event dispatched once a tween/animation completes.
1721
+ */
1500
1722
  class AnimationEndEvent extends CustomEvent {
1501
1723
  constructor() {
1502
1724
  super('end');
1503
1725
  }
1504
1726
  }
1727
+ /**
1728
+ * `start` event dispatched when a tween/animation begins.
1729
+ */
1505
1730
  class AnimationStartEvent extends CustomEvent {
1506
1731
  constructor() {
1507
1732
  super('start');
@@ -1510,7 +1735,20 @@
1510
1735
  //}
1511
1736
 
1512
1737
  //namespace Pacem.Animations {
1738
+ /**
1739
+ * Runs `requestAnimationFrame`-driven numeric tweens between two values, invoking a callback on each frame.
1740
+ */
1513
1741
  class TweenService {
1742
+ /**
1743
+ * Tweens a numeric value from `from` to `to` over `duration` milliseconds, invoking `callback` on every animation frame.
1744
+ * @param from Starting value.
1745
+ * @param to Ending value.
1746
+ * @param duration Tween duration, in milliseconds.
1747
+ * @param delay Delay before the tween starts, in milliseconds (default `0`).
1748
+ * @param easing Easing function applied to the normalized `[0,1]` time (defaults to {@link Easings.linear}).
1749
+ * @param callback Invoked on every frame (and once more with `time === 1.0`) with the normalized time and the current value.
1750
+ * @returns A promise resolved when the tween completes.
1751
+ */
1514
1752
  run(from, to, duration, delay = 0, easing = Easings.linear, callback = null) {
1515
1753
  return new Promise((resolve, _) => {
1516
1754
  const now = (performance && performance.now()) || Date.now();
@@ -1543,6 +1781,10 @@
1543
1781
  //}
1544
1782
 
1545
1783
  // namespace Pacem.Animations {
1784
+ /**
1785
+ * `requestAnimationFrame`-driven timer that invokes a callback at (approximately) a given frame rate.
1786
+ * Instances are created via the static {@link Timer.run} factory rather than `new`.
1787
+ */
1546
1788
  class Timer {
1547
1789
  #fps;
1548
1790
  #callback;
@@ -1563,9 +1805,15 @@
1563
1805
  this.#handle = requestAnimationFrame(this._run);
1564
1806
  }
1565
1807
  #then;
1808
+ /**
1809
+ * Creates and starts a new {@link Timer}.
1810
+ * @param callback Invoked on every tick with the current frame timestamp.
1811
+ * @param fps Target frame rate, in frames per second (default `60`).
1812
+ */
1566
1813
  static run(callback, fps = 60) {
1567
1814
  return new Timer(callback, fps);
1568
1815
  }
1816
+ /** Stops the timer, cancelling any pending animation frame. */
1569
1817
  stop() {
1570
1818
  cancelAnimationFrame(this.#handle);
1571
1819
  }
@@ -1583,6 +1831,7 @@
1583
1831
  });
1584
1832
 
1585
1833
  //namespace Pacem.Net {
1834
+ /** HTTP verbs accepted by {@link Fetcher.method} / {@link Http}. */
1586
1835
  var HttpMethod;
1587
1836
  (function (HttpMethod) {
1588
1837
  HttpMethod["Get"] = "GET";
@@ -1595,10 +1844,15 @@
1595
1844
  HttpMethod["Connect"] = "CONNECT";
1596
1845
  HttpMethod["Trace"] = "TRACE";
1597
1846
  })(HttpMethod || (HttpMethod = {}));
1847
+ /** Event name dispatched with the raw fetch result payload; see {@link Fetcher.result}. */
1598
1848
  const FetchResultEventName = 'fetchresult';
1849
+ /** Event name dispatched when a {@link Fetcher}'s request fails. */
1599
1850
  const FetchErrorEventName = 'error';
1851
+ /** Event name dispatched when a {@link Fetcher}'s request completes successfully. */
1600
1852
  const FetchSuccessEventName = 'success';
1853
+ /** Static helpers for working with fetch `Response`s. */
1601
1854
  class Fetcher {
1855
+ /** Tests whether a response carries no body (HTTP 204, or an explicit `Content-Length: 0`). */
1602
1856
  static isEmpty(r) {
1603
1857
  return r.status === 204 || r.headers.get("Content-Length") === "0";
1604
1858
  }
@@ -1608,17 +1862,22 @@
1608
1862
  /// <reference path="../promise.ts" />
1609
1863
  // namespace Pacem.Net {
1610
1864
  const noop = () => { };
1865
+ /** Error thrown by {@link Http.request} when a request fails outright or completes with a non-2xx status. */
1611
1866
  class StatusCodeError extends Error {
1867
+ /** @param statusCode HTTP status code (`500` for network-level failures). @param statusText Status text / error message. */
1612
1868
  constructor(statusCode, statusText) {
1613
1869
  super(statusText);
1614
1870
  this.statusCode = statusCode;
1615
1871
  }
1872
+ /** The HTTP status code that caused this error. */
1616
1873
  get status() {
1617
1874
  return this.statusCode;
1618
1875
  }
1619
1876
  }
1620
- /** @deprecated */
1877
+ /** Wraps a completed `XMLHttpRequest` produced by {@link Http.request}, exposing its status, headers and body in convenient forms.
1878
+ * @deprecated */
1621
1879
  class Response {
1880
+ /** @param req The completed `XMLHttpRequest`. @param processTime Elapsed request time, in milliseconds. */
1622
1881
  constructor(req, processTime) {
1623
1882
  if (!req)
1624
1883
  return;
@@ -1629,20 +1888,25 @@
1629
1888
  this._allHeadersRaw = req.getAllResponseHeaders();
1630
1889
  this._processTime = processTime;
1631
1890
  }
1891
+ /** Elapsed request time, in milliseconds. */
1632
1892
  get processTime() {
1633
1893
  return this._processTime;
1634
1894
  }
1895
+ /** Response headers, parsed into a name/value map (lazily, on first access). */
1635
1896
  get headers() {
1636
1897
  if (this._headers === undefined && this._allHeadersRaw)
1637
1898
  this._parseHeaders();
1638
1899
  return this._headers;
1639
1900
  }
1901
+ /** The `Content-Length` response header, parsed as a number. */
1640
1902
  get size() {
1641
1903
  return +this.headers['Content-Length'];
1642
1904
  }
1905
+ /** The `Content-Type` response header. */
1643
1906
  get mime() {
1644
1907
  return this.headers['Content-Type'];
1645
1908
  }
1909
+ /** The `Date` response header, parsed into a `Date`. */
1646
1910
  get date() {
1647
1911
  return new Date(Date.parse(this.headers['Date']));
1648
1912
  }
@@ -1658,9 +1922,13 @@
1658
1922
  });
1659
1923
  this._headers = headers;
1660
1924
  }
1925
+ /** HTTP status code. */
1661
1926
  get status() { return this._status; }
1927
+ /** Raw response body as text. */
1662
1928
  get text() { return this._text; }
1929
+ /** Response body, typed per `XMLHttpRequest.responseType` (see {@link type}). */
1663
1930
  get content() { return this._body; }
1931
+ /** The `XMLHttpRequest.responseType` used for this request. */
1664
1932
  get type() { return this._type; }
1665
1933
  /**
1666
1934
  * Short-hand utility for getting or parsing json content (if any).
@@ -1677,7 +1945,11 @@
1677
1945
  }
1678
1946
  }
1679
1947
  }
1680
- /** @deprecated */
1948
+ /**
1949
+ * Legacy `XMLHttpRequest`-based HTTP client, superseded by the standard `fetch` API and {@link Fetcher}.
1950
+ * Kept for backward compatibility.
1951
+ * @deprecated
1952
+ */
1681
1953
  class Http {
1682
1954
  constructor() { }
1683
1955
  /**
@@ -1823,6 +2095,9 @@
1823
2095
  /** Terminating the drag-drop activities. */
1824
2096
  DragDropEventType["End"] = "dragend";
1825
2097
  })(DragDropEventType || (DragDropEventType = {}));
2098
+ /**
2099
+ * Base class shared by the drag & drop event-args classes; wraps a {@link DragDropEventArgs} builder and exposes its common, read-only facets.
2100
+ */
1826
2101
  class DragDropEventArgsBaseClass {
1827
2102
  constructor(_builder) {
1828
2103
  this._builder = _builder;
@@ -1849,32 +2124,46 @@
1849
2124
  return pacemFoundation.Point.add(args.initialDelta, /* included in `initialDelta` for perf sake => { x: this._builder.scroll.left, y: this._builder.scroll.top },*/ pacemFoundation.Point.subtract(args.origin, args.currentPosition));
1850
2125
  }
1851
2126
  }
2127
+ /**
2128
+ * Event args dispatched with the {@link DragDropEventType.Init} event, mutable so listeners can override
2129
+ * the `placeholder` and `data` before the drag actually starts.
2130
+ */
1852
2131
  class DragDropInitEventArgsClass extends DragDropEventArgsBaseClass {
1853
2132
  constructor(_builder) {
1854
2133
  super(_builder);
1855
2134
  this.placeholder = _builder.placeholder;
1856
2135
  this.data = _builder.data;
1857
2136
  }
2137
+ /** Builds a new {@link DragDropInitEventArgsClass} out of a plain {@link DragDropEventArgs} builder. */
1858
2138
  static fromArgs(builder) {
1859
2139
  return new DragDropInitEventArgsClass(Utils.extend({}, builder));
1860
2140
  }
1861
2141
  }
2142
+ /**
2143
+ * Read-only event args dispatched with the drag/drop lifecycle events other than `draginit` (start, drag, drop, over, out, end).
2144
+ */
1862
2145
  class DragDropEventArgsClass extends DragDropEventArgsBaseClass {
1863
2146
  constructor(_builder, _placeholder = _builder.placeholder, _data = _builder.data) {
1864
2147
  super(_builder);
1865
2148
  this._placeholder = _placeholder;
1866
2149
  this._data = _data;
1867
2150
  }
2151
+ /** @readonly Gets the element used as a dragging placeholder. */
1868
2152
  get placeholder() {
1869
2153
  return this._placeholder;
1870
2154
  }
2155
+ /** @readonly Gets the logical payload being dragged. */
1871
2156
  get data() {
1872
2157
  return this._data;
1873
2158
  }
2159
+ /** Builds a new {@link DragDropEventArgsClass} out of a plain {@link DragDropEventArgs} builder. */
1874
2160
  static fromArgs(builder) {
1875
2161
  return new DragDropEventArgsClass(Utils.extend({}, builder));
1876
2162
  }
1877
2163
  }
2164
+ /**
2165
+ * Custom UI event dispatched throughout the drag & drop lifecycle (see {@link DragDropEventType}).
2166
+ */
1878
2167
  class DragDropEvent extends CustomUIEvent {
1879
2168
  constructor(type, args, eventInit, evt) {
1880
2169
  super(type, args, eventInit, evt);
@@ -1883,40 +2172,65 @@
1883
2172
  //}
1884
2173
 
1885
2174
  //namespace Pacem.UI {
2175
+ /**
2176
+ * Enumerates the resize handles a {@link Rescaler} can expose around a rescalable element.
2177
+ */
1886
2178
  var RescaleHandle;
1887
2179
  (function (RescaleHandle) {
2180
+ /** All four sides/corners are enabled. */
1888
2181
  RescaleHandle["All"] = "all";
2182
+ /** The top edge (and its corners) is enabled. */
1889
2183
  RescaleHandle["Top"] = "top";
2184
+ /** The left edge (and its corners) is enabled. */
1890
2185
  RescaleHandle["Left"] = "left";
2186
+ /** The right edge (and its corners) is enabled. */
1891
2187
  RescaleHandle["Right"] = "right";
2188
+ /** The bottom edge (and its corners) is enabled. */
1892
2189
  RescaleHandle["Bottom"] = "bottom";
1893
2190
  })(RescaleHandle || (RescaleHandle = {}));
2191
+ /**
2192
+ * Enumerates the events dispatched throughout the rescale gesture lifecycle.
2193
+ */
1894
2194
  var RescaleEventType;
1895
2195
  (function (RescaleEventType) {
2196
+ /** First rescaling act. */
1896
2197
  RescaleEventType["Start"] = "rescalestart";
2198
+ /** Any rescaling act. */
1897
2199
  RescaleEventType["Rescale"] = "rescale";
2200
+ /** Terminating the rescaling activities. */
1898
2201
  RescaleEventType["End"] = "rescaleend";
1899
2202
  })(RescaleEventType || (RescaleEventType = {}));
2203
+ /**
2204
+ * Read-only event args dispatched with the rescale gesture lifecycle events.
2205
+ */
1900
2206
  class RescaleEventArgsClass {
1901
2207
  constructor(_builder) {
1902
2208
  this._builder = _builder;
1903
2209
  }
2210
+ /** @readonly Gets the current pointer position. */
1904
2211
  get currentPosition() {
1905
2212
  return this._builder.currentPosition;
1906
2213
  }
2214
+ /** @readonly Gets the rectangle the element is being resized to. */
1907
2215
  get targetRect() {
1908
2216
  return this._builder.targetRect;
1909
2217
  }
2218
+ /** @readonly Gets the element being resized. */
1910
2219
  get element() {
1911
2220
  return this._builder.element;
1912
2221
  }
2222
+ /** @readonly Gets the handle being dragged (see {@link RescaleHandle}). */
1913
2223
  get handle() {
1914
2224
  return this._builder.handle;
1915
2225
  }
2226
+ /** Builds a new {@link RescaleEventArgsClass} out of a plain {@link RescaleEventArgs} builder. */
1916
2227
  static fromArgs(builder) {
1917
2228
  return new RescaleEventArgsClass(Utils.extend({}, builder));
1918
2229
  }
1919
2230
  }
2231
+ /**
2232
+ * Custom UI event dispatched throughout the rescale gesture lifecycle (see {@link RescaleEventType}).
2233
+ */
1920
2234
  class RescaleEvent extends CustomUIEvent {
1921
2235
  constructor(type, args, eventInit, evt) {
1922
2236
  super(type, args, eventInit, evt);
@@ -1924,32 +2238,49 @@
1924
2238
  }
1925
2239
  //}
1926
2240
 
2241
+ /**
2242
+ * Enumerates the events dispatched throughout the rotate gesture lifecycle.
2243
+ */
1927
2244
  var RotateEventType;
1928
2245
  (function (RotateEventType) {
2246
+ /** First rotating act. */
1929
2247
  RotateEventType["Start"] = "rotatestart";
2248
+ /** Any rotating act. */
1930
2249
  RotateEventType["Rotate"] = "rotate";
2250
+ /** Terminating the rotating activities. */
1931
2251
  RotateEventType["End"] = "rotateend";
1932
2252
  })(RotateEventType || (RotateEventType = {}));
2253
+ /**
2254
+ * Read-only event args dispatched with the rotate gesture lifecycle events.
2255
+ */
1933
2256
  class RotateEventArgsClass {
1934
2257
  constructor(_builder) {
1935
2258
  this._builder = _builder;
1936
2259
  }
2260
+ /** @readonly Gets the current pointer position. */
1937
2261
  get currentPosition() {
1938
2262
  return this._builder.currentPosition;
1939
2263
  }
2264
+ /** @readonly Gets the current rotation, in radians. */
1940
2265
  get rotation() {
1941
2266
  return this._builder.rotation;
1942
2267
  }
2268
+ /** @readonly Gets the element being rotated. */
1943
2269
  get element() {
1944
2270
  return this._builder.element;
1945
2271
  }
2272
+ /** @readonly Gets the pivot point the element is rotating around. */
1946
2273
  get center() {
1947
2274
  return this._builder.center;
1948
2275
  }
2276
+ /** Builds a new {@link RotateEventArgsClass} out of a plain {@link RotateEventArgs} builder. */
1949
2277
  static fromArgs(builder) {
1950
2278
  return new RotateEventArgsClass(Utils.extend({}, builder));
1951
2279
  }
1952
2280
  }
2281
+ /**
2282
+ * Custom UI event dispatched throughout the rotate gesture lifecycle (see {@link RotateEventType}).
2283
+ */
1953
2284
  class RotateEvent extends CustomUIEvent {
1954
2285
  constructor(type, args, eventInit, evt) {
1955
2286
  super(type, args, eventInit, evt);
@@ -1957,21 +2288,38 @@
1957
2288
  }
1958
2289
  //}
1959
2290
 
2291
+ /**
2292
+ * Enumerates the events dispatched throughout the swipe gesture lifecycle.
2293
+ */
1960
2294
  var SwipeEventType;
1961
2295
  (function (SwipeEventType) {
2296
+ /** Dispatched when the swipe gesture ends (release). */
1962
2297
  SwipeEventType["Swipe"] = "swipe";
2298
+ /** Dispatched while the pointer is dragging the element around. */
1963
2299
  SwipeEventType["Pan"] = "pan";
2300
+ /** Dispatched when the swipe ends and its resolved direction is leftward. */
1964
2301
  SwipeEventType["SwipeLeft"] = "swipeleft";
2302
+ /** Dispatched when the swipe ends and its resolved direction is rightward. */
1965
2303
  SwipeEventType["SwipeRight"] = "swiperight";
2304
+ /** Dispatched when the swipe ends and its resolved direction is upward. */
1966
2305
  SwipeEventType["SwipeUp"] = "swipeup";
2306
+ /** Dispatched when the swipe ends and its resolved direction is downward. */
1967
2307
  SwipeEventType["SwipeDown"] = "swipedown";
1968
2308
  // end of swipe animation
2309
+ /** Dispatched when the snap/bounce-back animation following a swipe completes. */
1969
2310
  SwipeEventType["SwipeAnimationEnd"] = "swipeanimationend";
2311
+ /** Dispatched when the snap/bounce-back animation following a leftward swipe completes. */
1970
2312
  SwipeEventType["SwipeLeftAnimationEnd"] = "swipeleftanimationend";
2313
+ /** Dispatched when the snap/bounce-back animation following a rightward swipe completes. */
1971
2314
  SwipeEventType["SwipeRightAnimationEnd"] = "swiperightanimationend";
2315
+ /** Dispatched when the snap/bounce-back animation following an upward swipe completes. */
1972
2316
  SwipeEventType["SwipeUpAnimationEnd"] = "swipeupanimationend";
2317
+ /** Dispatched when the snap/bounce-back animation following a downward swipe completes. */
1973
2318
  SwipeEventType["SwipeDownAnimationEnd"] = "swipedownanimationend";
1974
2319
  })(SwipeEventType || (SwipeEventType = {}));
2320
+ /**
2321
+ * Read-only event args dispatched with the swipe gesture lifecycle events.
2322
+ */
1975
2323
  class SwipeEventArgsClass {
1976
2324
  constructor(_builder) {
1977
2325
  this._builder = _builder;
@@ -1981,6 +2329,7 @@
1981
2329
  const isVertical = vertical ?? (Math.abs(horizontalspeed) < Math.abs(verticalspeed));
1982
2330
  return isVertical;
1983
2331
  }
2332
+ /** @readonly Gets the resolved swipe direction (`'up'`, `'down'`, `'left'` or `'right'`). */
1984
2333
  get direction() {
1985
2334
  return this.#isVertical
1986
2335
  ? (this._builder.verticalspeed > 0 ? 'down' : 'up')
@@ -2012,13 +2361,18 @@
2012
2361
  const inertia = this._builder.inertia ?? 8;
2013
2362
  return -Math.log(.01 /* v/v0 where v ~ 0 <=> 1% of v0 */) / inertia;
2014
2363
  }
2364
+ /** @readonly Gets the element being swiped. */
2015
2365
  get element() {
2016
2366
  return this._builder.element;
2017
2367
  }
2368
+ /** Builds a new {@link SwipeEventArgsClass} out of a plain {@link SwipeEventArgs} builder. */
2018
2369
  static fromArgs(builder) {
2019
2370
  return new SwipeEventArgsClass(Utils.extend({}, builder));
2020
2371
  }
2021
2372
  }
2373
+ /**
2374
+ * Custom typed event dispatched throughout the swipe gesture lifecycle (see {@link SwipeEventType}).
2375
+ */
2022
2376
  class SwipeEvent extends CustomTypedEvent {
2023
2377
  constructor(type, args, eventInit) {
2024
2378
  super(type, args, eventInit);
@@ -2047,6 +2401,7 @@
2047
2401
  get SwipeEventType () { return SwipeEventType; }
2048
2402
  });
2049
2403
 
2404
+ /** Dispatched by an {@link Iterative} container whenever its `index` changes. */
2050
2405
  class CurrentIndexChangeEvent extends CustomTypedEvent {
2051
2406
  constructor(args) {
2052
2407
  super('currentindexchange', args);
@@ -2055,11 +2410,16 @@
2055
2410
  //}
2056
2411
 
2057
2412
  /// <reference path="events.ts" />
2413
+ /** Runtime value (aliasing the built-in `Function`) usable where a constructor reference is needed as a value, paired with the {@link Type} interface for typing it. */
2058
2414
  const Type = Function;
2059
2415
  // #region CONSTS
2416
+ /** Key used to attach, on an element's constructor, the list of its `@Watch`-decorated (watched) property descriptors. */
2060
2417
  const WATCH_PROPS_VAR = 'pacem:properties';
2418
+ /** Key used to attach, on an element instance, the list of attribute names currently holding a pending (not-yet-evaluable) binding expression. */
2061
2419
  const INSTANCE_BINDINGS_VAR = 'pacem:custom-element:bindings';
2420
+ /** Key used to attach, on a templated node, a reference to the custom element instance ("host") whose template produced it — used to resolve binding expression scope. */
2062
2421
  const INSTANCE_HOST_VAR = 'pacem:custom-element:host';
2422
+ /** Key used to attach, on an element instance, its binding-expression evaluation scope object. */
2063
2423
  const INSTANCE_SCOPE_VAR = 'pacem:custom-element:scope';
2064
2424
  // #endregion
2065
2425
  //}
@@ -2068,37 +2428,66 @@
2068
2428
  var root;
2069
2429
  /** the overall customelement prefix */
2070
2430
  const P = (root = window['Pacem'])?.Configuration?.prefix ?? 'pacem';
2431
+ /** The prefix used for CSS custom properties and classes (e.g. `--{PCSS}-font-main`); configurable independently of the element tag prefix {@link P} via `window.Pacem.Configuration.css`, defaults to {@link P}. */
2071
2432
  const PCSS = root?.Configuration?.css ?? P;
2072
2433
  //}
2073
2434
 
2074
2435
  //namespace Pacem {
2436
+ /** Marker base class for elements that behave like `<template>` (e.g. a custom template-proxy element), so template-detection logic can treat them the same as a native `HTMLTemplateElement`. */
2075
2437
  class TemplateElement extends HTMLElement {
2076
2438
  }
2077
2439
  //}
2078
2440
 
2079
- /// <reference path="expression.ts" />
2080
- /// <reference path="promise.ts" />
2081
- /// <reference path="prefix.ts" />
2082
- /// <reference path="trees/json.ts" />
2083
- /// <reference path="utils.ts" />
2084
2441
  // namespace Pacem {
2085
2442
  const PACEM_BAG = '__pacem__';
2086
2443
  // {{ binding.expression }}
2087
2444
  const bindingPattern = /^\{\{(.|\n)+\}\}$/;
2088
2445
  // TODO: CSP-proof binding (no unsafe-eval)
2089
2446
  // binding syntax example: `{ binding: { source: ^item.property.path, binder: $pacem.func, parameters: [ ^index, 'foo', : host._baz], mode: 'twoway' } }`
2447
+ /**
2448
+ * Static grab-bag of low-level helpers underpinning the {@link CustomElement}/{@link Watch} decorators
2449
+ * and the binding-expression engine: attached-property storage (a per-instance, non-enumerable "bag"
2450
+ * used instead of expando properties), attribute/property name conversion, DOM tree traversal, host/
2451
+ * scope resolution for templated content, and binding-attribute parsing.
2452
+ */
2090
2453
  class CustomElementUtils {
2454
+ /** `true` when the platform's `customElements` registry is the Custom Elements polyfill rather than a native implementation. */
2091
2455
  static get polyfilling() {
2092
2456
  return customElements instanceof window['CustomElementRegistry'];
2093
2457
  }
2458
+ /** Converts a camelCase property name to its kebab-case attribute-name equivalent (e.g. `myProp` → `my-prop`). */
2094
2459
  static camelToKebab(camelCased) {
2095
2460
  return camelCased && camelCased.replace(/([A-Z])/g, '-$1').toLowerCase();
2096
2461
  }
2462
+ /** Converts a kebab-case attribute name to its camelCase property-name equivalent (e.g. `my-prop` → `myProp`). */
2097
2463
  static kebabToCamel(kebabCased) {
2098
2464
  return kebabCased && kebabCased.replace(/(-[a-z])/g, (m) => {
2099
2465
  return m[1].toUpperCase();
2100
2466
  });
2101
2467
  }
2468
+ /** Waits for the specified alement to be ready. */
2469
+ static waitForReady(element) {
2470
+ return new Promise((resolve, reject) => {
2471
+ if (Utils.isNull(element)) {
2472
+ reject('Not found.');
2473
+ }
2474
+ // if (element.isConnected && !(element instanceof PacemEventTarget)){
2475
+ // reject('Invalid element.');
2476
+ // }
2477
+ if (element.isReady) {
2478
+ resolve();
2479
+ }
2480
+ const callback = () => {
2481
+ element.removeEventListener('load', callback);
2482
+ resolve();
2483
+ };
2484
+ element.addEventListener('load', callback);
2485
+ });
2486
+ }
2487
+ /** Waits for the specified element to be ready, then executes the provided callback. */
2488
+ static whenReady(element, callback) {
2489
+ CustomElementUtils.waitForReady(element).then(callback);
2490
+ }
2102
2491
  static getWatchedProperties(target, includeInherited = true) {
2103
2492
  var properties = [];
2104
2493
  var chain = target instanceof HTMLElement ? target.constructor : target;
@@ -2109,9 +2498,16 @@
2109
2498
  } while (includeInherited && (chain = Object.getPrototypeOf(chain)));
2110
2499
  return properties;
2111
2500
  }
2501
+ /** Retrieves a single `@Watch`-decorated property descriptor by name; see {@link getWatchedProperties}. */
2112
2502
  static getWatchedProperty(target, name) {
2113
2503
  return this.getWatchedProperties(target, true).find(p => p.name === name);
2114
2504
  }
2505
+ /**
2506
+ * Loads a `<script>` tag once (deduplicated by `src`, cached via {@link import}), resolving when it fires `load`.
2507
+ * @param src Script URL.
2508
+ * @param integrity Optional Subresource Integrity hash.
2509
+ * @param crossorigin Whether to set `crossorigin` on the tag.
2510
+ */
2115
2511
  static importjs(src, integrity = null, crossorigin = false) {
2116
2512
  var attrs = { 'type': 'text\/javascript', 'src': src };
2117
2513
  if (!Utils.isNullOrEmpty(integrity))
@@ -2120,6 +2516,12 @@
2120
2516
  Utils.extend(attrs, { 'crossorigin': '' });
2121
2517
  return CustomElementUtils.import(src, 'script', attrs, (document.head || document.getElementsByTagName("head")[0]));
2122
2518
  }
2519
+ /**
2520
+ * Loads a `<link rel="stylesheet">` tag once (deduplicated by `src`, cached via {@link import}), resolving when it fires `load`.
2521
+ * @param src Stylesheet URL.
2522
+ * @param integrity Optional Subresource Integrity hash.
2523
+ * @param crossorigin Whether to set `crossorigin="anonymous"` on the tag.
2524
+ */
2123
2525
  static importcss(src, integrity = null, crossorigin = false) {
2124
2526
  var attrs = { 'rel': 'stylesheet', 'href': src };
2125
2527
  if (!Utils.isNullOrEmpty(integrity))
@@ -2128,6 +2530,15 @@
2128
2530
  Utils.extend(attrs, { 'crossorigin': 'anonymous' });
2129
2531
  return CustomElementUtils.import(src, 'link', attrs, (document.head || document.getElementsByTagName("head")[0]));
2130
2532
  }
2533
+ /**
2534
+ * Creates (or reuses an already-present, matching) element of `tagName` with the given attributes and
2535
+ * appends it to the DOM, returning a promise that resolves once it loads (or rejects on error). Results
2536
+ * are cached per `key` (under `Utils.core.imports`) so repeated calls with the same key are a no-op.
2537
+ * @param key Cache/dedupe key (typically the resource URL).
2538
+ * @param tagName Tag name of the element to create (e.g. `'script'`, `'link'`).
2539
+ * @param attrs Attributes to set on the element, also used to build a matching CSS selector to detect a pre-existing element.
2540
+ * @param appendTo Node to append the newly created element to, if none was found. Defaults to `document.body`.
2541
+ */
2131
2542
  static import(key, tagName, attrs, appendTo = document.body) {
2132
2543
  const _p = Utils.core;
2133
2544
  var _imports = _p['imports'] = _p['imports'] || {};
@@ -2157,7 +2568,9 @@
2157
2568
  }
2158
2569
  });
2159
2570
  }
2571
+ /** Theming-related helpers. */
2160
2572
  static { this.Theme = {
2573
+ /** Downloads the web fonts referenced by the current theme's `--{@link PCSS}-font-*` CSS custom properties, resolving once at least one font face is ready (or after a short timeout). */
2161
2574
  importWebFonts() {
2162
2575
  function cleanupQuotes(input) {
2163
2576
  // check if the string is wrapped around quotes to escape ';' chars
@@ -2195,6 +2608,14 @@
2195
2608
  return Promise.all(promises);
2196
2609
  }
2197
2610
  }; }
2611
+ /**
2612
+ * Stores an arbitrary value "attached" to `target` under `name`, in a private, non-enumerable bag
2613
+ * (rather than as a plain expando property) so it doesn't show up in `for...in`/`Object.keys`/JSON
2614
+ * serialization. Setting `value` to `null`/`undefined` removes the entry. See {@link getAttachedPropertyValue}.
2615
+ * @param target Object to attach the value to.
2616
+ * @param name Key under which the value is stored.
2617
+ * @param value Value to store, or `null`/`undefined` to remove the entry.
2618
+ */
2198
2619
  static setAttachedPropertyValue(target, name, value) {
2199
2620
  /*(target[PACEM_BAG] = target[PACEM_BAG] || {})[name] = value;*/
2200
2621
  if (Utils.isNull(target))
@@ -2209,9 +2630,16 @@
2209
2630
  else
2210
2631
  bag[name] = value;
2211
2632
  }
2633
+ /** Removes a value previously stored via {@link setAttachedPropertyValue}. */
2212
2634
  static deleteAttachedPropertyValue(target, name) {
2213
2635
  CustomElementUtils.setAttachedPropertyValue(target, name, undefined);
2214
2636
  }
2637
+ /**
2638
+ * Reads a value previously stored via {@link setAttachedPropertyValue}.
2639
+ * @param target Object the value is attached to.
2640
+ * @param name Key the value is stored under.
2641
+ * @param ensureValue If provided and no value is currently stored, this value is stored and returned (lazy-initialization).
2642
+ */
2215
2643
  static getAttachedPropertyValue(target, name, ensureValue) {
2216
2644
  const propKey = Object.getOwnPropertyDescriptor(target, PACEM_BAG), bag = propKey && propKey.value;
2217
2645
  if (Utils.isNull(bag && bag[name]) && !Utils.isNull(ensureValue)) {
@@ -2257,6 +2685,17 @@
2257
2685
  }
2258
2686
  return { target: { value: ref, name: name }, parent: { value: parent || scope, path: path.substring(0, ndx) }, root: { value: root, property: core } };
2259
2687
  }
2688
+ /**
2689
+ * Writes `value` at the given dotted `path`, rooted at `element` (see {@link resolvePath}), triggering
2690
+ * the appropriate `propertychange` notification. For paths nested more than one level deep (and not
2691
+ * targeting an `HTMLElement`, which fires change notifications autonomously), the whole root property
2692
+ * is cloned, mutated and reassigned so that a `propertychange` fires with meaningful old/new values -
2693
+ * a plain nested assignment wouldn't otherwise be observed. Repeater-bound `item` paths are special-cased
2694
+ * to update the owning {@link Repeater}'s `datasource` array in place.
2695
+ * @param element Root element the path is resolved against.
2696
+ * @param path Dotted path (e.g. `'foo.bar[0].baz'`) to the target property.
2697
+ * @param value New value to assign.
2698
+ */
2260
2699
  static set(element, path, value) {
2261
2700
  var obj = CustomElementUtils.resolvePath(path, element);
2262
2701
  var current = obj.target.value;
@@ -2287,6 +2726,7 @@
2287
2726
  }
2288
2727
  }
2289
2728
  }
2729
+ /** Reads the value at the given dotted `path`, rooted at `element`; see {@link resolvePath}. */
2290
2730
  static get(element, path) {
2291
2731
  var obj = CustomElementUtils.resolvePath(path, element);
2292
2732
  return obj && obj.target && obj.target.value;
@@ -2307,12 +2747,27 @@
2307
2747
  // logFn(`Element "${element.constructor.name}" isn't attached to any context yet.`);
2308
2748
  return retval;
2309
2749
  }
2750
+ /**
2751
+ * Finds the `Document` or `ShadowRoot` that `element` belongs to - used as the root for resolving
2752
+ * scoped binding expressions (e.g. `$document`/`$host` lookups). Falls back to the previously-attached
2753
+ * scope value (see `INSTANCE_SCOPE_VAR`, set on `connectedCallback`) when `element` is currently
2754
+ * disconnected, and to a legacy manual-walk implementation as a last resort (needed under Jasmine tests,
2755
+ * where `element.isConnected` never reports `true`).
2756
+ * @param element Element to resolve the containing document/shadow-root scope for.
2757
+ */
2310
2758
  static findScopeContext(element) {
2311
2759
  let retval = (element.isConnected) ?
2312
2760
  element.getRootNode()
2313
2761
  : CustomElementUtils.getAttachedPropertyValue(element, INSTANCE_SCOPE_VAR);
2314
2762
  return retval ?? /* in Jasmine TESTS `element.isConnected` always returns false (attached to #document-fragment) */ CustomElementUtils._findScopeContextLegacy(element);
2315
2763
  }
2764
+ /**
2765
+ * Walks up from `element` (crossing shadow-root boundaries via the host element) looking for the
2766
+ * first ancestor matching `predicate`.
2767
+ * @param element Element to start the upward search from.
2768
+ * @param predicate Test invoked (as `this`-bound and argument-passed) against each ancestor.
2769
+ * @returns The first matching ancestor, or `undefined` if none matches.
2770
+ */
2316
2771
  static findAncestor(element, predicate) {
2317
2772
  let el = element;
2318
2773
  let retval;
@@ -2326,12 +2781,20 @@
2326
2781
  }
2327
2782
  return retval;
2328
2783
  }
2784
+ /** Finds the nearest ancestor "shell" element - matching `.{@link PCSS}-body` - or falls back to `document.body`; see {@link findAncestor}. */
2329
2785
  static findAncestorShell(element) {
2330
2786
  return CustomElementUtils.findAncestor(element, el => Utils.is(el, `.${PCSS}-body`) || el === document.body);
2331
2787
  }
2788
+ /** Finds the nearest ancestor that is an instance of `ctor`; see {@link findAncestor}. */
2332
2789
  static findAncestorOfType(element, ctor) {
2333
2790
  return CustomElementUtils.findAncestor(element, el => el instanceof ctor);
2334
2791
  }
2792
+ /**
2793
+ * Collects the descendants of `element` matching `predicate`, via a `TreeWalker` over element nodes.
2794
+ * @param element Root element to search from (exclusive - the walker starts on its descendants).
2795
+ * @param predicate Test invoked against each descendant element.
2796
+ * @param firstOnly When `true`, stops and returns as soon as one match is found.
2797
+ */
2335
2798
  static findDescendants(element, predicate, firstOnly = false) {
2336
2799
  const walker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT);
2337
2800
  var retval = [];
@@ -2346,10 +2809,16 @@
2346
2809
  }
2347
2810
  return retval;
2348
2811
  }
2812
+ /** Finds the first descendant of `element` matching `predicate`, or `undefined` if none matches; see {@link findDescendants}. */
2349
2813
  static findFirstDescendant(element, predicate) {
2350
2814
  const any = CustomElementUtils.findDescendants(element, predicate, true);
2351
2815
  return Utils.isNullOrEmpty(any) ? void 0 : any[0];
2352
2816
  }
2817
+ /**
2818
+ * Queries the whole document for elements matching `selector`, additionally filtered by `filter`.
2819
+ * @param selector CSS selector to query for. Defaults to `'[pacem]'` (every Pacem custom element, which all carry that attribute once connected).
2820
+ * @param filter Extra predicate applied to each matched element. Defaults to accepting everything.
2821
+ */
2353
2822
  static findAll(selector = '[pacem]', filter = (e) => true) {
2354
2823
  const retval = [];
2355
2824
  document.querySelectorAll(selector).forEach((e, i, arr) => {
@@ -2411,6 +2880,14 @@
2411
2880
  } while (el != null);
2412
2881
  return retval;
2413
2882
  }
2883
+ /**
2884
+ * Tags every element/document-fragment node inside `template`'s content (that isn't already tagged)
2885
+ * with `host` under `INSTANCE_HOST_VAR`, so that once cloned and inserted into the DOM, binding
2886
+ * expressions in that fragment can resolve back to the custom element instance ("host") that owns
2887
+ * this template. See {@link findHostContext}.
2888
+ * @param host The custom element instance whose template this is.
2889
+ * @param template Template whose content's descendants should be tagged.
2890
+ */
2414
2891
  static assignHostContext(host, template) {
2415
2892
  // navigate through the DOM hierarchy
2416
2893
  const walker = document.createTreeWalker(template.content, NodeFilter.SHOW_ELEMENT + /* traverse templates' content */ NodeFilter.SHOW_DOCUMENT_FRAGMENT);
@@ -2423,6 +2900,13 @@
2423
2900
  }
2424
2901
  }
2425
2902
  }
2903
+ /**
2904
+ * Walks up from `element` looking for the nearest ancestor (inclusive) tagged with a host reference
2905
+ * via {@link assignHostContext}; this is the custom element instance whose template produced `element`,
2906
+ * used to resolve `$host`/scope references in binding expressions. Returns `undefined` (with a console
2907
+ * warning) if `element` is disconnected or isn't part of any templated component.
2908
+ * @param element Element to resolve the owning host for.
2909
+ */
2426
2910
  static findHostContext(element) {
2427
2911
  let el = element;
2428
2912
  let retval;
@@ -2445,6 +2929,7 @@
2445
2929
  logFn(`Element "${element.constructor.name}" isn't a descendant of a templated component.`);
2446
2930
  return retval;
2447
2931
  }
2932
+ /** Tests whether an attribute's raw string value has binding-expression syntax (`{{ ... }}`). */
2448
2933
  static isBindingAttribute(attr) {
2449
2934
  /*if (/^\s*\{\s*binding\s+.*\}\s*$/.test(attr)) {
2450
2935
 
@@ -2464,6 +2949,7 @@
2464
2949
  else*/
2465
2950
  return bindingPattern.test(attr);
2466
2951
  }
2952
+ /** Strips the `{{ }}` delimiters off a binding attribute's raw value, returning the bare expression text. Throws if `attr` isn't a valid binding attribute; see {@link isBindingAttribute}. */
2467
2953
  static extractBindingAttributeExpression(attr) {
2468
2954
  if (CustomElementUtils.isBindingAttribute(attr)) {
2469
2955
  return attr.substr(2, attr.length - 4);
@@ -2472,6 +2958,13 @@
2472
2958
  throw `Invalid attribute: incorrect binding syntax.`;
2473
2959
  }
2474
2960
  }
2961
+ /**
2962
+ * Parses a `{{ ... }}` binding attribute value into an {@link Expression}, recognizing the optional
2963
+ * trailing `, twoway` / `, once` modifier and stamping it onto the expression's dependencies (`twoway`
2964
+ * only applies when the expression has exactly one dependency that itself allows two-way binding).
2965
+ * @param attr Raw binding attribute value, including the `{{ }}` delimiters.
2966
+ * @param element Element the expression is evaluated/bound against (used to resolve scope references).
2967
+ */
2475
2968
  static parseBindingAttribute(attr, element) {
2476
2969
  // loose syntax {{ ... }}
2477
2970
  let expression = CustomElementUtils.extractBindingAttributeExpression(attr);
@@ -2492,6 +2985,14 @@
2492
2985
  });
2493
2986
  return expr;
2494
2987
  }
2988
+ /**
2989
+ * Defines an own property `name` on `o` with `attributes`, unless `o` already has an own property
2990
+ * descriptor for that name (in which case the existing descriptor is returned untouched).
2991
+ * @param o Object to define the property on.
2992
+ * @param name Property name.
2993
+ * @param attributes Property descriptor to apply if the property isn't already defined.
2994
+ * @returns The (possibly pre-existing) property descriptor.
2995
+ */
2495
2996
  static ensureMember(o, name, attributes) {
2496
2997
  let original = Object.getOwnPropertyDescriptor(o, name);
2497
2998
  if (original != undefined)
@@ -2552,6 +3053,7 @@
2552
3053
  const GET_VAL$6 = CustomElementUtils.getAttachedPropertyValue;
2553
3054
  const SET_VAL$5 = CustomElementUtils.setAttachedPropertyValue;
2554
3055
  const REPEATERITEM_PLACEHOLDER = 'pacem:repeater-item';
3056
+ /** Static lookup helpers for locating the {@link RepeaterItem} context a given element belongs to. */
2555
3057
  class Repeater {
2556
3058
  /**
2557
3059
  * Seeks for a PacemRepeaterItem element upwards through the DOM tree, given a starting element and the number of nesting levels.
@@ -2566,7 +3068,22 @@
2566
3068
  return retval;
2567
3069
  }
2568
3070
  }
3071
+ /**
3072
+ * Base class tracking a single rendered repetition of a {@link Repeater}'s template: it associates a
3073
+ * DOM placeholder node with the `item`/`index` scope values that template's binding expressions
3074
+ * evaluate against, and is itself attached to that placeholder (see {@link getRepeaterItem}) so
3075
+ * descendant elements can find their way back to it via {@link findUpwards}.
3076
+ */
2569
3077
  let RepeaterItem$1 = class RepeaterItem {
3078
+ /**
3079
+ * Seeks upwards from `element` (previous siblings, then parent, repeated) for the nearest ancestor
3080
+ * placeholder tagged as a {@link RepeaterItem}, skipping `upLevels` matches before returning one -
3081
+ * this is how deeply-nested repeaters resolve which repetition (of which ancestor repeater) an
3082
+ * expression's `^item`/`^^item`/... token refers to.
3083
+ * @param element Element to start the upward search from.
3084
+ * @param upLevels 0-based number of matching ancestors to skip before returning one (`0` = nearest).
3085
+ * @param logFn Called with a warning message if no match is found and `element` is connected to the DOM.
3086
+ */
2570
3087
  static findUpwards(element, upLevels = 0, logFn = console.warn) {
2571
3088
  if (Utils.isNull(element) || element.localName === 'template' || element instanceof /* template-like element? */ TemplateElement) {
2572
3089
  return null;
@@ -2579,16 +3096,20 @@
2579
3096
  }
2580
3097
  return item;
2581
3098
  }
3099
+ /** Tests whether `node` is the placeholder of some {@link RepeaterItem}. */
2582
3100
  static isRepeaterItem(node) {
2583
3101
  return !Utils.isNull(GET_VAL$6(node, REPEATERITEM_PLACEHOLDER));
2584
3102
  }
3103
+ /** Retrieves the {@link RepeaterItem} attached to `node`, if `node` is a repeater-item placeholder; see {@link isRepeaterItem}. */
2585
3104
  static getRepeaterItem(node) {
2586
3105
  return GET_VAL$6(node, REPEATERITEM_PLACEHOLDER);
2587
3106
  }
3107
+ /** @param _placeholder DOM node (typically a comment) that stands in for this repetition and gets tagged so {@link getRepeaterItem} can retrieve this instance back from it. */
2588
3108
  constructor(_placeholder) {
2589
3109
  this._placeholder = _placeholder;
2590
3110
  SET_VAL$5(_placeholder, REPEATERITEM_PLACEHOLDER, this);
2591
3111
  }
3112
+ /** The DOM placeholder node standing in for this repetition. */
2592
3113
  get placeholder() {
2593
3114
  return this._placeholder;
2594
3115
  }
@@ -2634,32 +3155,53 @@
2634
3155
  // * ...
2635
3156
  // */
2636
3157
  //const purePropertyPathPattern = /^[\w\.\$]+/;
3158
+ /**
3159
+ * A parsed, compiled binding expression (the content of a `{{ ... }}` attribute value). Parsing
3160
+ * (see {@link parse}) rewrites special tokens found in the source text - `:host.`, `^item`/`^^item`/...,
3161
+ * `^index`/`^^index`/..., `#id`, `::hostProp` - into references resolvable at evaluation time, and
3162
+ * records each of them as a {@link PropertyDependency} so the owning element can be notified (via
3163
+ * {@link PropertyChangeEvent}) and re-evaluate the expression whenever a dependency changes - this is
3164
+ * what powers the two-way/live data binding wired up by the {@link CustomElement} decorator.
3165
+ * Expressions with no dependencies are flagged `independent` (effectively a constant) and can be
3166
+ * evaluated immediately without waiting for the DOM/scope to be ready.
3167
+ */
2637
3168
  class Expression {
2638
3169
  constructor() {
2639
3170
  this._pending = false;
2640
3171
  this._independent = false;
2641
3172
  }
3173
+ /** The resolved property dependencies (element + property + path) this expression re-evaluates on change. Empty for {@link independent} expressions. */
2642
3174
  get dependencies() {
2643
3175
  return this._dependencies;
2644
3176
  }
3177
+ /** The compiled function body used by {@link evaluate}/{@link evaluateAsync} (a `return <expr>;` statement, guarded by a try/catch). */
2645
3178
  get functionBody() {
2646
3179
  return this._fnBody;
2647
3180
  }
3181
+ /** The compiled function body used by {@link evaluatePlus} (a bare, non-`return`ing statement, guarded by a try/catch) - suited for expressions run for their side effects, e.g. `on-*` event handlers. */
2648
3182
  get voidBody() {
2649
3183
  return this._voidBody;
2650
3184
  }
3185
+ /**
3186
+ * `true` when this expression couldn't be resolved against a scope yet (the element wasn't connected
3187
+ * to a document/shadow-root at parse time) - a shared, inert placeholder singleton returned by
3188
+ * {@link parse} in that case; evaluating it is a no-op. Callers should re-parse once the element is ready.
3189
+ */
2651
3190
  get pending() {
2652
3191
  return this._pending;
2653
3192
  }
3193
+ /** `true` when the expression has no dependencies (a constant) and can be evaluated immediately, without a resolved scope. */
2654
3194
  get independent() {
2655
3195
  return this._independent;
2656
3196
  }
3197
+ /** Evaluates the expression and returns its result, swallowing any runtime error (returning `undefined`). */
2657
3198
  evaluate() {
2658
3199
  if (!this._fn) {
2659
3200
  this._fn = new Function('$pacem', CONTEXT_PREFIX, this._fnBody);
2660
3201
  }
2661
3202
  return this._fn.apply(null, [Utils.core, this._args]);
2662
3203
  }
3204
+ /** Promise-wrapped variant of {@link evaluate} (resolves synchronously with the same result - kept for call-site uniformity with genuinely async evaluation paths). */
2663
3205
  evaluateAsync() {
2664
3206
  const deferred = DeferPromise.defer();
2665
3207
  if (!this._fn) {
@@ -2668,6 +3210,12 @@
2668
3210
  deferred.resolve(this._fn.apply(null, [Utils.core, this._args]));
2669
3211
  return deferred.promise;
2670
3212
  }
3213
+ /**
3214
+ * Executes the expression for its side effects (using {@link voidBody}, so no value is returned),
3215
+ * with extra named variables merged into scope alongside the expression's own dependencies -
3216
+ * used to expose e.g. `$event` to `on-*` event handler expressions.
3217
+ * @param args Extra name/value pairs made available to the expression, in addition to its resolved dependencies.
3218
+ */
2671
3219
  evaluatePlus(args = {}) {
2672
3220
  if (!this._fn) {
2673
3221
  let argNames = [CONTEXT_PREFIX];
@@ -2692,6 +3240,15 @@
2692
3240
  }
2693
3241
  return Expression._pendingExpression;
2694
3242
  }
3243
+ /**
3244
+ * Parses a binding expression's source text (the bare content of a `{{ ... }}` attribute, without the
3245
+ * delimiters - see {@link CustomElementUtils.extractBindingAttributeExpression}) into an {@link Expression},
3246
+ * resolving its special tokens against `element`'s scope (see {@link CustomElementUtils.findScopeContext}).
3247
+ * Throws if the expression matches the unsafe-code guard (`new`, `window.`, `document.`, `eval(`).
3248
+ * @param expression Bare expression source text.
3249
+ * @param element Element the expression is bound to; provides the scope special tokens (`:host.`, `#id`, `^item`, ...) resolve against.
3250
+ * @returns A constant expression if it has no dependencies; a shared pending placeholder if `element` isn't attached to a scope yet; otherwise a fully resolved expression.
3251
+ */
2695
3252
  static parse(expression, element) {
2696
3253
  var context = CustomElementUtils.findScopeContext(element);
2697
3254
  var args = { '$this': element };
@@ -2822,13 +3379,20 @@
2822
3379
  // }
2823
3380
 
2824
3381
  //namespace Pacem.Logging {
3382
+ /** Severity levels accepted by {@link Logger.log}, and used by {@link PacemEventTarget.log}. */
2825
3383
  var LogLevel;
2826
3384
  (function (LogLevel) {
3385
+ /** Fine-grained diagnostic detail. */
2827
3386
  LogLevel["Trace"] = "trace";
3387
+ /** Development-time diagnostic detail. */
2828
3388
  LogLevel["Debug"] = "debug";
3389
+ /** Recoverable but noteworthy condition. */
2829
3390
  LogLevel["Warn"] = "warn";
3391
+ /** Unrecoverable or unexpected failure. */
2830
3392
  LogLevel["Error"] = "error";
3393
+ /** General informational message. */
2831
3394
  LogLevel["Info"] = "info";
3395
+ /** Generic/default-severity message. */
2832
3396
  LogLevel["Log"] = "log";
2833
3397
  })(LogLevel || (LogLevel = {}));
2834
3398
  //}
@@ -2882,6 +3446,11 @@
2882
3446
  convert: (attr) => pacemFoundation.Rect.parse(attr),
2883
3447
  convertBack: (prop) => `${prop.x || 0} ${prop.y || 0} ${prop.width || 0} ${prop.height || 0}`
2884
3448
  };
3449
+ /**
3450
+ * Built-in {@link PropertyConverter} implementations, keyed by the type they convert to/from. Passed as
3451
+ * the `converter` option of a {@link Watch}-decorated property (e.g. `@Watch({ converter: PropertyConverters.Number })`)
3452
+ * to control how that property's attribute string is parsed and, on change, reflected back.
3453
+ */
2885
3454
  const PropertyConverters /*: { [name: string]: PropertyConverter }*/ = {
2886
3455
  None: NonePropertyConverter,
2887
3456
  String: StringPropertyConverter,
@@ -3029,6 +3598,31 @@
3029
3598
  }
3030
3599
  return promises;
3031
3600
  }
3601
+ /**
3602
+ * Class decorator that turns a class extending `HTMLElement` (typically {@link PacemEventTarget}) into a
3603
+ * fully-fledged Pacem custom element: it registers the tag with the custom elements registry and wraps
3604
+ * the standard `connectedCallback`/`disconnectedCallback`/`attributeChangedCallback`/`propertyChangedCallback`
3605
+ * lifecycle hooks (calling through to any hooks already defined on the class) so that:
3606
+ *
3607
+ * - `observedAttributes` is computed automatically from the class's {@link Watch}-decorated properties
3608
+ * (in kebab-case), merged with any statically-declared `observedAttributes`.
3609
+ * - On first connection, `config.template`/`config.templateUrl` (if provided) is fetched, parsed and
3610
+ * injected — into a Shadow Root when `config.shadow` is `true`, otherwise as light-DOM children,
3611
+ * splicing any pre-existing light-DOM content into a `<pacem-content>` placeholder if present.
3612
+ * - Attribute changes are converted to property values via each watched property's {@link PropertyConverter},
3613
+ * and dispatched as an {@link AttributeChangeEvent}.
3614
+ * - Property changes are dispatched as a {@link PropertyChangeEvent} (unless the property's `@Watch`
3615
+ * config sets `emit: false`) and, when `reflectBack` is enabled, written back onto the corresponding
3616
+ * attribute via the converter's `convertBack`.
3617
+ * - Binding expression attributes (`{{ ... }}`) are parsed and kept live: dependent properties are
3618
+ * re-evaluated whenever one of the expression's upstream properties fires a {@link PropertyChangeEvent}.
3619
+ * - Once the template (and all descendant templated custom elements) have finished rendering, the
3620
+ * `cloak` attribute is removed and `viewActivatedCallback` fires — this is the right place for logic
3621
+ * that depends on the element's full DOM (light or shadow) being in place.
3622
+ *
3623
+ * @param config Tag name, optional native `customElements.define` options, and optional template/templateUrl/shadow settings.
3624
+ * @returns A class decorator to apply to the custom element's class declaration.
3625
+ */
3032
3626
  const CustomElement = (config) => {
3033
3627
  return (target) => {
3034
3628
  // might be already registered
@@ -3363,6 +3957,27 @@
3363
3957
  // #endregion
3364
3958
  // #region WATCH PROPERTIES
3365
3959
  const DefaultPropertyConverter = PropertyConverters.None;
3960
+ /**
3961
+ * Property decorator that turns a plain class field (or accessor) into a Pacem "watched" property:
3962
+ * a property whose changes are detected (via reference/value comparison, see {@link DefaultComparer}),
3963
+ * optionally converted from/to its corresponding attribute string via a {@link PropertyConverter}
3964
+ * (see {@link PropertyConverters}), and notified through `propertyChangedCallback` plus a
3965
+ * {@link PropertyChangeEvent} (unless `config.emit` is `false`).
3966
+ *
3967
+ * Must be paired with the {@link CustomElement} class decorator, which is what actually reads the list
3968
+ * of watched properties (via `WATCH_PROPS_VAR`) to compute `observedAttributes` and wire up attribute/
3969
+ * property change plumbing — `@Watch` alone, on a class not decorated with `@CustomElement`, only sets
3970
+ * up the getter/setter and change notification, with no attribute involvement.
3971
+ *
3972
+ * Array-valued properties are additionally instrumented: their mutating methods (`push`, `pop`, `splice`,
3973
+ * `shift`, `unshift`, `copyWithin`) are patched so in-place mutations also trigger a change notification.
3974
+ *
3975
+ * @param config Optional behavior: `converter` (attribute↔property conversion, default `PropertyConverters.None`),
3976
+ * `emit` (whether to dispatch a {@link PropertyChangeEvent}, default `true`), `debounce` (delay the
3977
+ * change notification, either by a fixed number of milliseconds or `true` for one animation frame),
3978
+ * and `reflectBack` (write the property value back onto the attribute on change, default `false`).
3979
+ * @returns A property decorator to apply to the watched field/accessor.
3980
+ */
3366
3981
  function Watch(config) {
3367
3982
  return (target, prop, descriptor) => {
3368
3983
  var watchableProperties = GET_VAL$5(target.constructor, WATCH_PROPS_VAR, []);
@@ -3481,6 +4096,17 @@
3481
4096
  }
3482
4097
  };
3483
4098
  }
4099
+ /**
4100
+ * Property decorator that turns a class field into a lazily-resolved, cached reference to a descendant
4101
+ * element matching `selector`. Resolution happens on first read (via `shadowRoot.querySelectorAll` when
4102
+ * available, falling back to the element itself), and only nodes whose `INSTANCE_HOST_VAR` points back
4103
+ * at `this` are considered — this keeps the lookup scoped to the current element's own template output,
4104
+ * skipping over descendants that belong to a nested custom element's own template. The cache is reset
4105
+ * whenever the host element reconnects to the DOM (`connectedCallback`, see the {@link CustomElement} decorator).
4106
+ *
4107
+ * @param selector CSS selector identifying the child element to bind to.
4108
+ * @returns A property decorator to apply to the view-child field (read-only; no setter is defined).
4109
+ */
3484
4110
  function ViewChild(selector) {
3485
4111
  return (target, prop, descriptor) => {
3486
4112
  const key = `${prop}_${Utils.uniqueCode()}`;
@@ -3513,6 +4139,15 @@
3513
4139
  }
3514
4140
  // #endregion
3515
4141
  // #region CONCURRENT/DEBOUNCE EXECUTION
4142
+ /**
4143
+ * Method decorator that serializes calls to an async (promise-returning) method on a per-instance basis:
4144
+ * while an invocation is in flight, further calls are queued (their arguments buffered) instead of running
4145
+ * concurrently, and each queued call gets its own promise that resolves/rejects once it eventually runs.
4146
+ * Once the in-flight call settles, the oldest buffered call (if any) is dequeued and executed next.
4147
+ * Methods that don't return a promise-like value are simply invoked synchronously with no queuing.
4148
+ *
4149
+ * @returns A method decorator to apply to an async instance method.
4150
+ */
3516
4151
  function Concurrent() {
3517
4152
  function isPromiseLike(obj) {
3518
4153
  return obj && typeof obj.then === 'function';
@@ -3563,6 +4198,15 @@
3563
4198
  };
3564
4199
  };
3565
4200
  }
4201
+ /**
4202
+ * Method decorator that debounces calls to an instance method: repeated calls within the debounce window
4203
+ * cancel the previously scheduled invocation and reschedule it, so only the last call in a rapid burst
4204
+ * actually runs (with its own arguments), after the window elapses.
4205
+ *
4206
+ * @param msecs Debounce delay in milliseconds, or `true` to debounce to the next animation frame (`requestAnimationFrame`) instead of a fixed delay. Defaults to `50`.
4207
+ * @param keyFactory Computes the per-instance timer key from the method name and call arguments; override to scope debouncing per argument (e.g. debounce separately per id) instead of per method. Defaults to a single shared key per method.
4208
+ * @returns A method decorator to apply to the instance method to debounce.
4209
+ */
3566
4210
  function Debounce(msecs = 50, keyFactory = (key, ...args) => `pacem:debouncer:${key}`) {
3567
4211
  return function (target /* type, actually */, key, descriptor) {
3568
4212
  const originalMethod = descriptor.value;
@@ -3588,6 +4232,16 @@
3588
4232
  }
3589
4233
  };
3590
4234
  }
4235
+ /**
4236
+ * Method decorator that throttles calls to an instance method: the first call in a window runs immediately;
4237
+ * further calls arriving before the window elapses are not dropped but coalesced — only the most recent
4238
+ * set of arguments is remembered and, once the window elapses, one trailing call runs with those arguments
4239
+ * (mirroring a classic "leading + trailing" throttle).
4240
+ *
4241
+ * @param msecs Throttle window in milliseconds, or `true` to use a single animation frame (`requestAnimationFrame`) as the window. Defaults to `50`.
4242
+ * @param keyFactory Computes the per-instance timer key from the method name and call arguments; override to scope throttling per argument instead of per method. Defaults to a single shared key per method.
4243
+ * @returns A method decorator to apply to the instance method to throttle.
4244
+ */
3591
4245
  function Throttle(msecs = 50, keyFactory = (key, ...args) => `pacem:throttler:${key}`) {
3592
4246
  return function (target /* type, actually */, key, descriptor) {
3593
4247
  const originalMethod = descriptor.value;
@@ -3637,6 +4291,14 @@
3637
4291
  }
3638
4292
  }
3639
4293
  };
4294
+ /**
4295
+ * Method decorator that registers a static/instance method as a globally-named {@link TransformFunction},
4296
+ * making it callable by name from template binding expressions (e.g. `{{ ^value | myTransform }}`).
4297
+ * The registration is global (attached under `Utils.core`, dot-segmented by `name`), not per-instance.
4298
+ *
4299
+ * @param name Dot-separated registration path (e.g. `'strings.upper'`); segments before the last create/reuse nested namespaces under `Utils.core`. Defaults to the decorated method's own name when omitted.
4300
+ * @returns A method decorator to apply to the transform function.
4301
+ */
3640
4302
  function Transformer(name) {
3641
4303
  return function (target, key, descriptor) {
3642
4304
  const method = descriptor.value;
@@ -3654,6 +4316,16 @@
3654
4316
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3655
4317
  };
3656
4318
  //namespace Pacem.Components {
4319
+ /**
4320
+ * Base class for (almost) every Pacem custom element. Extends `HTMLElement` with the framework's
4321
+ * common lifecycle/event plumbing: `on-{event-type}` attribute handlers (see {@link emit}), a
4322
+ * {@link disabled} property that suppresses both outgoing (`dispatchEvent`) and incoming
4323
+ * (`emitHandler`) events, an optional {@link logger} sink, and an {@link isReady} flag toggled once
4324
+ * `viewActivatedCallback` has fired (see the {@link CustomElement} decorator for when that happens).
4325
+ * Concrete elements are expected to be decorated with `@CustomElement` and typically override
4326
+ * `propertyChangedCallback`/`viewActivatedCallback`/`connectedCallback`/`disconnectedCallback`,
4327
+ * calling `super.xxxCallback()` first/last as documented on each.
4328
+ */
3657
4329
  class PacemEventTarget extends HTMLElement {
3658
4330
  constructor() {
3659
4331
  super();
@@ -3836,12 +4508,14 @@
3836
4508
  return this._aria.attrs;
3837
4509
  }
3838
4510
  }
4511
+ /** Common base class for Pacem custom elements: adds ARIA support, CSS class/part/style bags, visibility, tab order and behaviors. */
3839
4512
  class PacemElement extends PacemEventTarget {
3840
4513
  constructor(role, aria) {
3841
4514
  super();
3842
4515
  this.#cssBag = [];
3843
4516
  this.#parts = [];
3844
4517
  this._tabIndex = -1;
4518
+ /** Gets or sets the list of behaviors to attach to this element. */
3845
4519
  this.behaviors = [];
3846
4520
  this._aria = new ElementAria(this, role, aria);
3847
4521
  }
@@ -4026,6 +4700,7 @@
4026
4700
  __decorate$H([
4027
4701
  Watch({ emit: false })
4028
4702
  ], PacemElement.prototype, "behaviors", void 0);
4703
+ /** Base class for elements whose (sanitized) inner content is driven by a `content` property, restoring the original markup on disconnect. */
4029
4704
  class PacemContentElement extends PacemElement {
4030
4705
  propertyChangedCallback(name, old, val, first) {
4031
4706
  super.propertyChangedCallback(name, old, val, first);
@@ -4069,11 +4744,13 @@
4069
4744
  __decorate$H([
4070
4745
  Watch({ emit: false, converter: PropertyConverters.String })
4071
4746
  ], PacemContentElement.prototype, "content", void 0);
4747
+ /** {@link PacemContentElement} variant that renders `content` verbatim, without any sanitization. */
4072
4748
  class PacemUnsafeContentElement extends PacemContentElement {
4073
4749
  sanitize(html) {
4074
4750
  return html;
4075
4751
  }
4076
4752
  }
4753
+ /** {@link PacemContentElement} variant that strips out `<script>` blocks (and, for `Node` content, `<script>` elements) before rendering `content`. */
4077
4754
  class PacemSafeContentElement extends PacemContentElement {
4078
4755
  _sanitizeLegacy(html) {
4079
4756
  if (Utils.isNullOrEmpty(html)) {
@@ -4105,6 +4782,7 @@
4105
4782
  }
4106
4783
  //}
4107
4784
 
4785
+ /** Base class for pluggable adapters that drive the focus/navigation behavior of a {@link PacemIterativeElement}. */
4108
4786
  class PacemAdapter extends PacemElement {
4109
4787
  constructor() {
4110
4788
  super(...arguments);
@@ -4233,6 +4911,10 @@
4233
4911
  const current = this._getAvailable();
4234
4912
  return ndx === this._getNextAvailable(current);
4235
4913
  }
4914
+ /**
4915
+ * Sets the master's index to the closest available item to the provided one.
4916
+ * @param ndx Desired index
4917
+ */
4236
4918
  select(ndx) {
4237
4919
  this._element.index = this._getAvailable(ndx);
4238
4920
  }
@@ -4256,6 +4938,7 @@
4256
4938
  return c > 3 && r && Object.defineProperty(target, key, r), r;
4257
4939
  };
4258
4940
  //namespace Pacem.Components {
4941
+ /** Removes itself from the DOM as soon as it gets connected; handy to strip out placeholder markup at runtime. */
4259
4942
  let PacemAnnihilatorElement = class PacemAnnihilatorElement extends HTMLElement {
4260
4943
  constructor() {
4261
4944
  super();
@@ -4276,6 +4959,7 @@
4276
4959
  return c > 3 && r && Object.defineProperty(target, key, r), r;
4277
4960
  };
4278
4961
  //namespace Pacem.Components {
4962
+ /** Warns the user (native `beforeunload` prompt or router-driven confirm dialog) before leaving the page. */
4279
4963
  let PacemBeforeunloadElement = class PacemBeforeunloadElement extends PacemEventTarget {
4280
4964
  constructor() {
4281
4965
  super(...arguments);
@@ -4322,9 +5006,11 @@
4322
5006
  return c > 3 && r && Object.defineProperty(target, key, r), r;
4323
5007
  };
4324
5008
  //namespace Pacem.Components {
5009
+ /** Wraps a {@link BroadcastChannel}, sending/receiving messages to/from other same-origin browsing contexts. */
4325
5010
  let PacemBroadcastChannelProxyElement = class PacemBroadcastChannelProxyElement extends PacemEventTarget {
4326
5011
  constructor() {
4327
5012
  super(...arguments);
5013
+ /** Gets or sets whether to automatically send `message` as soon as it changes (default `true`). */
4328
5014
  this.autosend = true;
4329
5015
  this._messageHandler = (evt) => {
4330
5016
  this.result = evt.data;
@@ -4360,6 +5046,10 @@
4360
5046
  this._disposeChannel();
4361
5047
  super.disconnectedCallback();
4362
5048
  }
5049
+ /**
5050
+ * Posts a message through the channel.
5051
+ * @param message Message to send; defaults to the current `message` property
5052
+ */
4363
5053
  send(message = this.message) {
4364
5054
  if (this.disabled) {
4365
5055
  return;
@@ -4412,6 +5102,7 @@
4412
5102
  return c > 3 && r && Object.defineProperty(target, key, r), r;
4413
5103
  };
4414
5104
  //namespace Pacem.Components {
5105
+ /** Detects the name and version of the current (or a provided) browser user agent. */
4415
5106
  let PacemBrowserDetectElement = class PacemBrowserDetectElement extends PacemEventTarget {
4416
5107
  viewActivatedCallback() {
4417
5108
  super.viewActivatedCallback();
@@ -4425,9 +5116,11 @@
4425
5116
  }
4426
5117
  #browser;
4427
5118
  #version;
5119
+ /** @readonly Gets the detected browser name. */
4428
5120
  get browser() {
4429
5121
  return this.#browser;
4430
5122
  }
5123
+ /** @readonly Gets the detected browser version. */
4431
5124
  get version() {
4432
5125
  return this.#version;
4433
5126
  }
@@ -4454,6 +5147,12 @@
4454
5147
 
4455
5148
  //namespace Pacem {
4456
5149
  const EXPIRATION_FIELD = '_exp';
5150
+ /**
5151
+ * JSON-serializing wrapper around `sessionStorage`/`localStorage` that transparently supports per-key
5152
+ * expiration: values stored with a `duration` are stamped with an expiry timestamp and evicted lazily
5153
+ * (checked on the next {@link getPropertyValue} call for that key, not via a timer). Session storage and
5154
+ * local storage are treated as a single logical namespace - storing a key in one clears any same-named entry in the other.
5155
+ */
4457
5156
  class Storage {
4458
5157
  _getStorage(persistent) {
4459
5158
  return !!persistent ? window.localStorage : window.sessionStorage;
@@ -4488,10 +5187,16 @@
4488
5187
  storage = this._getStorage(!persistent);
4489
5188
  storage.removeItem(name);
4490
5189
  }
5190
+ /**
5191
+ * Retrieves a previously stored value by `name`, checking session storage first, then local storage.
5192
+ * Returns `null` if not found, or if found but past its expiration.
5193
+ * @param name The unique key.
5194
+ */
4491
5195
  getPropertyValue(name) {
4492
5196
  return this._parseValue(this._getStorage(false), name)
4493
5197
  || this._parseValue(this._getStorage(true), name);
4494
5198
  }
5199
+ /** Clears both session and local storage entirely. */
4495
5200
  clear() {
4496
5201
  var storage = this._getStorage(true);
4497
5202
  storage.clear();
@@ -4499,6 +5204,7 @@
4499
5204
  storage.clear();
4500
5205
  }
4501
5206
  ;
5207
+ /** Removes a single entry by `name` from both session and local storage. */
4502
5208
  removeProperty(name) {
4503
5209
  var storage = this._getStorage(true);
4504
5210
  storage.removeItem(name);
@@ -4515,6 +5221,7 @@
4515
5221
  return c > 3 && r && Object.defineProperty(target, key, r), r;
4516
5222
  };
4517
5223
  //namespace Pacem.Components {
5224
+ /** Holds an arbitrary data model, optionally persisting it to local storage and debouncing/throttling change notifications. */
4518
5225
  let PacemDataElement = class PacemDataElement extends PacemEventTarget {
4519
5226
  constructor(storage = new Storage()) {
4520
5227
  super();
@@ -4710,6 +5417,7 @@
4710
5417
  return c > 3 && r && Object.defineProperty(target, key, r), r;
4711
5418
  };
4712
5419
  //namespace Pacem.Components {
5420
+ /** Base class for elements that move their own content to another DOM location, restoring nothing on disconnect. */
4713
5421
  class PacemTransferProxyElement extends PacemEventTarget {
4714
5422
  constructor() {
4715
5423
  super(...arguments);
@@ -4815,6 +5523,7 @@
4815
5523
  return PropertyConverters.Element.convertBack(prop, element);
4816
5524
  }
4817
5525
  };
5526
+ /** Listens for an arbitrary DOM event on a `target` element (or `window`) and re-dispatches it as its own `emit` event. */
4818
5527
  let PacemEventProxyElement = class PacemEventProxyElement extends PacemEventTarget {
4819
5528
  constructor() {
4820
5529
  super(...arguments);
@@ -4887,11 +5596,13 @@
4887
5596
  };
4888
5597
  //namespace Pacem.Components {
4889
5598
  const ABORT_MESSAGE = "New incoming request overrides the ongoing one. Aborting.";
5599
+ /** Declarative wrapper around the `fetch()` API, debouncing/aborting requests as its properties change and exposing the parsed `result`. */
4890
5600
  let PacemFetchElement = class PacemFetchElement extends PacemEventTarget {
4891
5601
  constructor() {
4892
5602
  super(...arguments);
4893
5603
  /** Gets or sets whether to trigger a fetch whenever a significant property has changed (default: true). */
4894
5604
  this.autofetch = true;
5605
+ /** Gets or sets the debounce delay (in milliseconds) applied before auto-triggered fetches (default `100`). */
4895
5606
  this.debounce = 100;
4896
5607
  }
4897
5608
  viewActivatedCallback() {
@@ -5150,6 +5861,7 @@
5150
5861
  super(type, { detail });
5151
5862
  }
5152
5863
  }
5864
+ /** Keeps track of an undo/redo-capable history of an arbitrary state. */
5153
5865
  let PacemHistoryElement = class PacemHistoryElement extends PacemEventTarget {
5154
5866
  #history;
5155
5867
  propertyChangedCallback(name, old, val, first) {
@@ -5183,6 +5895,7 @@
5183
5895
  this.#history = new pacemFoundation.HistoryService(val, this.maxlength);
5184
5896
  }
5185
5897
  }
5898
+ /** Moves the state forward one step, if `canRedo` is `true`. */
5186
5899
  redo() {
5187
5900
  const h = this.#history;
5188
5901
  if (!Utils.isNull(h)) {
@@ -5191,6 +5904,7 @@
5191
5904
  this._synchronize('redo');
5192
5905
  }
5193
5906
  }
5907
+ /** Clears the history stack, keeping only the current state. */
5194
5908
  reset() {
5195
5909
  const h = this.#history;
5196
5910
  if (!Utils.isNull(h)) {
@@ -5199,6 +5913,7 @@
5199
5913
  this._synchronize('reset');
5200
5914
  }
5201
5915
  }
5916
+ /** Moves the state back one step, if `canUndo` is `true`. */
5202
5917
  undo() {
5203
5918
  const h = this.#history;
5204
5919
  if (!Utils.isNull(h)) {
@@ -5240,6 +5955,7 @@
5240
5955
  return c > 3 && r && Object.defineProperty(target, key, r), r;
5241
5956
  };
5242
5957
  //namespace Pacem.Components {
5958
+ /** Sets (or removes) an attribute on the document's root `<html>` element. */
5243
5959
  let PacemHtmlProxyElement = class PacemHtmlProxyElement extends PacemEventTarget {
5244
5960
  constructor() {
5245
5961
  super(...arguments);
@@ -5288,6 +6004,7 @@
5288
6004
  return c > 3 && r && Object.defineProperty(target, key, r), r;
5289
6005
  };
5290
6006
  //namespace Pacem.Components {
6007
+ /** Conditionally shows or clears its own inner content, restoring the original markup whenever `match` becomes truthy again. */
5291
6008
  let PacemIfElement = class PacemIfElement extends HTMLElement {
5292
6009
  #innerHTML;
5293
6010
  propertyChangedCallback(name, old, val, first) {
@@ -5318,6 +6035,7 @@
5318
6035
  return c > 3 && r && Object.defineProperty(target, key, r), r;
5319
6036
  };
5320
6037
  //namespace Pacem.Components {
6038
+ /** Base class for elements that register themselves against an ancestor {@link PacemItemsContainerElement}. */
5321
6039
  class PacemItemElement extends PacemElement {
5322
6040
  get container() {
5323
6041
  return this._container;
@@ -5423,6 +6141,7 @@
5423
6141
  __decorate$u([
5424
6142
  Watch( /* can only be databound or assigned at runtime */)
5425
6143
  ], PacemCrossItemsContainerElement.prototype, "items", void 0);
6144
+ /** Base class for container elements holding a registry of {@link PacemItemElement} children. */
5426
6145
  class PacemItemsContainerElement extends PacemElement {
5427
6146
  constructor(role, aria) {
5428
6147
  super(role, aria);
@@ -5455,6 +6174,7 @@
5455
6174
  return c > 3 && r && Object.defineProperty(target, key, r), r;
5456
6175
  };
5457
6176
  //namespace Pacem.Components {
6177
+ /** Base class for items belonging to a {@link PacemIterativeElement}, forwarding their property changes to the master's `adapter`. */
5458
6178
  class PacemIterableElement extends PacemItemElement {
5459
6179
  /** @overrides */
5460
6180
  findContainer() {
@@ -5470,6 +6190,7 @@
5470
6190
  && iter.adapter.itemPropertyChangedCallback(index, name, old, val, first);
5471
6191
  }
5472
6192
  }
6193
+ /** Base class for container elements whose items are driven by a pluggable {@link PacemAdapter}, tracking a `current` `index`. */
5473
6194
  class PacemIterativeElement extends PacemItemsContainerElement {
5474
6195
  propertyChangedCallback(name, old, val, first) {
5475
6196
  super.propertyChangedCallback(name, old, val, first);
@@ -5527,6 +6248,7 @@
5527
6248
  //namespace Pacem.Components {
5528
6249
  const REMOVE_VALUE = 'false';
5529
6250
  const EMPTY_VALUE = 'true';
6251
+ /** Sets (or removes) an attribute on the closest ancestor shell element, e.g. to drive layout-wide CSS state. */
5530
6252
  let PacemLayoutProxyElement = class PacemLayoutProxyElement extends PacemEventTarget {
5531
6253
  #shell;
5532
6254
  connectedCallback() {
@@ -5580,6 +6302,7 @@
5580
6302
  return c > 3 && r && Object.defineProperty(target, key, r), r;
5581
6303
  };
5582
6304
  //namespace Pacem.Components {
6305
+ /** Creates, updates or removes a `<meta>` element in the document `<head>`, keyed by either `name` or `itemprop`. */
5583
6306
  let PacemMetaProxyElement = class PacemMetaProxyElement extends PacemEventTarget {
5584
6307
  propertyChangedCallback(name, old, val, first) {
5585
6308
  super.propertyChangedCallback(name, old, val, first);
@@ -5641,6 +6364,7 @@
5641
6364
  return c > 3 && r && Object.defineProperty(target, key, r), r;
5642
6365
  };
5643
6366
  //namespace Pacem.Components {
6367
+ /** Tracks the browser's network connectivity (`navigator.onLine`), updating `online` on `online`/`offline` events. */
5644
6368
  let PacemOnlineStatusElement = class PacemOnlineStatusElement extends PacemEventTarget {
5645
6369
  constructor() {
5646
6370
  super(...arguments);
@@ -5683,6 +6407,7 @@
5683
6407
  return c > 3 && r && Object.defineProperty(target, key, r), r;
5684
6408
  };
5685
6409
  //namespace Pacem.Components {
6410
+ /** Plain generic-purpose container element, useful as a databinding/behaviors host wherever a `<div>` would do. */
5686
6411
  let PacemPanelElement = class PacemPanelElement extends PacemSafeContentElement {
5687
6412
  };
5688
6413
  PacemPanelElement = __decorate$p([
@@ -5692,7 +6417,12 @@
5692
6417
 
5693
6418
  /// <reference path="events.ts" />
5694
6419
  //namespace Pacem {
6420
+ /** Event name dispatched to signal a generic, named command invocation; see {@link CommandEvent}. */
5695
6421
  const CommandEventName = 'command';
6422
+ /**
6423
+ * Bubbling, cancelable event representing a generic UI command (e.g. a button's `command`/`command-argument`
6424
+ * attributes), letting ancestor elements handle named actions without wiring a dedicated listener per command.
6425
+ */
5696
6426
  class CommandEvent extends CustomTypedEvent {
5697
6427
  constructor(args) {
5698
6428
  super(CommandEventName, args, { bubbles: true, cancelable: true });
@@ -5707,6 +6437,7 @@
5707
6437
  return c > 3 && r && Object.defineProperty(target, key, r), r;
5708
6438
  };
5709
6439
  //namespace Pacem.Components {
6440
+ /** Redirects consumers (e.g. {@link PacemRepeaterElement}) to an external `<template>` element, firing a `templatechange` event when it changes. */
5710
6441
  let PacemTemplateProxyElement = class PacemTemplateProxyElement extends /*PacemEventTarget*/ /*PacemEventTarget*/ TemplateElement {
5711
6442
  propertyChangedCallback(name, old, val, first) {
5712
6443
  // super.propertyChangedCallback(name, old, val, first);
@@ -5761,6 +6492,8 @@
5761
6492
  }
5762
6493
  //
5763
6494
  /**
6495
+ * Repeats its `<template>` content once per `datasource` item, keeping the rendered items in sync as the datasource changes.
6496
+ * @example
5764
6497
  * <pacem-repeater datasource="[{id:'first', items:['a','b','c']}, ...]">
5765
6498
  * <ol>
5766
6499
  * <li>
@@ -5792,6 +6525,7 @@
5792
6525
  this._databind();
5793
6526
  };
5794
6527
  }
6528
+ /** Removes the rendered item at the given index. */
5795
6529
  removeItem(index) {
5796
6530
  this._removeItems(index, index);
5797
6531
  }
@@ -5820,6 +6554,7 @@
5820
6554
  item.remove();
5821
6555
  }
5822
6556
  }
6557
+ /** Forces a full re-render of the items against the current `datasource`. */
5823
6558
  databind() {
5824
6559
  this._databind();
5825
6560
  }
@@ -6017,6 +6752,7 @@
6017
6752
  }
6018
6753
  }
6019
6754
  const BORDER_BOX = { box: 'border-box' };
6755
+ /** Observes size (and, optionally, position) changes of itself or a `target` element, firing a `resize` event accordingly. */
6020
6756
  let PacemResizeElement = class PacemResizeElement extends PacemEventTarget {
6021
6757
  constructor() {
6022
6758
  super(...arguments);
@@ -6115,6 +6851,7 @@
6115
6851
  this._dispatchResize();
6116
6852
  }
6117
6853
  }
6854
+ /** @readonly Gets the last measured size (and position, if `watchPosition` is set) of the observed target. */
6118
6855
  get currentSize() {
6119
6856
  var args = { height: this._previousHeight, width: this._previousWidth };
6120
6857
  if (this.watchPosition) {
@@ -6152,33 +6889,34 @@
6152
6889
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6153
6890
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6154
6891
  };
6155
- //namespace Pacem {
6156
- const RouterNavigatingEventName = 'navigating';
6157
- const RouterNavigateEventName = 'navigate';
6158
- class RouterNavigateEvent extends CustomTypedEvent {
6159
- constructor(path) {
6160
- super(RouterNavigateEventName, typeof path === 'string' ? { path } : path, { cancelable: false, bubbles: false });
6161
- }
6162
- }
6163
- class RouterNavigatingEvent extends CustomTypedEvent {
6164
- constructor(path) {
6165
- super(RouterNavigatingEventName, path, { cancelable: true, bubbles: false });
6166
- }
6167
- }
6168
- //}
6169
6892
  //namespace Pacem.Components {
6170
6893
  const CHECK_PATTERN = /^([\w\.]:)?\/\/[^\/]+/;
6894
+ /** Client-side router: parses/generates paths against a template and drives the browser History API. */
6171
6895
  let PacemRouterElement = class PacemRouterElement extends PacemEventTarget {
6172
6896
  constructor() {
6173
6897
  super(...arguments);
6898
+ this._onScroll = (e) => {
6899
+ const scrollRestoration = this.scrollRestoration ?? true;
6900
+ if (!scrollRestoration) {
6901
+ return;
6902
+ }
6903
+ const y = Math.floor(Utils.scrollTop);
6904
+ window.history.replaceState(Utils.extend({}, window.history.state, { $scrollY: y }), document.title);
6905
+ };
6174
6906
  this._onPopState = (evt) => {
6175
6907
  if (!Utils.isNull(evt.state) && !this.#cancelingNavigation) {
6176
- this.path = evt.state.$path;
6908
+ const state = evt.state;
6909
+ // navigate and scroll, just in case
6910
+ this.path = state.$path;
6177
6911
  }
6178
6912
  };
6179
6913
  }
6180
6914
  #cancelingNavigation;
6181
6915
  #template;
6916
+ /**
6917
+ * Merges the provided partial state into the current one and returns the resulting parsed {@link RouterState}, without navigating.
6918
+ * @param state Piece of new state to be merged
6919
+ */
6182
6920
  parseState(state = {}) {
6183
6921
  const path = this._stringifyMergedState(state);
6184
6922
  const segments = this._segmentateUrl(path);
@@ -6225,14 +6963,18 @@
6225
6963
  // exiting
6226
6964
  return;
6227
6965
  }
6966
+ const newState = !poppingState
6967
+ ? Utils.extend({ $scrollY: 0 }, state)
6968
+ : Utils.extend({ $scrollY: 0 }, window.history.state /* < may include `$scrollY` */, state);
6228
6969
  // this one actually does trigger the navigation in the outer world
6229
- this.state = state;
6970
+ // 'cause it is usually bound to a PacemViewElement 'url'
6971
+ this.state = newState;
6972
+ window.history.scrollRestoration = (this.scrollRestoration ?? true) ? 'manual' : 'auto';
6230
6973
  if (poppingState) {
6231
- window.history.scrollRestoration = 'manual';
6232
- window.history.replaceState(state, title);
6974
+ window.history.replaceState(newState, document.title);
6233
6975
  }
6234
6976
  else {
6235
- window.history.pushState(state, title, path);
6977
+ window.history.pushState(newState, title, path);
6236
6978
  }
6237
6979
  if (!Utils.isNullOrEmpty(title)) {
6238
6980
  document.title = title;
@@ -6257,6 +6999,7 @@
6257
6999
  connectedCallback() {
6258
7000
  super.connectedCallback();
6259
7001
  window.addEventListener('popstate', this._onPopState, false);
7002
+ document.addEventListener('scroll', this._onScroll, false);
6260
7003
  }
6261
7004
  viewActivatedCallback() {
6262
7005
  super.viewActivatedCallback();
@@ -6266,6 +7009,7 @@
6266
7009
  }
6267
7010
  }
6268
7011
  disconnectedCallback() {
7012
+ document.removeEventListener('scroll', this._onScroll, false);
6269
7013
  window.removeEventListener('popstate', this._onPopState, false);
6270
7014
  super.disconnectedCallback();
6271
7015
  }
@@ -6320,6 +7064,9 @@
6320
7064
  __decorate$l([
6321
7065
  Watch({ emit: false, converter: PropertyConverters.String })
6322
7066
  ], PacemRouterElement.prototype, "path", void 0);
7067
+ __decorate$l([
7068
+ Watch({ emit: false, reflectBack: true, converter: PropertyConverters.Boolean })
7069
+ ], PacemRouterElement.prototype, "scrollRestoration", void 0);
6323
7070
  PacemRouterElement = __decorate$l([
6324
7071
  CustomElement({ tagName: P + '-router' })
6325
7072
  ], PacemRouterElement);
@@ -6429,6 +7176,7 @@
6429
7176
  }
6430
7177
  return output;
6431
7178
  }
7179
+ /** Registers a service worker and manages its (optional) Push API subscription. */
6432
7180
  let PacemServiceWorkerProxyElement = class PacemServiceWorkerProxyElement extends PacemEventTarget {
6433
7181
  viewActivatedCallback() {
6434
7182
  super.viewActivatedCallback();
@@ -6481,6 +7229,10 @@
6481
7229
  }
6482
7230
  });
6483
7231
  }
7232
+ /**
7233
+ * Unsubscribes from push notifications.
7234
+ * @param subscription Subscription to cancel; defaults to the current `pushSubscription`
7235
+ */
6484
7236
  unsubscribe(subscription = this.pushSubscription) {
6485
7237
  return new Promise((resolve, reject) => {
6486
7238
  if (!Utils.isNull(subscription)) {
@@ -6498,6 +7250,10 @@
6498
7250
  }
6499
7251
  });
6500
7252
  }
7253
+ /**
7254
+ * Subscribes to push notifications through the registered service worker.
7255
+ * @param publicKey VAPID public key (base64url or raw bytes); defaults to `publicKey`
7256
+ */
6501
7257
  subscribe(publicKey = this.publicKey) {
6502
7258
  return new Promise((resolve, reject) => {
6503
7259
  if (typeof publicKey === 'string') {
@@ -6585,6 +7341,7 @@
6585
7341
  || (/^arrow/.test(key) && (piece === key.substr(5)));
6586
7342
  }
6587
7343
  const KeyboardShortcutExecuteEventName = "execute";
7344
+ /** Listens for a keyboard shortcut (optionally chorded, e.g. `"ctrl+k, s"`) on a target and fires an `execute` event when matched. */
6588
7345
  let PacemShortcutElement = class PacemShortcutElement extends PacemEventTarget {
6589
7346
  constructor() {
6590
7347
  super(...arguments);
@@ -6642,6 +7399,7 @@
6642
7399
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6643
7400
  };
6644
7401
  //namespace Pacem.Components {
7402
+ /** Sets its own `textContent` to the `text` property, escaping any markup. */
6645
7403
  let PacemSpanElement = class PacemSpanElement extends PacemSafeContentElement {
6646
7404
  propertyChangedCallback(name, old, val, first) {
6647
7405
  super.propertyChangedCallback(name, old, val, first);
@@ -6671,6 +7429,7 @@
6671
7429
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6672
7430
  };
6673
7431
  //namespace Pacem.Components {
7432
+ /** Injects a `<style>` element into the document `<head>`, populated either inline (`cssText`) or by fetching `src`. */
6674
7433
  let PacemStyleProxyElement = class PacemStyleProxyElement extends PacemEventTarget {
6675
7434
  propertyChangedCallback(name, old, val, first) {
6676
7435
  super.propertyChangedCallback(name, old, val, first);
@@ -6771,6 +7530,7 @@
6771
7530
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6772
7531
  };
6773
7532
  //namespace Pacem.Components {
7533
+ /** Renders the `text` property as its own plain-text content, replacing any existing child markup. */
6774
7534
  let PacemTextElement = class PacemTextElement extends HTMLElement {
6775
7535
  constructor() {
6776
7536
  super();
@@ -6802,6 +7562,7 @@
6802
7562
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6803
7563
  };
6804
7564
  //namespace Pacem.Components {
7565
+ /** Fires a `tick` event on a regular interval, as long as it's enabled and `interval` is greater than zero. */
6805
7566
  let PacemTimerElement = class PacemTimerElement extends PacemEventTarget {
6806
7567
  constructor() {
6807
7568
  super();
@@ -6848,6 +7609,7 @@
6848
7609
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6849
7610
  };
6850
7611
  //namespace Pacem.Components {
7612
+ /** Sets `document.title` to `value` whenever it changes. */
6851
7613
  let PacemTitleProxyElement = class PacemTitleProxyElement extends PacemEventTarget {
6852
7614
  propertyChangedCallback(name, old, val, first) {
6853
7615
  super.propertyChangedCallback(name, old, val, first);
@@ -6883,10 +7645,12 @@
6883
7645
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6884
7646
  };
6885
7647
  //namespace Pacem.Components {
7648
+ /** Animates a numeric `value` from `from` to `to` over `duration`, dispatching animation lifecycle events along the way. */
6886
7649
  let PacemTweenElement = class PacemTweenElement extends PacemEventTarget {
6887
7650
  constructor(_tweener = new TweenService()) {
6888
7651
  super();
6889
7652
  this._tweener = _tweener;
7653
+ /** Gets or sets the animation duration, in milliseconds (default `1000`). */
6890
7654
  this.duration = 1000;
6891
7655
  }
6892
7656
  propertyChangedCallback(name, old, val, first) {
@@ -6896,6 +7660,7 @@
6896
7660
  this._animate();
6897
7661
  }
6898
7662
  }
7663
+ /** Starts the animation programmatically and returns a promise resolved once it completes. */
6899
7664
  run() {
6900
7665
  return this._animate();
6901
7666
  }
@@ -7045,9 +7810,11 @@
7045
7810
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7046
7811
  };
7047
7812
  //namespace Pacem.Components {
7813
+ /** Wraps a {@link Worker}, sending/receiving messages to/from a web worker script. */
7048
7814
  let PacemWebWorkerProxyElement = class PacemWebWorkerProxyElement extends PacemEventTarget {
7049
7815
  constructor() {
7050
7816
  super(...arguments);
7817
+ /** Gets or sets whether to automatically send `message` as soon as it changes (default `true`). */
7051
7818
  this.autosend = true;
7052
7819
  this._messageHandler = (evt) => {
7053
7820
  this.result = evt.data;
@@ -7083,6 +7850,10 @@
7083
7850
  this._disposeWorker();
7084
7851
  super.disconnectedCallback();
7085
7852
  }
7853
+ /**
7854
+ * Posts a message to the worker.
7855
+ * @param message Message to send; defaults to the current `message` property
7856
+ */
7086
7857
  send(message = this.message) {
7087
7858
  if (this.disabled) {
7088
7859
  return;
@@ -7128,8 +7899,16 @@
7128
7899
  //}
7129
7900
 
7130
7901
  //namespace Pacem.Behaviors{
7902
+ /**
7903
+ * Base class for the "behavior" custom elements (drag & drop, swipe, rotate, rescale, ...) that attach
7904
+ * gesture-driven functionality to a set of registered elements without rendering anything of their own.
7905
+ */
7131
7906
  class PacemBehavior extends PacemEventTarget {
7132
7907
  #items = new WeakSet();
7908
+ /**
7909
+ * Registers an element with this behavior, decorating it if it wasn't already registered.
7910
+ * @param element Element to register.
7911
+ */
7133
7912
  register(element) {
7134
7913
  var container = this.#items;
7135
7914
  if (!container.has(element)) {
@@ -7137,6 +7916,10 @@
7137
7916
  this.decorate(element);
7138
7917
  }
7139
7918
  }
7919
+ /**
7920
+ * Unregisters a previously registered element, undecorating it.
7921
+ * @param element Element to unregister.
7922
+ */
7140
7923
  unregister(element) {
7141
7924
  var container = this.#items;
7142
7925
  if (container.has(element)) {
@@ -7144,6 +7927,7 @@
7144
7927
  container.delete(element);
7145
7928
  }
7146
7929
  }
7930
+ /** @readonly Determines whether the given element is currently registered with this behavior. */
7147
7931
  has(element) {
7148
7932
  return this.#items.has(element);
7149
7933
  }
@@ -7565,7 +8349,8 @@
7565
8349
  }
7566
8350
  }
7567
8351
  /**
7568
- * Pacem Drag & Drop element adapter.
8352
+ * Pacem Drag & Drop element adapter: implements {@link DragDropper} on top of {@link PacemBehavior} to make
8353
+ * registered elements draggable and, optionally, sortable/droppable onto {@link dropTargets}.
7569
8354
  */
7570
8355
  let PacemDragDropElement = class PacemDragDropElement extends PacemBehavior {
7571
8356
  constructor() {
@@ -7629,23 +8414,28 @@
7629
8414
  /** Gets or sets the drag mode ("self", "alias", "copy"). */
7630
8415
  this.mode = DragDataMode.Self;
7631
8416
  }
8417
+ /** Wires up the `mousedown`/`touchstart` listeners that arm the drag gesture on the given element. */
7632
8418
  decorate(element) {
7633
8419
  const options = { capture: false, passive: false };
7634
8420
  // TODO: add special effects starting the drag process after a while (timeout) the element is pressed.
7635
8421
  element.addEventListener('mousedown', this._startHandler, false);
7636
8422
  element.addEventListener('touchstart', this._startHandler, options);
7637
8423
  }
8424
+ /** Removes the listeners set up by {@link decorate}. */
7638
8425
  undecorate(element) {
7639
8426
  const options = { capture: false, passive: false };
7640
8427
  element.removeEventListener('mousedown', this._startHandler, false);
7641
8428
  element.removeEventListener('touchstart', this._startHandler, options);
7642
8429
  }
8430
+ /** Registers a listener for a {@link DragDropEventType} lifecycle event. */
7643
8431
  addEventListener(type, listener, useCapture) {
7644
8432
  super.addEventListener(type, listener, useCapture);
7645
8433
  }
8434
+ /** Unregisters a listener previously added for a {@link DragDropEventType} lifecycle event. */
7646
8435
  removeEventListener(type, listener, useCapture) {
7647
8436
  super.removeEventListener(type, listener, useCapture);
7648
8437
  }
8438
+ /** Dispatches a {@link DragDropEvent}, clearing internal per-element bookkeeping once the drag ends. */
7649
8439
  dispatchEvent(evt) {
7650
8440
  if (evt.type === DragDropEventType.End) {
7651
8441
  DEL_VAL$3(evt.detail.element, MOUSE_DOWN$2);
@@ -7828,6 +8618,10 @@
7828
8618
  const RESCALE_FRAME = 'pacem:rescale:frame';
7829
8619
  const MOUSE_DOWN$1 = 'pacem:rescale:origin';
7830
8620
  const DELEGATE$1 = 'pacem:rescale:delegate';
8621
+ /**
8622
+ * Pacem Rescale element adapter: implements {@link Rescaler} on top of {@link PacemBehavior}, decorating
8623
+ * registered elements with draggable resize handles (see {@link RescaleHandle}).
8624
+ */
7831
8625
  let PacemRescaleElement = class PacemRescaleElement extends PacemBehavior {
7832
8626
  constructor() {
7833
8627
  super(...arguments);
@@ -7855,11 +8649,13 @@
7855
8649
  /* logging */ (level, message, category) => this.log.apply(this, [level, message, category])));
7856
8650
  };
7857
8651
  }
8652
+ /** Adds the resize-handle frame (see {@link RescaleHandle}) around the given element. */
7858
8653
  decorate(element) {
7859
8654
  const el = element; getComputedStyle(el);
7860
8655
  Utils.addClass(el, PCSS + '-rescalable');
7861
8656
  this._setFrame(el);
7862
8657
  }
8658
+ /** Removes the resize-handle frame set up by {@link decorate}. */
7863
8659
  undecorate(element) {
7864
8660
  const el = element;
7865
8661
  Utils.removeClass(el, PCSS + '-rescalable');
@@ -8043,6 +8839,10 @@
8043
8839
  return x;
8044
8840
  }
8045
8841
  }
8842
+ /**
8843
+ * Pacem Rotate element adapter: implements {@link Rotator} on top of {@link PacemBehavior} to make
8844
+ * registered elements rotatable around a pivot point via mouse/touch drag.
8845
+ */
8046
8846
  let PacemRotateElement = class PacemRotateElement extends PacemBehavior {
8047
8847
  constructor() {
8048
8848
  super(...arguments);
@@ -8080,6 +8880,7 @@
8080
8880
  /* logging */ (level, message, category) => this.log.apply(this, [level, message, category])));
8081
8881
  };
8082
8882
  }
8883
+ /** Wires up the `mousedown`/`touchstart` listeners that arm the rotate gesture on the given element. */
8083
8884
  decorate(element) {
8084
8885
  const el = element;
8085
8886
  Utils.addClass(el, PCSS + '-rotatable');
@@ -8087,6 +8888,7 @@
8087
8888
  element.addEventListener('mousedown', this._startHandler, false);
8088
8889
  element.addEventListener('touchstart', this._startHandler, options);
8089
8890
  }
8891
+ /** Removes the listeners set up by {@link decorate}. */
8090
8892
  undecorate(element) {
8091
8893
  const el = element;
8092
8894
  Utils.removeClass(el, PCSS + '-rotatable');
@@ -8318,6 +9120,10 @@
8318
9120
  window.removeEventListener('pointerup', this._endHandler);
8319
9121
  }
8320
9122
  }
9123
+ /**
9124
+ * Pacem Swipe element adapter: implements {@link Swiper} on top of {@link PacemBehavior} to make
9125
+ * registered elements draggable along one axis, with snap points and fling/bounce-back detection.
9126
+ */
8321
9127
  let PacemSwipeElement = class PacemSwipeElement extends PacemBehavior {
8322
9128
  constructor() {
8323
9129
  super(...arguments);
@@ -8370,6 +9176,7 @@
8370
9176
  this._undo(el);
8371
9177
  };
8372
9178
  }
9179
+ /** Wires up the `pointerdown` listener that arms the swipe gesture on the given element. */
8373
9180
  decorate(element) {
8374
9181
  // https://docs.microsoft.com/en-us/microsoft-edge/dev-guide/dom/pointer-events
8375
9182
  if (element instanceof HTMLElement || element instanceof SVGElement) {
@@ -8377,6 +9184,7 @@
8377
9184
  }
8378
9185
  element.addEventListener('pointerdown', this._prepareHandler, false);
8379
9186
  }
9187
+ /** Removes the listener set up by {@link decorate}. */
8380
9188
  undecorate(element) {
8381
9189
  if (element instanceof HTMLElement || element instanceof SVGElement) {
8382
9190
  Utils.removeClass(element, PCSS + '-swipe');
@@ -8441,6 +9249,10 @@
8441
9249
  const EasingConverter = {
8442
9250
  convert: (attr) => Easings[attr] ?? Easings.linear
8443
9251
  };
9252
+ /**
9253
+ * Abstract base class for the `@CustomElement` animation items (color/number/point animations) that can be
9254
+ * hosted within a {@link PacemStoryboardElement}. Implements {@link Timeline}.
9255
+ */
8444
9256
  class AnimationElement extends PacemItemElement {
8445
9257
  }
8446
9258
  __decorate$5([
@@ -8464,15 +9276,21 @@
8464
9276
  __decorate$5([
8465
9277
  Watch({ emit: false, converter: PropertyConverters.String })
8466
9278
  ], AnimationElement.prototype, "direction", void 0);
9279
+ /**
9280
+ * Base class for animation elements that interpolate their `from`/`to` value via {@link TweenService}.
9281
+ * Concrete subclasses only need to supply {@link tweenInterpolationCallback} to map normalized progress to a value of type `T`.
9282
+ */
8467
9283
  class TweenAnimationElement extends AnimationElement {
8468
9284
  constructor(_tweener = new TweenService()) {
8469
9285
  super();
8470
9286
  this._tweener = _tweener;
8471
9287
  }
9288
+ /** @readonly Gets the {@link TweenService} instance driving this animation. */
8472
9289
  get tweener() {
8473
9290
  return this._tweener;
8474
9291
  }
8475
9292
  #cancelToken = false;
9293
+ /** Starts (or restarts) the tween and returns a promise resolved once it completes. */
8476
9294
  startAnimation() {
8477
9295
  this.#cancelToken = false;
8478
9296
  return new Promise((resolve, _) => {
@@ -8485,6 +9303,7 @@
8485
9303
  .then(resolve);
8486
9304
  });
8487
9305
  }
9306
+ /** Cancels the running tween. */
8488
9307
  cancelAnimation() {
8489
9308
  this.#cancelToken = true;
8490
9309
  }
@@ -8499,6 +9318,7 @@
8499
9318
  //namespace Pacem.Components {
8500
9319
  const DEFAULT_FROM$2 = { h: 0, l: 0, s: 0.5, a: 1 };
8501
9320
  const DEFAULT_TO$2 = { h: 0, l: 1, s: 0.5, a: 1 };
9321
+ /** Animates a CSS color `target[property]` from `from` to `to` (interpolated in HSLA space) over `duration`. */
8502
9322
  let PacemColorAnimationElement = class PacemColorAnimationElement extends TweenAnimationElement {
8503
9323
  propertyChangedCallback(name, old, val, first) {
8504
9324
  super.propertyChangedCallback(name, old, val, first);
@@ -8542,6 +9362,7 @@
8542
9362
  _parseColor(clr) {
8543
9363
  return pacemFoundation.Colors.hsl(pacemFoundation.Colors.parse(clr));
8544
9364
  }
9365
+ /** @inheritdoc */
8545
9366
  tweenInterpolationCallback(time, progress) {
8546
9367
  const from = this.#from, to = this.#to;
8547
9368
  const hsla = {
@@ -8572,7 +9393,9 @@
8572
9393
  //namespace Pacem.Components {
8573
9394
  const DEFAULT_FROM$1 = 0;
8574
9395
  const DEFAULT_TO$1 = 1;
9396
+ /** Animates a numeric `target[property]` from `from` to `to` over `duration`. */
8575
9397
  let PacemNumberAnimationElement = class PacemNumberAnimationElement extends TweenAnimationElement {
9398
+ /** @inheritdoc */
8576
9399
  tweenInterpolationCallback(time, progress) {
8577
9400
  const to = this.to ?? DEFAULT_TO$1, from = this.from ?? DEFAULT_FROM$1;
8578
9401
  return (to - from) * progress + from;
@@ -8597,7 +9420,9 @@
8597
9420
  //namespace Pacem.Components {
8598
9421
  const DEFAULT_FROM = { x: 0, y: 0 };
8599
9422
  const DEFAULT_TO = { x: 1, y: 1 };
9423
+ /** Animates a {@link Point} `target[property]` from `from` to `to` over `duration`. */
8600
9424
  let PacemPointAnimationElement = class PacemPointAnimationElement extends TweenAnimationElement {
9425
+ /** @inheritdoc */
8601
9426
  tweenInterpolationCallback(time, progress) {
8602
9427
  const to = this.to ?? DEFAULT_TO, from = this.from ?? DEFAULT_FROM;
8603
9428
  return {
@@ -8624,7 +9449,12 @@
8624
9449
  return c > 3 && r && Object.defineProperty(target, key, r), r;
8625
9450
  };
8626
9451
  //namespace Pacem.Components {
9452
+ /**
9453
+ * Groups one or more {@link Timeline}s (either {@link AnimationElement} child items or an explicit
9454
+ * `datasource`) and starts/cancels them together, optionally on view activation via `autostart`.
9455
+ */
8627
9456
  let PacemStoryboardElement = class PacemStoryboardElement extends PacemItemsContainerElement {
9457
+ /** @inheritdoc */
8628
9458
  validate(item) {
8629
9459
  return item instanceof AnimationElement;
8630
9460
  }
@@ -8665,12 +9495,14 @@
8665
9495
  }
8666
9496
  return Promise.all(promises);
8667
9497
  }
9498
+ /** Cancels every running {@link Timeline} in this storyboard. */
8668
9499
  cancelAnimation() {
8669
9500
  const ds = this._adaptedDatasource || [];
8670
9501
  for (let timeline of ds) {
8671
9502
  timeline.cancelAnimation();
8672
9503
  }
8673
9504
  }
9505
+ /** Starts (or restarts) every {@link Timeline} in this storyboard. */
8674
9506
  startAnimation() {
8675
9507
  return this._animate(true);
8676
9508
  }
@@ -8762,10 +9594,6 @@
8762
9594
  RepeaterItemRemoveEventName: RepeaterItemRemoveEventName,
8763
9595
  ResizeEvent: ResizeEvent,
8764
9596
  ResizeEventName: ResizeEventName,
8765
- RouterNavigateEvent: RouterNavigateEvent,
8766
- RouterNavigateEventName: RouterNavigateEventName,
8767
- RouterNavigatingEvent: RouterNavigatingEvent,
8768
- RouterNavigatingEventName: RouterNavigatingEventName,
8769
9597
  ScrollEvent: ScrollEvent,
8770
9598
  ScrollEventName: ScrollEventName,
8771
9599
  StateEvent: StateEvent,
@@ -8784,13 +9612,16 @@
8784
9612
  });
8785
9613
 
8786
9614
  //namespace Pacem {
9615
+ /** Framework-wide default settings. */
8787
9616
  const Defaults = {
8788
9617
  USE_SHADOW_ROOT: /*'attachShadow' in Element.prototype &&*/ false /* <- wait until html-imports */
8789
9618
  };
8790
9619
  //}
8791
9620
 
8792
9621
  //namespace Pacem.RegularExpressions {
9622
+ /** A pattern that can never match any string (`/a^/`); useful as a safe no-op default for optional matcher parameters. */
8793
9623
  const EMPTY_MATCHER = /a^/;
9624
+ /** Static regular-expression helpers. */
8794
9625
  class Regex {
8795
9626
  /**
8796
9627
  * Splits an input string into segments based on a matching pattern.
@@ -8846,7 +9677,21 @@
8846
9677
  cssRemove: cssRemove ?? 'fill-red-container',
8847
9678
  };
8848
9679
  }
9680
+ /**
9681
+ * The framework's built-in library of template-expression transform functions. Each static method here
9682
+ * is registered, via the {@link Transformer} decorator, under `Utils.core` (mostly by its own method
9683
+ * name - see each method's `@Transformer(...)` name override where present) so it becomes callable by
9684
+ * name from binding expressions (e.g. `{{ ^value | size }}`). Not part of the module's exported surface -
9685
+ * consumers use these by their registered transform name, not by importing this class.
9686
+ */
8849
9687
  class Transforms {
9688
+ /**
9689
+ * Wraps every case-insensitive occurrence of each whitespace-separated token of `query` found in `src`
9690
+ * (skipping matches inside HTML tags) with a `<span class="{css}">` highlight wrapper.
9691
+ * @param src Source HTML/text to search within.
9692
+ * @param query Whitespace-separated search terms.
9693
+ * @param css CSS class applied to the highlight `<span>`. Defaults to `{PCSS}-highlight`.
9694
+ */
8850
9695
  static highlight(src, query, css = PCSS + '-highlight') {
8851
9696
  if (!query || !src)
8852
9697
  return src;
@@ -8889,9 +9734,11 @@
8889
9734
  return acc;
8890
9735
  }, '');
8891
9736
  }
9737
+ /** Left-pads `src` (stringified) to `length` characters using `pad`; see {@link Utils.leftPad}. */
8892
9738
  static padleft(src, length, pad) {
8893
9739
  return Utils.leftPad('' + src, length, pad);
8894
9740
  }
9741
+ /** Formats a byte count `src` as a human-readable size string (`B`/`kB`/`MB`/`GB`), or `'-'` if not a positive number. */
8895
9742
  static size(src) {
8896
9743
  // TODO: use logarithms
8897
9744
  if (!(src > 0))
@@ -8904,12 +9751,25 @@
8904
9751
  return (src / 1_048_576).toFixed(2) + ' MB';
8905
9752
  return (src / 1_073_741_824).toFixed(2) + ' GB';
8906
9753
  }
9754
+ /**
9755
+ * Formats a decimal-degrees number `src` as degrees/minutes/seconds (e.g. `41° 53' 24"`).
9756
+ * @param src Decimal degrees value (sign indicates direction).
9757
+ * @param degSeparator Text following the degrees component.
9758
+ * @param minSeparator Text following the minutes component.
9759
+ * @param secSeparator Text following the seconds component.
9760
+ */
8907
9761
  static decToDeg(src, degSeparator = '° ', minSeparator = '\' ', secSeparator = '"') {
8908
9762
  const sign = Math.sign(src);
8909
9763
  src = Math.abs(src);
8910
9764
  const deg = Math.floor(src), min0 = (src - deg) * 60, min = Math.floor(min0), sec0 = (min0 - min) * 60, sec = Math.floor(sec0);
8911
9765
  return (sign < 0 ? '-' : '') + deg + degSeparator + min + minSeparator + sec + secSeparator;
8912
9766
  }
9767
+ /**
9768
+ * Formats a date-like value `src` (parsed via {@link Utils.parseDate}) as text.
9769
+ * @param src Date, timestamp, or parseable date string.
9770
+ * @param format Either a named shorthand (`'iso'`, `'isodate'`, `'localdate'`, `'time'`/`'localtime'`, `'full'`, or the default locale date format) or an `Intl.DateTimeFormatOptions` object.
9771
+ * @param culture BCP 47 locale to format with. Defaults to the browser's language.
9772
+ */
8913
9773
  static date(src, format, culture) {
8914
9774
  var date = Utils.parseDate(src), lang = culture || navigator.language;
8915
9775
  if (Utils.isNull(format) || typeof format === 'string') {
@@ -8937,6 +9797,13 @@
8937
9797
  return date.toLocaleString(culture, format);
8938
9798
  }
8939
9799
  }
9800
+ /**
9801
+ * Formats the elapsed time between `start` and `end`.
9802
+ * @param start Start date-like value.
9803
+ * @param end End date-like value.
9804
+ * @param format Either an `Intl.DateTimeFormatOptions` (formatted as a UTC duration, optionally sign-prefixed via `sign: true`), or omitted for the legacy `"{d}d {h}h {m}m {s}s {ms}ms"` textual format.
9805
+ * @param culture BCP 47 locale to format with (only used with `Intl.DateTimeFormatOptions`). Defaults to the browser's language.
9806
+ */
8940
9807
  static timespan(start, end, format, culture) {
8941
9808
  const startDate = Utils.parseDate(start), endDate = Utils.parseDate(end), span = endDate.valueOf() - startDate.valueOf(), sign = span < 0 ? '-' : '', elapsed = Math.abs(span);
8942
9809
  if (typeof format === 'object') {
@@ -8947,18 +9814,26 @@
8947
9814
  const msecsPerDay = 86400000, msecsPerHr = 3600000, msecsPerMin = 60000, days = Math.floor(elapsed / msecsPerDay), hrs = Math.floor((elapsed % msecsPerDay) / msecsPerHr), mins = Math.floor((elapsed % msecsPerHr) / msecsPerMin), secs = Math.floor((elapsed % msecsPerMin) / 1000), msecs = Math.floor(elapsed % 1000);
8948
9815
  return `${sign}${days}d ${hrs}h ${mins}m ${secs}s ${msecs}ms`;
8949
9816
  }
9817
+ /** Formats `src` as a currency amount using `Intl.NumberFormat`. @param currency ISO 4217 currency code. @param culture BCP 47 locale. Defaults to the browser's language. */
8950
9818
  static currency(src, currency, culture) {
8951
9819
  return new Intl.NumberFormat(culture ?? navigator.language, { style: 'currency', currency: currency }).format(src);
8952
9820
  }
9821
+ /**
9822
+ * Formats `src` as a number using `Intl.NumberFormat`.
9823
+ * @param formatOrCulture Either a BCP 47 locale string, or `Intl.NumberFormatOptions` (in which case `culture` supplies the locale).
9824
+ * @param culture BCP 47 locale, used only when `formatOrCulture` is a format-options object. Defaults to the browser's language.
9825
+ */
8953
9826
  static number(src, formatOrCulture, culture) {
8954
9827
  if (typeof formatOrCulture === 'string') {
8955
9828
  return new Intl.NumberFormat(formatOrCulture || navigator.language).format(src);
8956
9829
  }
8957
9830
  return new Intl.NumberFormat(culture ?? navigator.language, formatOrCulture).format(src);
8958
9831
  }
9832
+ /** Filters `src` with `filter`; a thin wrapper over `Array.prototype.filter` usable from template expressions. */
8959
9833
  static filter(src, filter) {
8960
9834
  return src.filter(filter);
8961
9835
  }
9836
+ /** Sorts `src` in place (ascending, via `>`/`<` comparison), optionally by a property path when items are objects. @param prop Property name to sort by; omit to compare items directly. */
8962
9837
  static orderby(src, prop) {
8963
9838
  return src.sort((a, b) => {
8964
9839
  if (!Utils.isNullOrEmpty(prop)) {
@@ -8969,31 +9844,39 @@
8969
9844
  });
8970
9845
  }
8971
9846
  // #region RegExp
9847
+ /** Tests `input` against a `RegExp` built from `pattern`/`flags`. Registered as `regex.isMatch`. */
8972
9848
  static isMatch(input, pattern, flags) {
8973
9849
  return new RegExp(pattern, flags).test(input);
8974
9850
  }
8975
9851
  // #endregion
8976
9852
  // #region shortcuts from 'Utils'
9853
+ /** Template-expression shortcut for {@link Utils.isEmpty}. */
8977
9854
  static isEmpty(obj) {
8978
9855
  return Utils.isEmpty(obj);
8979
9856
  }
9857
+ /** Template-expression shortcut for {@link Utils.isNull}. */
8980
9858
  static isNull(obj) {
8981
9859
  return Utils.isNull(obj);
8982
9860
  }
9861
+ /** Template-expression shortcut for {@link Utils.isNullOrEmpty}. */
8983
9862
  static isNullOrEmpty(obj) {
8984
9863
  return Utils.isNullOrEmpty(obj);
8985
9864
  }
9865
+ /** Reads a CSS custom property's value off the document; see {@link Utils.Css.getVariableValue}. Registered as `cssvar`. */
8986
9866
  static getCssVariable(name) {
8987
9867
  return Utils.Css.getVariableValue(name);
8988
9868
  }
9869
+ /** Reads a query-string parameter's value off the current URL; see {@link Utils.URIs.parseQuery}. Registered as `querystring`. */
8989
9870
  static getQuerystring(name) {
8990
9871
  return Utils.URIs.parseQuery()[name];
8991
9872
  }
8992
9873
  // #endregion
8993
9874
  // #region shortcuts from 'CustomElementUtils'
9875
+ /** Template-expression shortcut for {@link CustomElementUtils.Theme}'s `importWebFonts`. */
8994
9876
  static importThemeWebFonts() {
8995
9877
  return CustomElementUtils.Theme.importWebFonts();
8996
9878
  }
9879
+ /** Template-expression shortcut for {@link CustomElementUtils.findHostContext}. Registered as `host`. */
8997
9880
  static findHostContext(element) {
8998
9881
  return CustomElementUtils.findHostContext(element);
8999
9882
  }
@@ -9097,6 +9980,10 @@
9097
9980
  Regex: Regex,
9098
9981
  Repeater: Repeater,
9099
9982
  RepeaterItem: RepeaterItem$1,
9983
+ RouterNavigateEvent: RouterNavigateEvent,
9984
+ RouterNavigateEventName: RouterNavigateEventName,
9985
+ RouterNavigatingEvent: RouterNavigatingEvent,
9986
+ RouterNavigatingEventName: RouterNavigatingEventName,
9100
9987
  Storage: Storage,
9101
9988
  TemplateElement: TemplateElement,
9102
9989
  Throttle: Throttle,