motion 11.13.5 → 11.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,45 +1,45 @@
1
1
  
2
2
  lib/index.js → dist/motion.dev.js...
3
- created dist/motion.dev.js in 690ms
3
+ created dist/motion.dev.js in 710ms
4
4
  
5
5
  lib/index.js → dist/motion.js...
6
- created dist/motion.js in 781ms
6
+ created dist/motion.js in 865ms
7
7
  
8
8
  lib/index.js → dist/cjs...
9
- created dist/cjs in 251ms
9
+ created dist/cjs in 224ms
10
10
  
11
11
  lib/react-client.js → dist/cjs...
12
- created dist/cjs in 436ms
12
+ created dist/cjs in 340ms
13
13
  
14
14
  lib/react.js → dist/cjs...
15
- created dist/cjs in 33ms
15
+ created dist/cjs in 16ms
16
16
  
17
17
  lib/mini.js → dist/cjs...
18
- created dist/cjs in 94ms
18
+ created dist/cjs in 62ms
19
19
  
20
20
  lib/react-mini.js → dist/cjs...
21
- created dist/cjs in 28ms
21
+ created dist/cjs in 26ms
22
22
  
23
23
  lib/react-m.js → dist/cjs...
24
- created dist/cjs in 78ms
24
+ created dist/cjs in 70ms
25
25
  
26
26
  lib/index.js, lib/mini.js, lib/react.js, lib/react-mini.js, lib/react-client.js, lib/react-m.js → dist/es...
27
- created dist/es in 578ms
27
+ created dist/es in 593ms
28
28
  
29
29
  types/index.d.ts → dist/index.d.ts...
30
- created dist/index.d.ts in 9ms
30
+ created dist/index.d.ts in 10ms
31
31
  
32
32
  types/react.d.ts → dist/react.d.ts...
33
- created dist/react.d.ts in 6ms
33
+ created dist/react.d.ts in 5ms
34
34
  
35
35
  types/react-mini.d.ts → dist/react-mini.d.ts...
36
- created dist/react-mini.d.ts in 3ms
36
+ created dist/react-mini.d.ts in 5ms
37
37
  
38
38
  types/react-m.d.ts → dist/react-m.d.ts...
39
- created dist/react-m.d.ts in 4ms
39
+ created dist/react-m.d.ts in 3ms
40
40
  
41
41
  types/mini.d.ts → dist/mini.d.ts...
42
- created dist/mini.d.ts in 3ms
42
+ created dist/mini.d.ts in 1ms
43
43
  
44
44
  types/react-client.d.ts → dist/react-client.d.ts...
45
- created dist/react-client.d.ts in 3ms
45
+ created dist/react-client.d.ts in 2ms
package/dist/cjs/index.js CHANGED
@@ -19,6 +19,14 @@ if (process.env.NODE_ENV !== "production") {
19
19
  };
20
20
  }
21
21
 
