@vvfx/sdk 0.2.11 → 0.2.13

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.
@@ -12,10 +12,11 @@ export type CardHTMLAutoHeightOptions = {
12
12
  autoHeightId?: string;
13
13
  onAutoHeight?: (height: number) => void;
14
14
  onStreamRuntimePhase?: (phase: CardHTMLStreamRuntimePhase) => void;
15
+ streamRuntimeId?: string;
15
16
  };
16
17
  export type CardHTMLStreamRuntimePhase = 'parsing' | 'draining' | 'complete' | 'finalizing' | 'disposed' | 'error';
17
18
  export declare function createAutoHeightMessageListener(iframe: HTMLIFrameElement, options?: CardHTMLAutoHeightOptions): CardHTMLRenderCleanup;
18
- export declare function getCardHTMLStreamRuntimePhase(data: unknown): CardHTMLStreamRuntimePhase | undefined;
19
+ export declare function getCardHTMLStreamRuntimePhase(data: unknown, expectedRuntimeId: string): CardHTMLStreamRuntimePhase | undefined;
19
20
  export declare function isCardHTMLAutoHeightMessage(data: unknown, id: string): data is CardHTMLAutoHeightMessage;
20
21
  export declare function requestCardHTMLAutoHeight(iframe: HTMLIFrameElement, id: string): void;
21
22
  export declare function withCardHTMLAutoHeightBridge(html: string, id?: string): string;