22
+ const isDragging = {
23
+ x: false,
24
+ y: false,
25
+ };
26
+ function isDragActive() {
27
+ return isDragging.y;
28
+ }
29
+
22
30
  function resolveElements(elementOrSelector, scope, selectorCache) {
23
31
  var _a;
24
32
  if (elementOrSelector instanceof Element) {
@@ -40,14 +48,6 @@ function resolveElements(elementOrSelector, scope, selectorCache) {
40
48
  return Array.from(elementOrSelector);
41
49
  }
42
50
 
43
- const isDragging = {
44
- x: false,
45
- y: false,
46
- };
47
- function isDragActive() {
48
- return isDragging.y;
49
- }
50
-
51
51
  function addUniqueItem(arr, item) {
52
52
  if (arr.indexOf(item) === -1)
53
53
  arr.push(item);
@@ -323,7 +323,7 @@ class MotionValue {
323
323
  * This will be replaced by the build step with the latest version number.
324
324
  * When MotionValues are provided to motion components, warn if versions are mixed.
325
325
  */
326
- this.version = "11.13.5";
326
+ this.version = "11.14.0";
327
327
  /**
328
328
  * Tracks whether this value can output a velocity. Currently this is only true
329
329
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -4160,7 +4160,7 @@ function updateMotionValuesFromProps(element, next, prev) {
4160
4160
  * and warn against mismatches.
4161
4161
  */
4162
4162
  if (process.env.NODE_ENV === "development") {
4163
- warnOnce(nextValue.version === "11.13.5", `Attempting to mix Motion versions ${nextValue.version} with 11.13.5 may not work as expected.`);
4163
+ warnOnce(nextValue.version === "11.14.0", `Attempting to mix Motion versions ${nextValue.version} with 11.14.0 may not work as expected.`);
4164
4164
  }
4165
4165
  }
4166
4166
  else if (isMotionValue(prevValue)) {
@@ -3348,7 +3348,7 @@ class MotionValue {
3348
3348
  * This will be replaced by the build step with the latest version number.
3349
3349
  * When MotionValues are provided to motion components, warn if versions are mixed.
3350
3350
  */
3351
- this.version = "11.13.5";
3351
+ this.version = "11.14.0";
3352
3352
  /**
3353
3353
  * Tracks whether this value can output a velocity. Currently this is only true
3354
3354
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -4254,6 +4254,14 @@ const animations = {
4254
4254
  },
4255
4255
  };
4256
4256
 
4257
+ const isDragging = {
4258
+ x: false,
4259
+ y: false,
4260
+ };
4261
+ function isDragActive() {
4262
+ return isDragging.x || isDragging.y;
4263
+ }
4264
+
4257
4265
  function resolveElements(elementOrSelector, scope, selectorCache) {
4258
4266
  var _a;
4259
4267
  if (elementOrSelector instanceof Element) {
@@ -4275,19 +4283,23 @@ function resolveElements(elementOrSelector, scope, selectorCache) {
4275
4283
  return Array.from(elementOrSelector);
4276
4284
  }
4277
4285
 
4278
- const isDragging = {
4279
- x: false,
4280
- y: false,
4281
- };
4282
- function isDragActive() {
4283
- return isDragging.x || isDragging.y;
4286
+ function setupGesture(elementOrSelector, options) {
4287
+ const elements = resolveElements(elementOrSelector);
4288
+ const gestureAbortController = new AbortController();
4289
+ const eventOptions = {
4290
+ passive: true,
4291
+ ...options,
4292
+ signal: gestureAbortController.signal,
4293
+ };
4294
+ const cancel = () => gestureAbortController.abort();
4295
+ return [elements, eventOptions, cancel];
4284
4296
  }
4285
4297
 
4286
4298
  /**
4287
4299
  * Filter out events that are not pointer events, or are triggering
4288
4300
  * while a Motion gesture is active.
4289
4301
  */
4290
- function filterEvents(callback) {
4302
+ function filterEvents$1(callback) {
4291
4303
  return (event) => {
4292
4304
  if (event.pointerType === "touch" || isDragActive())
4293
4305
  return;
@@ -4302,27 +4314,172 @@ function filterEvents(callback) {
4302
4314
  * @public
4303
4315
  */
4304
4316
  function hover(elementOrSelector, onHoverStart, options = {}) {
4305
- const gestureAbortController = new AbortController();
4306
- const eventOptions = {
4307
- passive: true,
4308
- ...options,
4309
- signal: gestureAbortController.signal,
4310
- };
4311
- const onPointerEnter = filterEvents((enterEvent) => {
4317
+ const [elements, eventOptions, cancel] = setupGesture(elementOrSelector, options);
4318
+ const onPointerEnter = filterEvents$1((enterEvent) => {
4312
4319
  const { target } = enterEvent;
4313
4320
  const onHoverEnd = onHoverStart(enterEvent);
4314
4321
  if (!onHoverEnd || !target)
4315
4322
  return;
4316
- const onPointerLeave = filterEvents((leaveEvent) => {
4323
+ const onPointerLeave = filterEvents$1((leaveEvent) => {
4317
4324
  onHoverEnd(leaveEvent);
4318
4325
  target.removeEventListener("pointerleave", onPointerLeave);
4319
4326
  });
4320
4327
  target.addEventListener("pointerleave", onPointerLeave, eventOptions);
4321
4328
  });
4322
- resolveElements(elementOrSelector).forEach((element) => {
4329
+ elements.forEach((element) => {
4323
4330
  element.addEventListener("pointerenter", onPointerEnter, eventOptions);
4324
4331
  });
4325
- return () => gestureAbortController.abort();
4332
+ return cancel;
4333
+ }
4334
+
4335
+ const isPrimaryPointer = (event) => {
4336
+ if (event.pointerType === "mouse") {
4337
+ return typeof event.button !== "number" || event.button <= 0;
4338
+ }
4339
+ else {
4340
+ /**
4341
+ * isPrimary is true for all mice buttons, whereas every touch point
4342
+ * is regarded as its own input. So subsequent concurrent touch points
4343
+ * will be false.
4344
+ *
4345
+ * Specifically match against false here as incomplete versions of
4346
+ * PointerEvents in very old browser might have it set as undefined.
4347
+ */
4348
+ return event.isPrimary !== false;
4349
+ }
4350
+ };
4351
+
4352
+ const isPressing = new WeakSet();
4353
+
4354
+ /**
4355
+ * Filter out events that are not "Enter" keys.
4356
+ */
4357
+ function filterEvents(callback) {
4358
+ return (event) => {
4359
+ if (event.key !== "Enter")
4360
+ return;
4361
+ callback(event);
4362
+ };
4363
+ }
4364
+ function firePointerEvent(target, type) {
4365
+ target.dispatchEvent(new PointerEvent("pointer" + type, { isPrimary: true, bubbles: true }));
4366
+ }
4367
+ const enableKeyboardPress = (focusEvent, eventOptions) => {
4368
+ const element = focusEvent.currentTarget;
4369
+ if (!element)
4370
+ return;
4371
+ const handleKeydown = filterEvents(() => {
4372
+ if (isPressing.has(element))
4373
+ return;
4374
+ firePointerEvent(element, "down");
4375
+ const handleKeyup = filterEvents(() => {
4376
+ firePointerEvent(element, "up");
4377
+ });
4378
+ const handleBlur = () => firePointerEvent(element, "cancel");
4379
+ element.addEventListener("keyup", handleKeyup, eventOptions);
4380
+ element.addEventListener("blur", handleBlur, eventOptions);
4381
+ });
4382
+ element.addEventListener("keydown", handleKeydown, eventOptions);
4383
+ /**
4384
+ * Add an event listener that fires on blur to remove the keydown events.
4385
+ */
4386
+ element.addEventListener("blur", () => element.removeEventListener("keydown", handleKeydown), eventOptions);
4387
+ };
4388
+
4389
+ const focusableElements = new Set([
4390
+ "BUTTON",
4391
+ "INPUT",
4392
+ "SELECT",
4393
+ "TEXTAREA",
4394
+ "A",
4395
+ ]);
4396
+ function isElementKeyboardAccessible(element) {
4397
+ return focusableElements.has(element.tagName) || element.tabIndex !== -1;
4398
+ }
4399
+
4400
+ /**
4401
+ * Recursively traverse up the tree to check whether the provided child node
4402
+ * is the parent or a descendant of it.
4403
+ *
4404
+ * @param parent - Element to find
4405
+ * @param child - Element to test against parent
4406
+ */
4407
+ const isNodeOrChild = (parent, child) => {
4408
+ if (!child) {
4409
+ return false;
4410
+ }
4411
+ else if (parent === child) {
4412
+ return true;
4413
+ }
4414
+ else {
4415
+ return isNodeOrChild(parent, child.parentElement);
4416
+ }
4417
+ };
4418
+
4419
+ /**
4420
+ * Filter out events that are not primary pointer events, or are triggering
4421
+ * while a Motion gesture is active.
4422
+ */
4423
+ function isValidPressEvent(event) {
4424
+ return isPrimaryPointer(event) && !isDragActive();
4425
+ }
4426
+ /**
4427
+ * Create a press gesture.
4428
+ *
4429
+ * Press is different to `"pointerdown"`, `"pointerup"` in that it
4430
+ * automatically filters out secondary pointer events like right
4431
+ * click and multitouch.
4432
+ *
4433
+ * It also adds accessibility support for keyboards, where
4434
+ * an element with a press gesture will receive focus and
4435
+ * trigger on Enter `"keydown"` and `"keyup"` events.
4436
+ *
4437
+ * This is different to a browser's `"click"` event, which does
4438
+ * respond to keyboards but only for the `"click"` itself, rather
4439
+ * than the press start and end/cancel. The element also needs
4440
+ * to be focusable for this to work, whereas a press gesture will
4441
+ * make an element focusable by default.
4442
+ *
4443
+ * @public
4444
+ */
4445
+ function press(elementOrSelector, onPressStart, options = {}) {
4446
+ const [elements, eventOptions, cancelEvents] = setupGesture(elementOrSelector, options);
4447
+ const startPress = (startEvent) => {
4448
+ const element = startEvent.currentTarget;
4449
+ if (!isValidPressEvent(startEvent) || isPressing.has(element))
4450
+ return;
4451
+ isPressing.add(element);
4452
+ const onPressEnd = onPressStart(startEvent);
4453
+ const onPointerEnd = (endEvent, success) => {
4454
+ window.removeEventListener("pointerup", onPointerUp);
4455
+ window.removeEventListener("pointercancel", onPointerCancel);
4456
+ if (!isValidPressEvent(endEvent) || !isPressing.has(element)) {
4457
+ return;
4458
+ }
4459
+ isPressing.delete(element);
4460
+ if (onPressEnd) {
4461
+ onPressEnd(endEvent, { success });
4462
+ }
4463
+ };
4464
+ const onPointerUp = (upEvent) => {
4465
+ onPointerEnd(upEvent, options.useGlobalTarget ||
4466
+ isNodeOrChild(element, upEvent.target));
4467
+ };
4468
+ const onPointerCancel = (cancelEvent) => {
4469
+ onPointerEnd(cancelEvent, false);
4470
+ };
4471
+ window.addEventListener("pointerup", onPointerUp, eventOptions);
4472
+ window.addEventListener("pointercancel", onPointerCancel, eventOptions);
4473
+ };
4474
+ elements.forEach((element) => {
4475
+ if (!isElementKeyboardAccessible(element)) {
4476
+ element.tabIndex = 0;
4477
+ }
4478
+ const target = options.useGlobalTarget ? window : element;
4479
+ target.addEventListener("pointerdown", startPress, eventOptions);
4480
+ element.addEventListener("focus", (event) => enableKeyboardPress(event, eventOptions), eventOptions);
4481
+ });
4482
+ return cancelEvents;
4326
4483
  }
4327
4484
 
4328
4485
  function setDragLock(axis) {
@@ -4350,23 +4507,6 @@ function setDragLock(axis) {
4350
4507
  }
4351
4508
  }
4352
4509
 
4353
- const isPrimaryPointer = (event) => {
4354
- if (event.pointerType === "mouse") {
4355
- return typeof event.button !== "number" || event.button <= 0;
4356
- }
4357
- else {
4358
- /**
4359
- * isPrimary is true for all mice buttons, whereas every touch point
4360
- * is regarded as its own input. So subsequent concurrent touch points
4361
- * will be false.
4362
- *
4363
- * Specifically match against false here as incomplete versions of
4364
- * PointerEvents in very old browser might have it set as undefined.
4365
- */
4366
- return event.isPrimary !== false;
4367
- }
4368
- };
4369
-
4370
4510
  function extractEventInfo(event) {
4371
4511
  return {
4372
4512
  point: {
@@ -4400,7 +4540,7 @@ function distance2D(a, b) {
4400
4540
  * @internal
4401
4541
  */
4402
4542
  class PanSession {
4403
- constructor(event, handlers, { transformPagePoint, contextWindow, dragSnapToOrigin = false } = {}) {
4543
+ constructor(event, handlers, { transformPagePoint, contextWindow, dragSnapToOrigin = false, } = {}) {
4404
4544
  /**
4405
4545
  * @internal
4406
4546
  */
@@ -7787,142 +7927,28 @@ class FocusGesture extends Feature {
7787
7927
  unmount() { }
7788
7928
  }
7789
7929
 
7790
- /**
7791
- * Recursively traverse up the tree to check whether the provided child node
7792
- * is the parent or a descendant of it.
7793
- *
7794
- * @param parent - Element to find
7795
- * @param child - Element to test against parent
7796
- */
7797
- const isNodeOrChild = (parent, child) => {
7798
- if (!child) {
7799
- return false;
7800
- }
7801
- else if (parent === child) {
7802
- return true;
7930
+ function handlePressEvent(node, event, lifecycle) {
7931
+ const { props } = node;
7932
+ if (node.animationState && props.whileTap) {
7933
+ node.animationState.setActive("whileTap", lifecycle === "Start");
7803
7934
  }
7804
- else {
7805
- return isNodeOrChild(parent, child.parentElement);
7935
+ const eventName = ("onTap" + (lifecycle === "End" ? "" : lifecycle));
7936
+ const callback = props[eventName];
7937
+ if (callback) {
7938
+ frame.postRender(() => callback(event, extractEventInfo(event)));
7806
7939
  }
7807
- };
7808
-
7809
- function fireSyntheticPointerEvent(name, handler) {
7810
- if (!handler)
7811
- return;
7812
- const syntheticPointerEvent = new PointerEvent("pointer" + name);
7813
- handler(syntheticPointerEvent, extractEventInfo(syntheticPointerEvent));
7814
7940
  }
7815
7941
  class PressGesture extends Feature {
7816
- constructor() {
7817
- super(...arguments);
7818
- this.removeStartListeners = noop;
7819
- this.removeEndListeners = noop;
7820
- this.removeAccessibleListeners = noop;
7821
- this.startPointerPress = (startEvent, startInfo) => {
7822
- if (this.isPressing)
7823
- return;
7824
- this.removeEndListeners();
7825
- const props = this.node.getProps();
7826
- const endPointerPress = (endEvent, endInfo) => {
7827
- if (!this.checkPressEnd())
7828
- return;
7829
- const { onTap, onTapCancel, globalTapTarget } = this.node.getProps();
7830
- /**
7831
- * We only count this as a tap gesture if the event.target is the same
7832
- * as, or a child of, this component's element
7833
- */
7834
- const handler = !globalTapTarget &&
7835
- !isNodeOrChild(this.node.current, endEvent.target)
7836
- ? onTapCancel
7837
- : onTap;
7838
- if (handler) {
7839
- frame.update(() => handler(endEvent, endInfo));
7840
- }
7841
- };
7842
- const removePointerUpListener = addPointerEvent(window, "pointerup", endPointerPress, {
7843
- passive: !(props.onTap || props["onPointerUp"]),
7844
- });
7845
- const removePointerCancelListener = addPointerEvent(window, "pointercancel", (cancelEvent, cancelInfo) => this.cancelPress(cancelEvent, cancelInfo), {
7846
- passive: !(props.onTapCancel ||
7847
- props["onPointerCancel"]),
7848
- });
7849
- this.removeEndListeners = pipe(removePointerUpListener, removePointerCancelListener);
7850
- this.startPress(startEvent, startInfo);
7851
- };
7852
- this.startAccessiblePress = () => {
7853
- const handleKeydown = (keydownEvent) => {
7854
- if (keydownEvent.key !== "Enter" || this.isPressing)
7855
- return;
7856
- const handleKeyup = (keyupEvent) => {
7857
- if (keyupEvent.key !== "Enter" || !this.checkPressEnd())
7858
- return;
7859
- fireSyntheticPointerEvent("up", (event, info) => {
7860
- const { onTap } = this.node.getProps();
7861
- if (onTap) {
7862
- frame.postRender(() => onTap(event, info));
7863
- }
7864
- });
7865
- };
7866
- this.removeEndListeners();
7867
- this.removeEndListeners = addDomEvent(this.node.current, "keyup", handleKeyup);
7868
- fireSyntheticPointerEvent("down", (event, info) => {
7869
- this.startPress(event, info);
7870
- });
7871
- };
7872
- const removeKeydownListener = addDomEvent(this.node.current, "keydown", handleKeydown);
7873
- const handleBlur = () => {
7874
- if (!this.isPressing)
7875
- return;
7876
- fireSyntheticPointerEvent("cancel", (cancelEvent, cancelInfo) => this.cancelPress(cancelEvent, cancelInfo));
7877
- };
7878
- const removeBlurListener = addDomEvent(this.node.current, "blur", handleBlur);
7879
- this.removeAccessibleListeners = pipe(removeKeydownListener, removeBlurListener);
7880
- };
7881
- }
7882
- startPress(event, info) {
7883
- this.isPressing = true;
7884
- const { onTapStart, whileTap } = this.node.getProps();
7885
- /**
7886
- * Ensure we trigger animations before firing event callback
7887
- */
7888
- if (whileTap && this.node.animationState) {
7889
- this.node.animationState.setActive("whileTap", true);
7890
- }
7891
- if (onTapStart) {
7892
- frame.postRender(() => onTapStart(event, info));
7893
- }
7894
- }
7895
- checkPressEnd() {
7896
- this.removeEndListeners();
7897
- this.isPressing = false;
7898
- const props = this.node.getProps();
7899
- if (props.whileTap && this.node.animationState) {
7900
- this.node.animationState.setActive("whileTap", false);
7901
- }
7902
- return !isDragActive();
7903
- }
7904
- cancelPress(event, info) {
7905
- if (!this.checkPressEnd())
7906
- return;
7907
- const { onTapCancel } = this.node.getProps();
7908
- if (onTapCancel) {
7909
- frame.postRender(() => onTapCancel(event, info));
7910
- }
7911
- }
7912
7942
  mount() {
7913
- const props = this.node.getProps();
7914
- const removePointerListener = addPointerEvent(props.globalTapTarget ? window : this.node.current, "pointerdown", this.startPointerPress, {
7915
- passive: !(props.onTapStart ||
7916
- props["onPointerStart"]),
7917
- });
7918
- const removeFocusListener = addDomEvent(this.node.current, "focus", this.startAccessiblePress);
7919
- this.removeStartListeners = pipe(removePointerListener, removeFocusListener);
7920
- }
7921
- unmount() {
7922
- this.removeStartListeners();
7923
- this.removeEndListeners();
7924
- this.removeAccessibleListeners();
7943
+ const { current } = this.node;
7944
+ if (!current)
7945
+ return;
7946
+ this.unmount = press(current, (startEvent) => {
7947
+ handlePressEvent(this.node, startEvent, "Start");
7948
+ return (endEvent, { success }) => handlePressEvent(this.node, endEvent, success ? "End" : "Cancel");
7949
+ }, { useGlobalTarget: this.node.props.globalTapTarget });
7925
7950
  }
7951
+ unmount() { }
7926
7952
  }
7927
7953
 
7928
7954
  /**
@@ -9130,7 +9156,7 @@ function updateMotionValuesFromProps(element, next, prev) {
9130
9156
  * and warn against mismatches.
9131
9157
  */
9132
9158
  if (process.env.NODE_ENV === "development") {
9133
- warnOnce(nextValue.version === "11.13.5", `Attempting to mix Motion versions ${nextValue.version} with 11.13.5 may not work as expected.`);
9159
+ warnOnce(nextValue.version === "11.14.0", `Attempting to mix Motion versions ${nextValue.version} with 11.14.0 may not work as expected.`);
9134
9160
  }
9135
9161
  }
9136
9162
  else if (isMotionValue(prevValue)) {
@@ -1,4 +1,4 @@
1
- import { isPrimaryPointer } from './utils/is-primary-pointer.mjs';
1
+ import { isPrimaryPointer } from '../../../../motion-dom/dist/es/gestures/utils/is-primary-pointer.mjs';
2
2
 
3
3
  function extractEventInfo(event) {
4
4
  return {
@@ -3,14 +3,14 @@ import { secondsToMilliseconds, millisecondsToSeconds } from '../../utils/time-c
3
3
  import { addPointerEvent } from '../../events/add-pointer-event.mjs';
4
4
  import { pipe } from '../../utils/pipe.mjs';
5
5
  import { distance2D } from '../../utils/distance.mjs';
6
- import { isPrimaryPointer } from '../../events/utils/is-primary-pointer.mjs';
6
+ import { isPrimaryPointer } from '../../../../../motion-dom/dist/es/gestures/utils/is-primary-pointer.mjs';
7
7
  import { frame, cancelFrame, frameData } from '../../frameloop/frame.mjs';
8
8
 
9
9
  /**
10
10
  * @internal
11
11
  */
12
12
  class PanSession {
13
- constructor(event, handlers, { transformPagePoint, contextWindow, dragSnapToOrigin = false } = {}) {
13
+ constructor(event, handlers, { transformPagePoint, contextWindow, dragSnapToOrigin = false, } = {}) {
14
14
  /**
15
15
  * @internal
16
16
  */