@@ -1,3 +1,4 @@
1
+ import { serializeInlineScriptJson } from './inline-script-json';
1
2
  export function createAutoHeightMessageListener(iframe, options) {
2
3
  if (!options?.autoHeightId || !options.onAutoHeight) {
3
4
  return () => {
@@ -12,7 +13,9 @@ export function createAutoHeightMessageListener(iframe, options) {
12
13
  options.onAutoHeight?.(event.data.height);
13
14
  return;
14
15
  }
15
- const phase = getCardHTMLStreamRuntimePhase(event.data);
16
+ const phase = options.streamRuntimeId
17
+ ? getCardHTMLStreamRuntimePhase(event.data, options.streamRuntimeId)
18
+ : undefined;
16
19
  if (phase) {
17
20
  options.onStreamRuntimePhase?.(phase);
18
21
  }
@@ -22,15 +25,21 @@ export function createAutoHeightMessageListener(iframe, options) {
22
25
  window.removeEventListener('message', handleMessage);
23
26
  };
24
27
  }
25
- export function getCardHTMLStreamRuntimePhase(data) {
28
+ export function getCardHTMLStreamRuntimePhase(data, expectedRuntimeId) {
26
29
  if (typeof data !== 'object' || data === null) {
27
30
  return undefined;
28
31
  }
29
32
  const message = data;
30
- if (message.type !== 'huamei:html-stream-runtime-status' || typeof message.payload !== 'object' || message.payload === null) {
33
+ if (message.source !== 'vvfx-card-html-stream-runtime' ||
34
+ message.type !== 'huamei:html-stream-runtime-status' ||
35
+ typeof message.payload !== 'object' || message.payload === null) {
31
36
  return undefined;
32
37
  }
33
- const phase = message.payload.phase;
38
+ const payload = message.payload;
39
+ if (payload.runtimeId !== expectedRuntimeId) {
40
+ return undefined;
41
+ }
42
+ const phase = payload.phase;
34
43
  return ['parsing', 'draining', 'complete', 'finalizing', 'disposed', 'error'].includes(String(phase))
35
44
  ? phase
36
45
  : undefined;
@@ -57,7 +66,7 @@ export function withCardHTMLAutoHeightBridge(html, id) {
57
66
  const script = `
58
67
  <script data-vvfx-card-html-auto-height>
59
68
  (() => {
60
- const id = ${JSON.stringify(id)};
69
+ const id = ${serializeInlineScriptJson(id)};
61
70
  let frame = 0;
62
71
  const getNodeHeight = (node) => {
63
72
  if (node.nodeType === Node.ELEMENT_NODE) {
@@ -4,13 +4,18 @@ import { createHostMessageListener } from './host-message-runtime';
4
4
  import { normalizePath } from './path-utils';
5
5
  import { withCardHTMLViewportStyle } from './html-viewport-style';
6
6
  import { withCardHTMLAnchorNavigationGuard } from './anchor-navigation-runtime';
7
+ import { createCardHTMLRuntimeId, withCardHTMLRuntimeContext } from './runtime-context';
7
8
  export function renderDocumentContent(overlay, content, options) {
8
9
  const iframe = document.createElement('iframe');
9
10
  const files = normalizeDocumentFiles(content.files);
10
11
  const entry = normalizePath(content.entry);
11
12
  const createFileUrl = createDocumentFileUrlFactory(files);
13
+ const streamRuntimeId = createCardHTMLRuntimeId(options?.autoHeightId);
12
14
  const messageCleanup = createHostMessageListener(iframe, content);
13
- const autoHeightMessageCleanup = createAutoHeightMessageListener(iframe, options);
15
+ const autoHeightMessageCleanup = createAutoHeightMessageListener(iframe, {
16
+ ...options,
17
+ streamRuntimeId,
18
+ });
14
19
  iframe.style.width = '100%';
15
20
  iframe.style.height = '100%';
16
21
  iframe.style.border = '0';
@@ -22,7 +27,7 @@ export function renderDocumentContent(overlay, content, options) {
22
27
  iframe.setAttribute('sandbox', content.sandbox);
23
28
  }
24
29
  const entryHtml = files.get(entry) ?? '';
25
- iframe.srcdoc = withCardHTMLAutoHeightBridge(withCardHTMLAnchorNavigationGuard(withCardHTMLViewportStyle(transformHTMLDocument(entry, entryHtml, createFileUrl)), content.allowAnchorNavigation), options?.autoHeightId);
30
+ iframe.srcdoc = withCardHTMLAutoHeightBridge(withCardHTMLAnchorNavigationGuard(withCardHTMLRuntimeContext(withCardHTMLViewportStyle(transformHTMLDocument(entry, entryHtml, createFileUrl)), streamRuntimeId), content.allowAnchorNavigation), options?.autoHeightId);
26
31
  overlay.appendChild(iframe);
27
32
  return () => {
28
33
  messageCleanup();
@@ -0,0 +1 @@
1
+ export declare function serializeInlineScriptJson(value: unknown): string;
@@ -0,0 +1,8 @@
1
+ export function serializeInlineScriptJson(value) {
2
+ return JSON.stringify(value)
3
+ .replace(/</g, '\\u003c')
4
+ .replace(/>/g, '\\u003e')
5
+ .replace(/&/g, '\\u0026')
6
+ .replace(/\u2028/g, '\\u2028')
7
+ .replace(/\u2029/g, '\\u2029');
8
+ }
@@ -133,6 +133,7 @@ export declare class HTMLOverlayManager {
133
133
  private getChildrenNaturalHeight;
134
134
  private cleanupAutoHeight;
135
135
  private applyAutoHeight;
136
+ private isAutoHeightFeedbackLoop;
136
137
  private setAutoHeightStreamPhase;
137
138
  private isAutoHeightStreamActive;
138
139
  private getAutoHeightAnchor;
@@ -35,6 +35,7 @@ const EDITING_VIEWPORT_PADDING = 48;
35
35
  const EDITING_VIEWPORT_BOX_SCALE = 1.1;
36
36
  const AUTO_HEIGHT_EPSILON = 0.5;
37
37
  const AUTO_HEIGHT_MAX_MULTIPLIER = 32;
38
+ const AUTO_HEIGHT_FEEDBACK_STEP_LIMIT = 2;
38
39
  const CARD_RASTERIZE_READY_TIMEOUT = 3000;
39
40
  const CARD_HTML_EVENT_MESSAGE_SOURCE = 'vvfx-card-html-event';
40
41
  const requestHTMLOverlayFrame = (callback) => {
@@ -84,6 +85,7 @@ export class HTMLOverlayManager {
84
85
  autoHeightCleanups: new Map(),
85
86
  autoHeightFrames: new Map(),
86
87
  autoHeightInitialHeights: new Map(),
88
+ autoHeightFeedback: new Map(),
87
89
  autoHeightStreamPhases: new Map(),
88
90
  };
89
91
  constructor(options) {
@@ -148,6 +150,7 @@ export class HTMLOverlayManager {
148
150
  });
149
151
  this.state.autoHeightFrames.clear();
150
152
  this.state.autoHeightInitialHeights.clear();
153
+ this.state.autoHeightFeedback.clear();
151
154
  this.state.autoHeightStreamPhases.clear();
152
155
  this.eventCleanups.forEach(cleanup => {
153
156
  cleanup();
@@ -1421,6 +1424,7 @@ export class HTMLOverlayManager {
1421
1424
  cancelHTMLOverlayFrame(frame);
1422
1425
  this.state.autoHeightFrames.delete(id);
1423
1426
  }
1427
+ this.state.autoHeightFeedback.delete(id);
1424
1428
  }
1425
1429
  applyAutoHeight(id, height) {
1426
1430
  const item = this.options.getItems().find(candidate => candidate.id === id);
@@ -1438,11 +1442,28 @@ export class HTMLOverlayManager {
1438
1442
  if (Math.abs(nextHeight - item.property.height) <= AUTO_HEIGHT_EPSILON) {
1439
1443
  return;
1440
1444
  }
1445
+ if (this.isAutoHeightFeedbackLoop(id, item.property.height, nextHeight)) {
1446
+ return;
1447
+ }
1441
1448
  this.options.setCardItemHeight(id, nextHeight, {
1442
1449
  anchor: this.getAutoHeightAnchor(item),
1443
1450
  previousHeight: item.property.height,
1444
1451
  });
1445
1452
  }
1453
+ isAutoHeightFeedbackLoop(id, currentHeight, nextHeight) {
1454
+ if (nextHeight <= currentHeight) {
1455
+ this.state.autoHeightFeedback.delete(id);
1456
+ return false;
1457
+ }
1458
+ const offset = nextHeight - currentHeight;
1459
+ const previous = this.state.autoHeightFeedback.get(id);
1460
+ const continues = previous !== undefined &&
1461
+ Math.abs(previous.nextHeight - currentHeight) <= AUTO_HEIGHT_EPSILON &&
1462
+ Math.abs(previous.offset - offset) <= AUTO_HEIGHT_EPSILON;
1463
+ const steps = continues ? previous.steps + 1 : 0;
1464
+ this.state.autoHeightFeedback.set(id, { nextHeight, offset, steps });
1465
+ return steps >= AUTO_HEIGHT_FEEDBACK_STEP_LIMIT;
1466
+ }
1446
1467
  setAutoHeightStreamPhase(id, phase) {
1447
1468
  if (phase === 'parsing' || phase === 'draining' || phase === 'finalizing') {
1448
1469
  this.state.autoHeightStreamPhases.set(id, phase);
@@ -0,0 +1,2 @@
1
+ export declare function createCardHTMLRuntimeId(cardId?: string): string;
2
+ export declare function withCardHTMLRuntimeContext(html: string, runtimeId: string): string;
@@ -0,0 +1,16 @@
1
+ import { serializeInlineScriptJson } from './inline-script-json';
2
+ let runtimeSequence = 0;
3
+ export function createCardHTMLRuntimeId(cardId) {
4
+ runtimeSequence += 1;
5
+ return `${cardId || 'card'}:${runtimeSequence}`;
6
+ }
7
+ export function withCardHTMLRuntimeContext(html, runtimeId) {
8
+ const script = `<script data-vvfx-card-html-runtime-context>window.__VVFX_CARD_HTML_RUNTIME_ID__=${serializeInlineScriptJson(runtimeId)};</script>`;
9
+ if (/<head(?:\s[^>]*)?>/i.test(html)) {
10
+ return html.replace(/<head(\s[^>]*)?>/i, match => `${match}${script}`);
11
+ }
12
+ if (/<html(?:\s[^>]*)?>/i.test(html)) {
13
+ return html.replace(/<html(\s[^>]*)?>/i, match => `${match}<head>${script}</head>`);
14
+ }
15
+ return `<!doctype html><html><head>${script}</head><body>${html}</body></html>`;
16
+ }
package/dist/index.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  * Description: TODO
4
4
  * Author: Ant Group CO., Ltd.
5
5
  * Contributors: 赤芍,何即,不择,意绮
6
- * Version: v0.2.11
6
+ * Version: v0.2.13
7
7
  */
8
8
 
9
9
  'use strict';
@@ -69603,6 +69603,10 @@ function vi(t) {
69603
69603
  return false;
69604
69604
  }
69605
69605
 
69606
+ function serializeInlineScriptJson(value) {
69607
+ return JSON.stringify(value).replace(/</g, '\\u003c').replace(/>/g, '\\u003e').replace(/&/g, '\\u0026').replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
69608
+ }
69609
+
69606
69610
  function createAutoHeightMessageListener(iframe, options) {
69607
69611
  if (!(options == null ? void 0 : options.autoHeightId) || !options.onAutoHeight) {
69608
69612
  return function() {
@@ -69617,7 +69621,7 @@ function createAutoHeightMessageListener(iframe, options) {
69617
69621
  options.onAutoHeight == null ? void 0 : options.onAutoHeight.call(options, event.data.height);
69618
69622
  return;
69619
69623
  }
69620
- var phase = getCardHTMLStreamRuntimePhase(event.data);
69624
+ var phase = options.streamRuntimeId ? getCardHTMLStreamRuntimePhase(event.data, options.streamRuntimeId) : undefined;
69621
69625
  if (phase) {
69622
69626
  options.onStreamRuntimePhase == null ? void 0 : options.onStreamRuntimePhase.call(options, phase);
69623
69627
  }
@@ -69627,15 +69631,19 @@ function createAutoHeightMessageListener(iframe, options) {
69627
69631
  window.removeEventListener('message', handleMessage);
69628
69632
  };
69629
69633
  }
69630
- function getCardHTMLStreamRuntimePhase(data) {
69634
+ function getCardHTMLStreamRuntimePhase(data, expectedRuntimeId) {
69631
69635
  if ((typeof data === "undefined" ? "undefined" : _type_of(data)) !== 'object' || data === null) {
69632
69636
  return undefined;
69633
69637
  }
69634
69638
  var message = data;
69635
- if (message.type !== 'huamei:html-stream-runtime-status' || _type_of(message.payload) !== 'object' || message.payload === null) {
69639
+ if (message.source !== 'vvfx-card-html-stream-runtime' || message.type !== 'huamei:html-stream-runtime-status' || _type_of(message.payload) !== 'object' || message.payload === null) {
69640
+ return undefined;
69641
+ }
69642
+ var payload = message.payload;
69643
+ if (payload.runtimeId !== expectedRuntimeId) {
69636
69644
  return undefined;
69637
69645
  }
69638
- var phase = message.payload.phase;
69646
+ var phase = payload.phase;
69639
69647
  return [
69640
69648
  'parsing',
69641
69649
  'draining',
@@ -69663,7 +69671,7 @@ function withCardHTMLAutoHeightBridge(html, id) {
69663
69671
  if (!id) {
69664
69672
  return html;
69665
69673
  }
69666
- var script = "\n<script data-vvfx-card-html-auto-height>\n(() => {\n const id = " + JSON.stringify(id) + ";\n let frame = 0;\n const getNodeHeight = (node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n if (window.getComputedStyle(node).position === 'fixed') {\n return 0;\n }\n const rect = node.getBoundingClientRect();\n return rect.bottom + window.scrollY;\n }\n if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {\n const range = document.createRange();\n range.selectNodeContents(node);\n const rects = Array.from(range.getClientRects());\n range.detach();\n return rects.reduce((height, rect) => Math.max(height, rect.bottom + window.scrollY), 0);\n }\n\n return 0;\n };\n const getContentHeight = (element) => {\n if (!element) return 0;\n return Array.from(element.childNodes).reduce((height, child) => {\n return Math.max(height, getNodeHeight(child));\n }, 0);\n };\n const getHeight = () => {\n const body = document.body;\n const root = document.documentElement;\n const contentHeight = getContentHeight(body);\n const scrollHeight = Math.max(root.scrollHeight, body ? body.scrollHeight : 0);\n return Math.ceil(contentHeight > 0 ? contentHeight : scrollHeight);\n };\n const postHeight = () => {\n frame = 0;\n window.parent.postMessage({\n source: 'vvfx-card-html-auto-height',\n id,\n height: getHeight(),\n }, '*');\n };\n const schedule = () => {\n if (frame) return;\n frame = requestAnimationFrame(postHeight);\n };\n window.addEventListener('message', (event) => {\n const message = event.data;\n if (!message || message.source !== 'vvfx-card-html-auto-height-request' || message.id !== id) {\n return;\n }\n\n schedule();\n });\n window.addEventListener('load', schedule);\n window.addEventListener('resize', schedule);\n new ResizeObserver(schedule).observe(document.documentElement);\n if (document.body) {\n new ResizeObserver(schedule).observe(document.body);\n new MutationObserver(schedule).observe(document.body, {\n attributes: true,\n childList: true,\n subtree: true,\n characterData: true,\n });\n }\n schedule();\n})();\n</script>";
69674
+ var script = "\n<script data-vvfx-card-html-auto-height>\n(() => {\n const id = " + serializeInlineScriptJson(id) + ";\n let frame = 0;\n const getNodeHeight = (node) => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n if (window.getComputedStyle(node).position === 'fixed') {\n return 0;\n }\n const rect = node.getBoundingClientRect();\n return rect.bottom + window.scrollY;\n }\n if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) {\n const range = document.createRange();\n range.selectNodeContents(node);\n const rects = Array.from(range.getClientRects());\n range.detach();\n return rects.reduce((height, rect) => Math.max(height, rect.bottom + window.scrollY), 0);\n }\n\n return 0;\n };\n const getContentHeight = (element) => {\n if (!element) return 0;\n return Array.from(element.childNodes).reduce((height, child) => {\n return Math.max(height, getNodeHeight(child));\n }, 0);\n };\n const getHeight = () => {\n const body = document.body;\n const root = document.documentElement;\n const contentHeight = getContentHeight(body);\n const scrollHeight = Math.max(root.scrollHeight, body ? body.scrollHeight : 0);\n return Math.ceil(contentHeight > 0 ? contentHeight : scrollHeight);\n };\n const postHeight = () => {\n frame = 0;\n window.parent.postMessage({\n source: 'vvfx-card-html-auto-height',\n id,\n height: getHeight(),\n }, '*');\n };\n const schedule = () => {\n if (frame) return;\n frame = requestAnimationFrame(postHeight);\n };\n window.addEventListener('message', (event) => {\n const message = event.data;\n if (!message || message.source !== 'vvfx-card-html-auto-height-request' || message.id !== id) {\n return;\n }\n\n schedule();\n });\n window.addEventListener('load', schedule);\n window.addEventListener('resize', schedule);\n new ResizeObserver(schedule).observe(document.documentElement);\n if (document.body) {\n new ResizeObserver(schedule).observe(document.body);\n new MutationObserver(schedule).observe(document.body, {\n attributes: true,\n childList: true,\n subtree: true,\n characterData: true,\n });\n }\n schedule();\n})();\n</script>";
69667
69675
  if (/<\/body>/i.test(html)) {
69668
69676
  return html.replace(/<\/body>/i, "" + script + "</body>");
69669
69677
  }
@@ -69872,14 +69880,37 @@ function withCardHTMLAnchorNavigationGuard(html, allowAnchorNavigation) {
69872
69880
  return "" + html + script;
69873
69881
  }
69874
69882
 
69883
+ var runtimeSequence = 0;
69884
+ function createCardHTMLRuntimeId(cardId) {
69885
+ runtimeSequence += 1;
69886
+ return (cardId || 'card') + ":" + runtimeSequence;
69887
+ }
69888
+ function withCardHTMLRuntimeContext(html, runtimeId) {
69889
+ var script = "<script data-vvfx-card-html-runtime-context>window.__VVFX_CARD_HTML_RUNTIME_ID__=" + serializeInlineScriptJson(runtimeId) + ";</script>";
69890
+ if (/<head(?:\s[^>]*)?>/i.test(html)) {
69891
+ return html.replace(/<head(\s[^>]*)?>/i, function(match) {
69892
+ return "" + match + script;
69893
+ });
69894
+ }
69895
+ if (/<html(?:\s[^>]*)?>/i.test(html)) {
69896
+ return html.replace(/<html(\s[^>]*)?>/i, function(match) {
69897
+ return match + "<head>" + script + "</head>";
69898
+ });
69899
+ }
69900
+ return "<!doctype html><html><head>" + script + "</head><body>" + html + "</body></html>";
69901
+ }
69902
+
69875
69903
  function renderDocumentContent(overlay, content, options) {
69876
69904
  var _files_get;
69877
69905
  var iframe = document.createElement('iframe');
69878
69906
  var files = normalizeDocumentFiles(content.files);
69879
69907
  var entry = normalizePath(content.entry);
69880
69908
  var createFileUrl = createDocumentFileUrlFactory(files);
69909
+ var streamRuntimeId = createCardHTMLRuntimeId(options == null ? void 0 : options.autoHeightId);
69881
69910
  var messageCleanup = createHostMessageListener(iframe, content);
69882
- var autoHeightMessageCleanup = createAutoHeightMessageListener(iframe, options);
69911
+ var autoHeightMessageCleanup = createAutoHeightMessageListener(iframe, _extends({}, options, {
69912
+ streamRuntimeId: streamRuntimeId
69913
+ }));
69883
69914
  iframe.style.width = '100%';
69884
69915
  iframe.style.height = '100%';
69885
69916
  iframe.style.border = '0';
@@ -69890,7 +69921,7 @@ function renderDocumentContent(overlay, content, options) {
69890
69921
  iframe.setAttribute('sandbox', content.sandbox);
69891
69922
  }
69892
69923
  var entryHtml = (_files_get = files.get(entry)) != null ? _files_get : '';
69893
- iframe.srcdoc = withCardHTMLAutoHeightBridge(withCardHTMLAnchorNavigationGuard(withCardHTMLViewportStyle(transformHTMLDocument(entry, entryHtml, createFileUrl)), content.allowAnchorNavigation), options == null ? void 0 : options.autoHeightId);
69924
+ iframe.srcdoc = withCardHTMLAutoHeightBridge(withCardHTMLAnchorNavigationGuard(withCardHTMLRuntimeContext(withCardHTMLViewportStyle(transformHTMLDocument(entry, entryHtml, createFileUrl)), streamRuntimeId), content.allowAnchorNavigation), options == null ? void 0 : options.autoHeightId);
69894
69925
  overlay.appendChild(iframe);
69895
69926
  return function() {
69896
69927
  messageCleanup();
@@ -70485,6 +70516,7 @@ var EDITING_VIEWPORT_PADDING = 48;
70485
70516
  var EDITING_VIEWPORT_BOX_SCALE = 1.1;
70486
70517
  var AUTO_HEIGHT_EPSILON = 0.5;
70487
70518
  var AUTO_HEIGHT_MAX_MULTIPLIER = 32;
70519
+ var AUTO_HEIGHT_FEEDBACK_STEP_LIMIT = 2;
70488
70520
  var CARD_RASTERIZE_READY_TIMEOUT = 3000;
70489
70521
  var CARD_HTML_EVENT_MESSAGE_SOURCE = 'vvfx-card-html-event';
70490
70522
  var requestHTMLOverlayFrame = function requestHTMLOverlayFrame(callback) {
@@ -70532,6 +70564,7 @@ var HTMLOverlayManager = /*#__PURE__*/ function() {
70532
70564
  autoHeightCleanups: new Map(),
70533
70565
  autoHeightFrames: new Map(),
70534
70566
  autoHeightInitialHeights: new Map(),
70567
+ autoHeightFeedback: new Map(),
70535
70568
  autoHeightStreamPhases: new Map()
70536
70569
  };
70537
70570
  this.handleContainerDoubleClick = function(event) {
@@ -70685,6 +70718,7 @@ var HTMLOverlayManager = /*#__PURE__*/ function() {
70685
70718
  });
70686
70719
  this.state.autoHeightFrames.clear();
70687
70720
  this.state.autoHeightInitialHeights.clear();
70721
+ this.state.autoHeightFeedback.clear();
70688
70722
  this.state.autoHeightStreamPhases.clear();
70689
70723
  this.eventCleanups.forEach(function(cleanup) {
70690
70724
  cleanup();
@@ -71983,6 +72017,7 @@ var HTMLOverlayManager = /*#__PURE__*/ function() {
71983
72017
  cancelHTMLOverlayFrame(frame);
71984
72018
  this.state.autoHeightFrames.delete(id);
71985
72019
  }
72020
+ this.state.autoHeightFeedback.delete(id);
71986
72021
  };
71987
72022
  _proto.applyAutoHeight = function applyAutoHeight(id, height) {
71988
72023
  var item = this.options.getItems().find(function(candidate) {
@@ -72002,11 +72037,30 @@ var HTMLOverlayManager = /*#__PURE__*/ function() {
72002
72037
  if (Math.abs(nextHeight - item.property.height) <= AUTO_HEIGHT_EPSILON) {
72003
72038
  return;
72004
72039
  }
72040
+ if (this.isAutoHeightFeedbackLoop(id, item.property.height, nextHeight)) {
72041
+ return;
72042
+ }
72005
72043
  this.options.setCardItemHeight(id, nextHeight, {
72006
72044
  anchor: this.getAutoHeightAnchor(item),
72007
72045
  previousHeight: item.property.height
72008
72046
  });
72009
72047
  };
72048
+ _proto.isAutoHeightFeedbackLoop = function isAutoHeightFeedbackLoop(id, currentHeight, nextHeight) {
72049
+ if (nextHeight <= currentHeight) {
72050
+ this.state.autoHeightFeedback.delete(id);
72051
+ return false;
72052
+ }
72053
+ var offset = nextHeight - currentHeight;
72054
+ var previous = this.state.autoHeightFeedback.get(id);
72055
+ var continues = previous !== undefined && Math.abs(previous.nextHeight - currentHeight) <= AUTO_HEIGHT_EPSILON && Math.abs(previous.offset - offset) <= AUTO_HEIGHT_EPSILON;
72056
+ var steps = continues ? previous.steps + 1 : 0;
72057
+ this.state.autoHeightFeedback.set(id, {
72058
+ nextHeight: nextHeight,
72059
+ offset: offset,
72060
+ steps: steps
72061
+ });
72062
+ return steps >= AUTO_HEIGHT_FEEDBACK_STEP_LIMIT;
72063
+ };
72010
72064
  _proto.setAutoHeightStreamPhase = function setAutoHeightStreamPhase(id, phase) {
72011
72065
  if (phase === 'parsing' || phase === 'draining' || phase === 'finalizing') {
72012
72066
  this.state.autoHeightStreamPhases.set(id, phase);