@onekeyfe/react-native-native-list 6.7.0-alpha.375 → 6.7.0-alpha.382

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 (116) hide show
  1. package/android/src/main/java/com/onekey/nativelist/HybridNativeList.kt +14 -1
  2. package/android/src/main/java/com/onekey/nativelist/NativeListAccessoryStack.kt +240 -11
  3. package/android/src/main/java/com/onekey/nativelist/NativeListActivityDetailsView.kt +7 -4
  4. package/android/src/main/java/com/onekey/nativelist/NativeListActivityRenderer.kt +6 -3
  5. package/android/src/main/java/com/onekey/nativelist/NativeListButtonGroupRenderer.kt +102 -0
  6. package/android/src/main/java/com/onekey/nativelist/NativeListContainerSlotAdapter.kt +12 -0
  7. package/android/src/main/java/com/onekey/nativelist/NativeListDataRowRenderer.kt +87 -7
  8. package/android/src/main/java/com/onekey/nativelist/NativeListIdentityRenderer.kt +177 -1
  9. package/android/src/main/java/com/onekey/nativelist/NativeListLeadingVisual.kt +43 -14
  10. package/android/src/main/java/com/onekey/nativelist/NativeListMessageRenderer.kt +25 -0
  11. package/android/src/main/java/com/onekey/nativelist/NativeListModels.kt +33 -2
  12. package/android/src/main/java/com/onekey/nativelist/NativeListPrimitives.kt +22 -0
  13. package/android/src/main/java/com/onekey/nativelist/NativeListRendererRegistry.kt +2 -0
  14. package/android/src/main/java/com/onekey/nativelist/NativeListRendererRowView.kt +2 -0
  15. package/android/src/main/java/com/onekey/nativelist/NativeListResolvedText.kt +3 -2
  16. package/android/src/main/java/com/onekey/nativelist/NativeListSectionHeaderRenderer.kt +69 -0
  17. package/android/src/main/java/com/onekey/nativelist/NativeListTextView.kt +55 -1
  18. package/android/src/main/java/com/onekey/nativelist/NativeListView.kt +1912 -107
  19. package/android/src/test/java/com/margelo/nitro/nativelist/NativeListPressPolicyTest.kt +1 -0
  20. package/docs/ROW_TEMPLATES.md +60 -9
  21. package/docs/SPEC.md +450 -5
  22. package/docs/STYLE_SPEC.md +6 -0
  23. package/ios/HybridNativeList.swift +21 -2
  24. package/ios/NativeListAccessoryStack.swift +227 -39
  25. package/ios/NativeListActivityDetailsView.swift +18 -8
  26. package/ios/NativeListActivityRenderer.swift +8 -2
  27. package/ios/NativeListButtonGroupRenderer.swift +89 -0
  28. package/ios/NativeListDataRowRenderer.swift +155 -27
  29. package/ios/NativeListDesignAssets.swift +3 -0
  30. package/ios/NativeListIdentityRenderer.swift +166 -30
  31. package/ios/NativeListLeadingVisual.swift +49 -14
  32. package/ios/NativeListMessageRenderer.swift +34 -1
  33. package/ios/NativeListModels.swift +42 -2
  34. package/ios/NativeListRendererRegistry.swift +1 -0
  35. package/ios/NativeListResolvedText.swift +2 -1
  36. package/ios/NativeListRowHost.swift +14 -0
  37. package/ios/NativeListSectionHeaderRenderer.swift +88 -0
  38. package/ios/RNCNativeListView.swift +1013 -55
  39. package/ios/Resources/NativeListIcons.xcassets/onekey_crypto_coin_outline.imageset/Contents.json +15 -0
  40. package/ios/Resources/NativeListIcons.xcassets/onekey_crypto_coin_outline.imageset/icon.svg +4 -0
  41. package/ios/Resources/NativeListIcons.xcassets/onekey_gas_solid.imageset/Contents.json +15 -0
  42. package/ios/Resources/NativeListIcons.xcassets/onekey_gas_solid.imageset/icon.svg +3 -0
  43. package/ios/Resources/NativeListIcons.xcassets/onekey_refresh_ccw_outline.imageset/Contents.json +15 -0
  44. package/ios/Resources/NativeListIcons.xcassets/onekey_refresh_ccw_outline.imageset/icon.svg +3 -0
  45. package/ios/tests/NativeListActivityPresentationTests.swift +56 -0
  46. package/ios/tests/NativeListLifecycleTests.swift +2720 -3
  47. package/lib/module/NativeList.js +175 -28
  48. package/lib/module/NativeList.web.js +129 -30
  49. package/lib/module/index.js +1 -1
  50. package/lib/module/models.js +1 -0
  51. package/lib/module/selection.js +1 -1
  52. package/lib/module/validation.js +421 -8
  53. package/lib/module/web/NativeListWebEngine.js +507 -19
  54. package/lib/module/web/templates/ActivityRowRenderer.js +8 -7
  55. package/lib/module/web/templates/ButtonGroupRowRenderer.js +47 -0
  56. package/lib/module/web/templates/DataRowRenderer.js +40 -5
  57. package/lib/module/web/templates/IdentityRowRenderer.js +90 -4
  58. package/lib/module/web/templates/MessageRowRenderer.js +18 -2
  59. package/lib/module/web/templates/RowContainerStyle.js +1 -0
  60. package/lib/module/web/templates/RowRendererRegistry.js +3 -0
  61. package/lib/module/web/templates/SectionHeaderRowRenderer.js +36 -2
  62. package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +26 -0
  63. package/lib/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +4 -0
  64. package/lib/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +10 -0
  65. package/lib/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +20 -0
  66. package/lib/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +14 -0
  67. package/lib/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +12 -0
  68. package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +2 -0
  69. package/lib/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +43 -0
  70. package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +4 -0
  71. package/lib/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +4 -0
  72. package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +4 -0
  73. package/lib/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +6 -0
  74. package/lib/nitrogen/generated/shared/json/NativeListConfig.json +2 -0
  75. package/lib/typescript/src/NativeList.d.ts +1 -1
  76. package/lib/typescript/src/NativeList.nitro.d.ts +2 -0
  77. package/lib/typescript/src/NativeList.types.d.ts +18 -0
  78. package/lib/typescript/src/index.d.ts +2 -2
  79. package/lib/typescript/src/models.d.ts +105 -9
  80. package/lib/typescript/src/validation.d.ts +12 -0
  81. package/lib/typescript/src/web/NativeListWebEngine.d.ts +32 -0
  82. package/lib/typescript/src/web/templates/ButtonGroupRowRenderer.d.ts +14 -0
  83. package/lib/typescript/src/web/templates/IdentityRowRenderer.d.ts +1 -1
  84. package/lib/typescript/src/web/templates/MessageRowRenderer.d.ts +9 -3
  85. package/nitrogen/generated/android/c++/JHybridNativeListSpec.cpp +26 -0
  86. package/nitrogen/generated/android/c++/JHybridNativeListSpec.hpp +4 -0
  87. package/nitrogen/generated/android/c++/views/JHybridNativeListStateUpdater.cpp +10 -0
  88. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nativelist/HybridNativeListSpec.kt +20 -0
  89. package/nitrogen/generated/ios/c++/HybridNativeListSpecSwift.hpp +14 -0
  90. package/nitrogen/generated/ios/c++/views/HybridNativeListComponent.mm +12 -0
  91. package/nitrogen/generated/ios/swift/HybridNativeListSpec.swift +2 -0
  92. package/nitrogen/generated/ios/swift/HybridNativeListSpec_cxx.swift +43 -0
  93. package/nitrogen/generated/shared/c++/HybridNativeListSpec.cpp +4 -0
  94. package/nitrogen/generated/shared/c++/HybridNativeListSpec.hpp +4 -0
  95. package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.cpp +4 -0
  96. package/nitrogen/generated/shared/c++/views/HybridNativeListComponent.hpp +6 -0
  97. package/nitrogen/generated/shared/json/NativeListConfig.json +2 -0
  98. package/package.json +3 -3
  99. package/react-native-native-list.podspec +1 -0
  100. package/src/NativeList.nitro.ts +2 -0
  101. package/src/NativeList.tsx +313 -44
  102. package/src/NativeList.types.ts +22 -0
  103. package/src/NativeList.web.tsx +204 -48
  104. package/src/index.ts +2 -0
  105. package/src/models.ts +117 -3
  106. package/src/selection.ts +1 -0
  107. package/src/validation.ts +852 -6
  108. package/src/web/NativeListWebEngine.ts +803 -20
  109. package/src/web/templates/ActivityRowRenderer.ts +14 -6
  110. package/src/web/templates/ButtonGroupRowRenderer.ts +58 -0
  111. package/src/web/templates/DataRowRenderer.ts +93 -20
  112. package/src/web/templates/IdentityRowRenderer.ts +150 -5
  113. package/src/web/templates/MessageRowRenderer.ts +23 -7
  114. package/src/web/templates/RowContainerStyle.ts +2 -0
  115. package/src/web/templates/RowRendererRegistry.ts +11 -1
  116. package/src/web/templates/SectionHeaderRowRenderer.ts +47 -4
@@ -22,13 +22,13 @@ function bindLegacy(body, row, primitives) {
22
22
  node.hidden = !row[key];
23
23
  if (style?.[key]) primitives.textStyle(node, style[key]);
24
24
  }
25
- const visualKey = JSON.stringify([row.key, row.leading, row.secondaryLeading]);
25
+ const visualKey = JSON.stringify([row.key, row.hideLeading, row.leading, row.secondaryLeading]);
26
26
  if (v.visualKey !== visualKey) {
27
27
  v.visuals.forEach(node => {
28
28
  primitives.dispose(node);
29
29
  node.remove();
30
30
  });
31
- v.visuals = [row.leading, row.secondaryLeading].map(source => primitives.visual(source)).filter(node => !!node);
31
+ v.visuals = (row.hideLeading ? [] : [row.leading, row.secondaryLeading]).map(source => primitives.visual(source)).filter(node => !!node);
32
32
  v.visuals.forEach(node => body.insertBefore(node, v.column));
33
33
  v.visualStyles = v.visuals.map(node => new RowVisualStyle(node));
34
34
  v.visualKey = visualKey;
@@ -224,22 +224,23 @@ function bindHistory(body, row, primitives) {
224
224
  Object.assign(v.identity.style, {
225
225
  display: 'flex',
226
226
  alignItems: 'center',
227
- gap: '12px',
227
+ gap: row.hideLeading ? '0' : '12px',
228
228
  minWidth: '0',
229
229
  flex: '1 1 0'
230
230
  });
231
231
  Object.assign(v.visual.style, {
232
+ display: row.hideLeading ? 'none' : '',
232
233
  position: 'relative',
233
234
  width: '40px',
234
235
  height: '40px',
235
236
  flex: '0 0 40px'
236
237
  });
237
- const visualKey = JSON.stringify([row.key, row.leading, row.secondaryLeading]);
238
+ const visualKey = JSON.stringify([row.key, row.hideLeading, row.leading, row.secondaryLeading]);
238
239
  if (v.visualKey !== visualKey) {
239
240
  Array.from(v.visual.children).forEach(n => primitives.dispose(n));
240
241
  v.visual.replaceChildren();
241
242
  v.visuals = [];
242
- const sources = [row.leading, row.secondaryLeading].filter(Boolean);
243
+ const sources = row.hideLeading ? [] : [row.leading, row.secondaryLeading].filter(Boolean);
243
244
  sources.forEach(source => {
244
245
  const visual = primitives.visual(source);
245
246
  if (!visual) return;
@@ -263,7 +264,7 @@ function bindHistory(body, row, primitives) {
263
264
  });
264
265
  v.visualKey = visualKey;
265
266
  }
266
- const sources = [row.leading, row.secondaryLeading].filter(Boolean);
267
+ const sources = row.hideLeading ? [] : [row.leading, row.secondaryLeading].filter(Boolean);
267
268
  v.visuals.forEach((retained, index) => {
268
269
  const {
269
270
  node: visual,
@@ -493,7 +494,7 @@ function bindHistory(body, row, primitives) {
493
494
  v.feeSecondary.style.cssText = ellipsis + 'font-size:14px;line-height:20px;font-weight:400;color:var(--nl-secondary);';
494
495
  valueText(v.feePrimary, row.fee?.primary, row.fee?.primaryTextSegments, 14, 20, 400);
495
496
  valueText(v.feeSecondary, row.fee?.secondary, row.fee?.secondaryTextSegments, 14, 20, 400);
496
- v.actions.style.cssText = 'display:flex;gap:12px;padding-left:52px;padding-bottom:4px;';
497
+ v.actions.style.cssText = `display:flex;gap:12px;padding-left:${row.hideLeading ? 0 : 52}px;padding-bottom:4px;`;
497
498
  v.actions.style.display = footer ? 'flex' : 'none';
498
499
  const actionKeys = new Set();
499
500
  for (const [index, action] of (row.footerActions ?? []).entries()) {
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+
3
+ import { markActionAnchorSource } from "./RowElements.js";
4
+ function bind(body, row) {
5
+ body.replaceChildren();
6
+ body.className = 'ok-native-list-row ok-native-list-button-group';
7
+ body.removeAttribute('data-nl-container-background');
8
+ body.removeAttribute('data-nl-container-border');
9
+ row.buttons.forEach((descriptor, index) => {
10
+ const button = body.ownerDocument.createElement('button');
11
+ button.type = 'button';
12
+ button.className = 'ok-native-list-block-button';
13
+ button.dataset.nativeListAction = descriptor.actionKey;
14
+ button.dataset.nlButtonKey = descriptor.key;
15
+ button.dataset.nlSlot = `button-${index}`;
16
+ if (descriptor.testID) button.dataset.testid = descriptor.testID;
17
+ button.setAttribute('aria-label', descriptor.accessibilityLabel ?? descriptor.label);
18
+ button.disabled = Boolean(row.disabled || descriptor.disabled || descriptor.loading);
19
+ button.setAttribute('aria-busy', descriptor.loading ? 'true' : 'false');
20
+ markActionAnchorSource(button, 'buttonGroup', index);
21
+ const label = body.ownerDocument.createElement('span');
22
+ label.textContent = descriptor.label;
23
+ if (descriptor.loading) {
24
+ const spinner = body.ownerDocument.createElement('span');
25
+ spinner.className = 'ok-native-list-spinner';
26
+ spinner.setAttribute('role', 'progressbar');
27
+ button.appendChild(spinner);
28
+ }
29
+ button.appendChild(label);
30
+ body.appendChild(button);
31
+ });
32
+ }
33
+ function create(document, row, _primitives) {
34
+ const body = document.createElement('div');
35
+ body.dataset.nlRenderer = 'buttonGroup';
36
+ bind(body, row);
37
+ return body;
38
+ }
39
+ export const buttonGroupRowRenderer = {
40
+ key: 'buttonGroup',
41
+ create,
42
+ bind,
43
+ recycle: body => body.replaceChildren(),
44
+ measure: (_row, _width) => 64,
45
+ measureRendered: body => body.scrollHeight
46
+ };
47
+ //# sourceMappingURL=ButtonGroupRowRenderer.js.map
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
 
3
- import { createElement, tagSlot } from "./RowElements.js";
3
+ import { createElement, markActionAnchorSource, setData, tagSlot } from "./RowElements.js";
4
+ import { applyValueSegments, fontWeight } from "./RowText.js";
4
5
  import { RowVisualStyle } from "./RowVisual.js";
5
6
  const views = new WeakMap();
6
7
  const tone = (value, fallback) => value === 'positive' ? 'var(--nl-positive)' : value === 'negative' ? 'var(--nl-negative)' : value === 'secondary' ? 'var(--nl-secondary)' : `var(--nl-${fallback})`;
@@ -16,6 +17,9 @@ function bind(body, row, primitives) {
16
17
  v.controls.replaceChildren();
17
18
  if (row.checkbox) v.controls.appendChild(primitives.accessory(row.key, row.checkbox, 0));
18
19
  v.controls.style.display = 'contents';
20
+ v.trailing.replaceChildren();
21
+ row.trailing?.forEach((accessory, index) => v.trailing.appendChild(primitives.accessory(row.key, accessory, index)));
22
+ v.trailing.hidden = !row.trailing?.length;
19
23
  v.index.style.cssText = '';
20
24
  v.index.hidden = row.index === undefined;
21
25
  v.index.textContent = String(row.index ?? '');
@@ -54,7 +58,26 @@ function bind(body, row, primitives) {
54
58
  if (style?.titleBadgeGap !== undefined) cell.primaryLine.style.gap = `${style.titleBadgeGap}px`;
55
59
  cell.primary.style.cssText = '';
56
60
  cell.primary.textContent = column.text;
61
+ applyValueSegments(cell.primary, column.textSegments, style?.columns?.fontSize ?? 14, style?.columns?.lineHeight ?? 20, fontWeight(style?.columns?.fontWeight, 500));
57
62
  if (style?.columns) primitives.textStyle(cell.primary, style.columns);
63
+ cell.titleIcons.replaceChildren();
64
+ if (column.titleIcon || column.secondaryTitleIcon) {
65
+ cell.primary.style.minWidth = '0';
66
+ cell.primary.style.overflow = 'hidden';
67
+ cell.primary.style.textOverflow = 'ellipsis';
68
+ cell.primary.style.whiteSpace = 'nowrap';
69
+ [column.titleIcon, column.secondaryTitleIcon].filter(icon => icon !== undefined).forEach(descriptor => {
70
+ const icon = primitives.iconAction(descriptor.name, undefined, undefined, descriptor.tintColor);
71
+ icon.className = 'ok-native-list-identity-title-icon';
72
+ if (descriptor.hoverActionKey) {
73
+ setData(icon, 'nativeListHoverAction', descriptor.hoverActionKey);
74
+ setData(icon, 'nativeListIconHelp', true);
75
+ markActionAnchorSource(icon, 'leadingAction');
76
+ }
77
+ if (descriptor.accessibilityLabel) icon.setAttribute('aria-label', descriptor.accessibilityLabel);else icon.setAttribute('aria-hidden', 'true');
78
+ cell.titleIcons.appendChild(icon);
79
+ });
80
+ }
58
81
  cell.badges.replaceChildren();
59
82
  cell.badges.style.display = 'contents';
60
83
  if (column.key === 'asset') row.badges?.forEach(badge => {
@@ -64,17 +87,22 @@ function bind(body, row, primitives) {
64
87
  });
65
88
  // Legacy Web layout: secondary leading text sits inline before the primary
66
89
  // text; secondary text is a direct line below it, toned by secondaryTone.
67
- cell.secondaryLine.style.display = column.secondaryText ? 'contents' : 'none';
68
- [column.secondaryLeadingText, column.secondaryText].forEach((text, slot) => {
90
+ const secondaryText = column.secondaryTextSegments?.length ? column.secondaryTextSegments.map(segment => segment.text).join('') : column.secondaryText;
91
+ cell.secondaryLine.style.display = secondaryText ? 'contents' : 'none';
92
+ [column.secondaryLeadingText, secondaryText].forEach((text, slot) => {
69
93
  const label = cell.secondary[slot];
70
94
  label.hidden = !text;
71
95
  if (!text) label.remove();else if (slot === 0) cell.primaryLine.insertBefore(label, cell.primary);else cell.secondaryLine.appendChild(label);
72
96
  label.style.cssText = '';
73
97
  label.textContent = text ?? '';
98
+ if (slot === 1) {
99
+ applyValueSegments(label, column.secondaryTextSegments, style?.columnSecondary?.fontSize ?? 12, style?.columnSecondary?.lineHeight ?? 16, fontWeight(style?.columnSecondary?.fontWeight, 400));
100
+ }
74
101
  if (slot === 1) label.style.color = tone(column.secondaryTone, 'secondary');
75
102
  if (style?.columnSecondary) primitives.textStyle(label, style.columnSecondary);
76
103
  });
77
104
  });
105
+ body.appendChild(v.trailing);
78
106
  }
79
107
  function create(document, row, primitives) {
80
108
  const body = createElement(document, 'div', 'ok-native-list-row ok-native-list-data');
@@ -82,6 +110,7 @@ function create(document, row, primitives) {
82
110
  const index = tagSlot(createElement(document, 'span', 'ok-native-list-index'), 'index');
83
111
  const favorite = createElement(document, 'span', 'ok-native-list-favorite');
84
112
  const controls = createElement(document, 'span');
113
+ const trailing = createElement(document, 'span', 'ok-native-list-accessories');
85
114
  body.append(controls, index, favorite);
86
115
  const columns = Array.from({
87
116
  length: 4
@@ -89,8 +118,10 @@ function create(document, row, primitives) {
89
118
  const cell = createElement(document, 'span', 'ok-native-list-data-cell');
90
119
  const primaryLine = createElement(document, 'span', 'ok-native-list-data-primary');
91
120
  const primary = tagSlot(createElement(document, 'span'), 'columns');
121
+ const titleIcons = createElement(document, 'span');
122
+ titleIcons.style.display = 'contents';
92
123
  const badges = createElement(document, 'span');
93
- primaryLine.append(primary, badges);
124
+ primaryLine.append(primary, titleIcons, badges);
94
125
  const secondaryLine = createElement(document, 'span', 'ok-native-list-data-secondary-line');
95
126
  const secondary = Array.from({
96
127
  length: 2
@@ -102,15 +133,18 @@ function create(document, row, primitives) {
102
133
  body: cell,
103
134
  primaryLine,
104
135
  primary,
136
+ titleIcons,
105
137
  badges,
106
138
  secondaryLine,
107
139
  secondary
108
140
  };
109
141
  });
142
+ body.appendChild(trailing);
110
143
  views.set(body, {
111
144
  favorite,
112
145
  index,
113
146
  controls,
147
+ trailing,
114
148
  columns,
115
149
  visualKey: '',
116
150
  primitives
@@ -129,6 +163,7 @@ function recycle(body) {
129
163
  v.visualStyle = undefined;
130
164
  v.visualKey = '';
131
165
  v.controls.replaceChildren();
166
+ v.trailing.replaceChildren();
132
167
  }
133
168
  export const dataRowRenderer = {
134
169
  key: 'dataRow',
@@ -137,7 +172,7 @@ export const dataRowRenderer = {
137
172
  recycle,
138
173
  // Legacy presets: table rows without secondary text are 8 units shorter.
139
174
  measure: (row, _width, layout) => {
140
- const secondary = row.columns.some(column => column.secondaryText);
175
+ const secondary = row.columns.some(column => column.secondaryTextSegments?.length ? column.secondaryTextSegments.some(segment => segment.text.length > 0) : !!column.secondaryText);
141
176
  return (secondary ? 60 : 56) + (layout === 'table' && !secondary ? -8 : 0);
142
177
  },
143
178
  measureRendered: (_body, _row) => undefined
@@ -100,6 +100,77 @@ function createIdentityRow(document, primitives, row) {
100
100
  });
101
101
  column.insertBefore(segments, titleElement.nextSibling);
102
102
  }
103
+ if (row.titleIcon || row.secondaryTitleIcon) {
104
+ const badgeLine = titleElement.querySelector(':scope > .ok-native-list-badges');
105
+ const titleText = createElement(document, 'span', 'ok-native-list-identity-title-text');
106
+ while (titleElement.firstChild && titleElement.firstChild !== badgeLine) titleText.appendChild(titleElement.firstChild);
107
+ titleElement.prepend(titleText);
108
+ const icons = [row.titleIcon, row.secondaryTitleIcon].filter(icon => icon !== undefined).map(descriptor => {
109
+ const icon = primitives.iconAction(descriptor.name, undefined, undefined, descriptor.tintColor);
110
+ icon.className = 'ok-native-list-identity-title-icon';
111
+ if (descriptor.hoverActionKey) {
112
+ setData(icon, 'nativeListHoverAction', descriptor.hoverActionKey);
113
+ setData(icon, 'nativeListIconHelp', true);
114
+ markActionAnchorSource(icon, 'leadingAction');
115
+ }
116
+ if (descriptor.accessibilityLabel) icon.setAttribute('aria-label', descriptor.accessibilityLabel);else icon.setAttribute('aria-hidden', 'true');
117
+ return icon;
118
+ });
119
+ titleText.after(...icons);
120
+ titleElement.style.display = 'flex';
121
+ titleElement.style.alignItems = 'center';
122
+ titleElement.style.gap = '4px';
123
+ }
124
+ if (row.titleSuffixes?.length) {
125
+ const badges = titleElement.querySelector(':scope > .ok-native-list-badges');
126
+ let titleText = titleElement.querySelector(':scope > .ok-native-list-identity-title-text, :scope > [data-nl-slot="title"]');
127
+ if (!titleText) {
128
+ titleText = tagSlot(createElement(document, 'span', 'ok-native-list-identity-title-text'), 'title');
129
+ while (titleElement.firstChild && titleElement.firstChild !== badges) titleText.appendChild(titleElement.firstChild);
130
+ titleElement.prepend(titleText);
131
+ titleElement.removeAttribute('data-nl-slot');
132
+ } else if (titleElement.hasAttribute('data-nl-slot')) {
133
+ titleElement.removeAttribute('data-nl-slot');
134
+ tagSlot(titleText, 'title');
135
+ }
136
+ titleElement.style.display = 'flex';
137
+ titleElement.style.alignItems = 'center';
138
+ titleText.style.flex = '0 1 auto';
139
+ titleText.style.minWidth = 'min(80px, 100%)';
140
+ titleText.style.overflow = 'hidden';
141
+ titleText.style.textOverflow = 'ellipsis';
142
+ titleText.style.whiteSpace = 'nowrap';
143
+ row.titleSuffixes.forEach(suffix => {
144
+ const label = createElement(document, 'span', 'ok-native-list-identity-title-suffix', suffix.text);
145
+ label.style.flex = '0 1 auto';
146
+ label.style.minWidth = '0';
147
+ label.style.marginInlineStart = row.titleIcon || row.secondaryTitleIcon ? '4px' : '8px';
148
+ label.style.maxWidth = suffix.maxWidth === undefined ? '' : `${suffix.maxWidth}px`;
149
+ label.style.overflow = 'hidden';
150
+ label.style.textOverflow = 'ellipsis';
151
+ label.style.whiteSpace = 'nowrap';
152
+ label.style.fontSize = '12px';
153
+ label.style.lineHeight = '16px';
154
+ label.style.fontWeight = '400';
155
+ label.style.fontFamily = 'var(--nl-font-regular)';
156
+ label.style.color = suffix.tone === 'disabled' ? 'var(--nl-disabled)' : 'var(--nl-secondary)';
157
+ titleElement.insertBefore(label, badges);
158
+ });
159
+ }
160
+ if (row.badges?.length && !row.titleIcon && !row.secondaryTitleIcon) {
161
+ const titleText = titleElement.querySelector(':scope > [data-nl-slot="title"]');
162
+ const badges = titleElement.querySelector(':scope > .ok-native-list-badges');
163
+ titleElement.style.display = 'flex';
164
+ titleElement.style.alignItems = 'center';
165
+ if (titleText) {
166
+ titleText.style.flex = '0 1 auto';
167
+ titleText.style.minWidth = row.titleSuffixes?.length ? 'min(80px, 100%)' : '0';
168
+ }
169
+ if (badges) {
170
+ badges.style.flex = '0 1 auto';
171
+ badges.style.minWidth = '0';
172
+ }
173
+ }
103
174
  if (presentation === 'walletSidebar' && row.badges?.length) {
104
175
  const badges = createElement(document, 'span', 'ok-native-list-wallet-badges');
105
176
  row.badges.forEach(badge => badges.appendChild(createBadge(document, badge)));
@@ -107,9 +178,9 @@ function createIdentityRow(document, primitives, row) {
107
178
  }
108
179
  for (const key of ['title', 'subtitle']) {
109
180
  const lines = row.style?.[key]?.lines ?? row[`${key}Lines`];
110
- if (lines !== undefined) column.querySelectorAll(`[data-nl-slot="${key}"]`).forEach(text => applyTextLayout(text, {
181
+ if (lines !== undefined) column.querySelectorAll(`[data-nl-slot="${key}"]`).forEach(text => applyTextLayout(text, lines === 0 ? {} : {
111
182
  lines
112
- }));
183
+ }, lines === 0 ? 0 : undefined));
113
184
  }
114
185
  }
115
186
  body.appendChild(column);
@@ -125,6 +196,17 @@ function applyIdentityStyle(body, row) {
125
196
  if (box.verticalPadding !== undefined) body.style.paddingBlock = String(box.verticalPadding) + 'px';
126
197
  const vertical = row.type === 'identity' && row.presentation === 'walletSidebar';
127
198
  const leading = body.querySelector(':scope > .ok-native-list-visual, :scope > .ok-native-list-stacked');
199
+ if (row.style?.leadingContentMaxWidthRatio !== undefined && !vertical) {
200
+ const column = body.querySelector(':scope > .ok-native-list-flex');
201
+ const trailing = body.querySelector(':scope > .ok-native-list-accessories');
202
+ const visualWidth = leading ? row.style.image?.width ?? (row.presentation === 'accountSelector' || row.presentation === 'networkSelector' ? 32 : 40) : 0;
203
+ const gap = leading ? row.style.leadingGap ?? 12 : 0;
204
+ if (column) {
205
+ column.style.flex = '0 1 auto';
206
+ column.style.maxWidth = `calc(${row.style.leadingContentMaxWidthRatio * 100}% - ${visualWidth + gap}px)`;
207
+ }
208
+ if (trailing) trailing.style.marginInlineStart = 'auto';
209
+ }
128
210
  const defaultGap = body.style.gap || (row.type === 'identity' && row.presentation === 'walletSidebar' ? '4px' : row.type === 'identity' && row.presentation === 'accountSelector' ? '8px' : '12px');
129
211
  if (box.lineGap !== undefined) {
130
212
  const targets = body.querySelectorAll(':scope > .ok-native-list-flex');
@@ -161,7 +243,7 @@ function applyIdentityStyle(body, row) {
161
243
  // Clip the bitmap itself; decorations may extend beyond the visual slot.
162
244
  leading.style.overflow = leading.matches('img') ? 'hidden' : 'visible';
163
245
  }
164
- const images = leading.matches('img') ? [leading] : leading.querySelectorAll(':scope > img, :scope > .ok-native-list-visual-fallback');
246
+ const images = leading.matches('img') ? [leading] : leading.querySelectorAll(':scope > img:not(.ok-native-list-visual-corner), :scope > .ok-native-list-visual-fallback:not(.ok-native-list-visual-corner)');
165
247
  images.forEach(bitmap => {
166
248
  if (bitmap !== leading) {
167
249
  if (image.width !== undefined) bitmap.style.width = '100%';
@@ -285,6 +367,10 @@ export const identityRowRenderer = {
285
367
  recycle,
286
368
  appliesSizePreset: row => !row.presentation,
287
369
  measure: (row, _width) => row.presentation === 'walletSidebar' ? 68 + (row.badges?.length ? 24 : 0) : row.presentation === 'networkSelector' ? 47 : row.presentation === 'accountSelector' ? 58 : row.tertiary ? 72 : row.subtitle ? 60 : 56,
288
- measureRendered: (_body, _row) => undefined
370
+ measureRendered: (body, row) => {
371
+ if (row.contentHeight !== 'auto' || hasExplicitRowHeight(row)) return undefined;
372
+ const height = body.getBoundingClientRect().height;
373
+ return height > 0 ? height : undefined;
374
+ }
289
375
  };
290
376
  //# sourceMappingURL=IdentityRowRenderer.js.map
@@ -46,6 +46,7 @@ export function bindMessageRow(body, row, primitives) {
46
46
  body.style.cssText = '';
47
47
  body.removeAttribute('data-nl-container-background');
48
48
  body.removeAttribute('data-nl-container-border');
49
+ if (row.presentation === 'inlineWarning') body.setAttribute('data-nl-inline-warning', 'true');else body.removeAttribute('data-nl-inline-warning');
49
50
  body.style.padding = `${resolved.verticalPadding}px ${resolved.horizontalPadding}px`;
50
51
  body.style.height = resolved.automaticHeight ? 'auto' : '100%';
51
52
  views.column.style.cssText = '';
@@ -53,7 +54,22 @@ export function bindMessageRow(body, row, primitives) {
53
54
  for (const [view, text] of [[views.title, resolved.title], [views.body, resolved.body], [views.time, resolved.time]]) {
54
55
  view.style.cssText = '';
55
56
  view.textContent = text.value;
56
- primitives.textStyle(view, text.style);
57
+ const {
58
+ lines,
59
+ ...textStyle
60
+ } = text.style;
61
+ primitives.textStyle(view, lines === 0 ? textStyle : {
62
+ ...textStyle,
63
+ lines
64
+ });
65
+ if (lines === 0) {
66
+ view.style.whiteSpace = 'pre-wrap';
67
+ view.style.overflow = 'visible';
68
+ view.style.textOverflow = 'clip';
69
+ view.style.maxHeight = 'none';
70
+ view.style.removeProperty('-webkit-line-clamp');
71
+ view.style.removeProperty('-webkit-box-orient');
72
+ }
57
73
  }
58
74
  views.unread.style.cssText = '';
59
75
  if (row.body) {
@@ -143,7 +159,7 @@ export function measureMessageRow(row, availableWidth) {
143
159
  if (!text.value) return 0;
144
160
  const value = text.style.lines === 1 ? text.value.replace(/\r\n|[\r\n]/g, ' ') : text.value;
145
161
  const lines = value.split(/\r\n|[\r\n]/).reduce((total, line) => total + Math.max(1, Math.ceil(Array.from(line).reduce((sum, char) => sum + (char.charCodeAt(0) > 255 ? text.style.fontSize : text.style.fontSize / 2), 0) / Math.max(1, width))), 0);
146
- return Math.min(text.style.lines, lines) * text.style.lineHeight;
162
+ return (text.style.lines === 0 ? lines : Math.min(text.style.lines, lines)) * text.style.lineHeight;
147
163
  };
148
164
  const timeWidth = Math.min(availableWidth / 3, Math.max(0, r.time.value.length * r.time.style.fontSize / 2));
149
165
  const textWidth = availableWidth - r.horizontalPadding * 2 - (row.leading ? r.imageWidth + r.leadingGap : 0) - (row.thumbnail ? 76 : 0) - (row.unread ? 19 : 0) - timeWidth - 12;
@@ -66,6 +66,7 @@ export function applyRowContainerStyle(body, row) {
66
66
  body.style.removeProperty('background-color');
67
67
  }
68
68
  if (container.cornerRadius !== undefined) set(body, 'border-radius', `${container.cornerRadius}px`);
69
+ if (row.type === 'message' && row.presentation === 'inlineWarning') set(body, 'border-radius', '0px');
69
70
  if (container.borderWidth !== undefined) {
70
71
  // Paint above member backgrounds without changing the content box or hit targets.
71
72
  body.setAttribute('data-nl-container-border', 'true');
@@ -10,6 +10,7 @@ import { dataRowRenderer } from "./DataRowRenderer.js";
10
10
  import { activityRowRenderer } from "./ActivityRowRenderer.js";
11
11
  import { systemRowRenderer } from "./SystemRowRenderer.js";
12
12
  import { actionRowRenderer } from "./ActionRowRenderer.js";
13
+ import { buttonGroupRowRenderer } from "./ButtonGroupRowRenderer.js";
13
14
  import { mediaTileRowRenderer } from "./MediaTileRowRenderer.js";
14
15
  import { messageRowRenderer } from "./MessageRowRenderer.js";
15
16
  import { railRowRenderer } from "./RailRowRenderer.js";
@@ -34,6 +35,7 @@ const factories = {
34
35
  activity: row => registration(activityRowRenderer, row),
35
36
  system: row => registration(systemRowRenderer, row),
36
37
  action: row => registration(actionRowRenderer, row),
38
+ buttonGroup: row => registration(buttonGroupRowRenderer, row),
37
39
  message: row => registration(messageRowRenderer, row),
38
40
  rail: row => registration(railRowRenderer, row),
39
41
  mediaTile: row => registration(mediaTileRowRenderer, row)
@@ -49,6 +51,7 @@ const renderers = {
49
51
  activity: activityRowRenderer,
50
52
  system: systemRowRenderer,
51
53
  action: actionRowRenderer,
54
+ buttonGroup: buttonGroupRowRenderer,
52
55
  message: messageRowRenderer,
53
56
  rail: railRowRenderer,
54
57
  mediaTile: mediaTileRowRenderer
@@ -4,6 +4,20 @@ import { applyTextWeight } from "./RowText.js";
4
4
  import { applyTabularNumbers, hasExplicitRowHeight } from "./RowElements.js";
5
5
  import { createElement, setData, tagSlot, markActionAnchorSource, createTextColumn } from "./RowElements.js";
6
6
  import { applyValueSegments } from "./RowText.js";
7
+ function bindHelp(target, help) {
8
+ markActionAnchorSource(target, 'trailingAccessory', 0);
9
+ if (help.presentation === 'tooltip') {
10
+ setData(target, 'nativeListHoverAction', help.actionKey);
11
+ setData(target, 'nativeListIconHelp', true);
12
+ } else {
13
+ setData(target, 'nativeListAction', help.actionKey);
14
+ target.setAttribute('role', 'button');
15
+ }
16
+ if (help.underline === 'dashed') {
17
+ target.style.textDecoration = 'underline dashed';
18
+ target.style.textUnderlineOffset = '4px';
19
+ }
20
+ }
7
21
  function createSectionHeader(document, primitives, row) {
8
22
  const body = createElement(document, 'div', 'ok-native-list-row ok-native-list-section');
9
23
  setData(body, 'variant', row.variant);
@@ -17,6 +31,11 @@ function createSectionHeader(document, primitives, row) {
17
31
  const column = createTextColumn(document, row.title, row.subtitle);
18
32
  const title = column.firstElementChild;
19
33
  title.classList.add('ok-native-list-section-title');
34
+ if (row.leadingBadge) {
35
+ const badge = createElement(document, 'span', 'ok-native-list-badge', row.leadingBadge.text);
36
+ if (row.leadingBadge.tone) setData(badge, 'tone', row.leadingBadge.tone);
37
+ body.appendChild(badge);
38
+ }
20
39
  if (row.titleActionKey) {
21
40
  setData(title, 'nativeListAction', row.titleActionKey);
22
41
  markActionAnchorSource(title, 'leadingAction');
@@ -31,6 +50,11 @@ function createSectionHeader(document, primitives, row) {
31
50
  }
32
51
  if (row.titleActionOnHover) setData(title, 'nativeListHoverAction', true);
33
52
  }
53
+ if (row.style?.titleDecoration === 'none') title.style.textDecoration = 'none';
54
+ if (row.style?.titleDecoration === 'dashed') {
55
+ title.style.textDecoration = 'underline dashed';
56
+ title.style.textUnderlineOffset = '4px';
57
+ }
34
58
  if (row.presentation === 'networkSelector' && hasExplicitRowHeight(row)) {
35
59
  body.style.padding = row.variant === 'summary' ? '24px 12px 20px' : '0 12px';
36
60
  body.style.backgroundColor = 'var(--nl-bg)';
@@ -108,7 +132,7 @@ function createSectionHeader(document, primitives, row) {
108
132
  body.appendChild(pendingLine);
109
133
  } else body.appendChild(column);
110
134
  if (row.value) {
111
- const value = tagSlot(createElement(document, row.valueActionKey ? 'button' : 'span', row.valueActionKey ? 'ok-native-list-action-button ok-native-list-section-value' : 'ok-native-list-value ok-native-list-section-value', row.value), 'value');
135
+ const value = tagSlot(createElement(document, row.valueActionKey || row.valueHelp?.presentation === 'popover' ? 'button' : 'span', row.valueActionKey || row.valueHelp?.presentation === 'popover' ? 'ok-native-list-action-button ok-native-list-section-value' : 'ok-native-list-value ok-native-list-section-value', row.value), 'value');
112
136
  applyValueSegments(value, row.valueSegments);
113
137
  if (row.presentation === 'networkSelector' && hasExplicitRowHeight(row)) {
114
138
  value.style.fontFamily = 'inherit';
@@ -127,7 +151,17 @@ function createSectionHeader(document, primitives, row) {
127
151
  setData(value, 'nativeListAction', row.valueActionKey);
128
152
  markActionAnchorSource(value, 'trailingAccessory', 0);
129
153
  }
130
- body.appendChild(value);
154
+ if (row.valueHelp) bindHelp(value, row.valueHelp);
155
+ if (row.style?.valuePlacement === 'afterTitle') {
156
+ value.style.marginLeft = '0';
157
+ value.style.flexShrink = '0';
158
+ value.style.alignSelf = 'center';
159
+ title.insertAdjacentElement('afterend', value);
160
+ column.style.flexDirection = 'row';
161
+ column.style.alignItems = 'center';
162
+ column.style.justifyContent = 'flex-start';
163
+ column.style.gap = '8px';
164
+ } else body.appendChild(value);
131
165
  }
132
166
  if (row.valueIcon) {
133
167
  const valueIcon = primitives.iconAction(row.valueIcon.name, row.valueIcon.actionKey, row.valueIcon.disabled, row.valueIcon.tintColor);
@@ -88,6 +88,15 @@ namespace margelo::nitro::nativelist {
88
88
  static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<jni::JString> /* containerSlotHeightsJson */)>("setContainerSlotHeightsJson");
89
89
  method(_javaPart, jni::make_jstring(containerSlotHeightsJson));
90
90
  }
91
+ std::string JHybridNativeListSpec::getSidecarLayoutJson() {
92
+ static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<jni::JString>()>("getSidecarLayoutJson");
93
+ auto __result = method(_javaPart);
94
+ return __result->toStdString();
95
+ }
96
+ void JHybridNativeListSpec::setSidecarLayoutJson(const std::string& sidecarLayoutJson) {
97
+ static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<jni::JString> /* sidecarLayoutJson */)>("setSidecarLayoutJson");
98
+ method(_javaPart, jni::make_jstring(sidecarLayoutJson));
99
+ }
91
100
  NativeListScrollEdgeEffect JHybridNativeListSpec::getTopScrollEdgeEffect() {
92
101
  static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<JNativeListScrollEdgeEffect>()>("getTopScrollEdgeEffect");
93
102
  auto __result = method(_javaPart);
@@ -252,6 +261,23 @@ namespace margelo::nitro::nativelist {
252
261
  static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<JFunc_void_std__string::javaobject> /* onVisibleRangeChanged */)>("setOnVisibleRangeChanged_cxx");
253
262
  method(_javaPart, onVisibleRangeChanged.has_value() ? JFunc_void_std__string_cxx::fromCpp(onVisibleRangeChanged.value()) : nullptr);
254
263
  }
264
+ std::optional<std::function<void(const std::string& /* payloadJson */)>> JHybridNativeListSpec::getOnStructuralTransitionSettled() {
265
+ static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<JFunc_void_std__string::javaobject>()>("getOnStructuralTransitionSettled_cxx");
266
+ auto __result = method(_javaPart);
267
+ return __result != nullptr ? std::make_optional([&]() -> std::function<void(const std::string& /* payloadJson */)> {
268
+ if (__result->isInstanceOf(JFunc_void_std__string_cxx::javaClassStatic())) [[likely]] {
269
+ auto downcast = jni::static_ref_cast<JFunc_void_std__string_cxx::javaobject>(__result);
270
+ return downcast->cthis()->getFunction();
271
+ } else {
272
+ auto __resultRef = jni::make_global(__result);
273
+ return JNICallable<JFunc_void_std__string, void(std::string)>(std::move(__resultRef));
274
+ }
275
+ }()) : std::nullopt;
276
+ }
277
+ void JHybridNativeListSpec::setOnStructuralTransitionSettled(const std::optional<std::function<void(const std::string& /* payloadJson */)>>& onStructuralTransitionSettled) {
278
+ static const auto method = _javaPart->javaClassStatic()->getMethod<void(jni::alias_ref<JFunc_void_std__string::javaobject> /* onStructuralTransitionSettled */)>("setOnStructuralTransitionSettled_cxx");
279
+ method(_javaPart, onStructuralTransitionSettled.has_value() ? JFunc_void_std__string_cxx::fromCpp(onStructuralTransitionSettled.value()) : nullptr);
280
+ }
255
281
 
256
282
  // Methods
257
283
  void JHybridNativeListSpec::applySnapshot(const std::string& snapshotJson) {
@@ -56,6 +56,8 @@ namespace margelo::nitro::nativelist {
56
56
  void setFontFamiliesJson(const std::string& fontFamiliesJson) override;
57
57
  std::string getContainerSlotHeightsJson() override;
58
58
  void setContainerSlotHeightsJson(const std::string& containerSlotHeightsJson) override;
59
+ std::string getSidecarLayoutJson() override;
60
+ void setSidecarLayoutJson(const std::string& sidecarLayoutJson) override;
59
61
  NativeListScrollEdgeEffect getTopScrollEdgeEffect() override;
60
62
  void setTopScrollEdgeEffect(NativeListScrollEdgeEffect topScrollEdgeEffect) override;
61
63
  double getTopOverlayHeight() override;
@@ -80,6 +82,8 @@ namespace margelo::nitro::nativelist {
80
82
  void setOnEndReached(const std::optional<std::function<void(const std::string& /* payloadJson */)>>& onEndReached) override;
81
83
  std::optional<std::function<void(const std::string& /* payloadJson */)>> getOnVisibleRangeChanged() override;
82
84
  void setOnVisibleRangeChanged(const std::optional<std::function<void(const std::string& /* payloadJson */)>>& onVisibleRangeChanged) override;
85
+ std::optional<std::function<void(const std::string& /* payloadJson */)>> getOnStructuralTransitionSettled() override;
86
+ void setOnStructuralTransitionSettled(const std::optional<std::function<void(const std::string& /* payloadJson */)>>& onStructuralTransitionSettled) override;
83
87
 
84
88
  public:
85
89
  // Methods
@@ -68,6 +68,11 @@ void JHybridNativeListStateUpdater::updateViewProps(jni::alias_ref<jni::JClass>
68
68
  : !newProps->containerSlotHeightsJson.hasSameValue(oldProps->containerSlotHeightsJson)) {
69
69
  hybridView->setContainerSlotHeightsJson(newProps->containerSlotHeightsJson.get());
70
70
  }
71
+ if (oldProps == nullptr
72
+ ? newProps->sidecarLayoutJson.isProvided()
73
+ : !newProps->sidecarLayoutJson.hasSameValue(oldProps->sidecarLayoutJson)) {
74
+ hybridView->setSidecarLayoutJson(newProps->sidecarLayoutJson.get());
75
+ }
71
76
  if (oldProps == nullptr
72
77
  ? newProps->topScrollEdgeEffect.isProvided()
73
78
  : !newProps->topScrollEdgeEffect.hasSameValue(oldProps->topScrollEdgeEffect)) {
@@ -128,6 +133,11 @@ void JHybridNativeListStateUpdater::updateViewProps(jni::alias_ref<jni::JClass>
128
133
  : !newProps->onVisibleRangeChanged.hasSameValue(oldProps->onVisibleRangeChanged)) {
129
134
  hybridView->setOnVisibleRangeChanged(newProps->onVisibleRangeChanged.get());
130
135
  }
136
+ if (oldProps == nullptr
137
+ ? newProps->onStructuralTransitionSettled.isProvided()
138
+ : !newProps->onStructuralTransitionSettled.hasSameValue(oldProps->onStructuralTransitionSettled)) {
139
+ hybridView->setOnStructuralTransitionSettled(newProps->onStructuralTransitionSettled.get());
140
+ }
131
141
 
132
142
  // Update hybridRef if it changed
133
143
  if (oldProps == nullptr
@@ -45,6 +45,12 @@ abstract class HybridNativeListSpec: HybridView() {
45
45
  @set:Keep
46
46
  abstract var containerSlotHeightsJson: String
47
47
 
48
+ @get:DoNotStrip
49
+ @get:Keep
50
+ @set:DoNotStrip
51
+ @set:Keep
52
+ abstract var sidecarLayoutJson: String
53
+
48
54
  @get:DoNotStrip
49
55
  @get:Keep
50
56
  @set:DoNotStrip
@@ -172,6 +178,20 @@ abstract class HybridNativeListSpec: HybridView() {
172
178
  set(value) {
173
179
  onVisibleRangeChanged = value?.let { it }
174
180
  }
181
+
182
+ abstract var onStructuralTransitionSettled: ((payloadJson: String) -> Unit)?
183
+
184
+ private var onStructuralTransitionSettled_cxx: Func_void_std__string?
185
+ @Keep
186
+ @DoNotStrip
187
+ get() {
188
+ return onStructuralTransitionSettled?.let { Func_void_std__string_java(it) }
189
+ }
190
+ @Keep
191
+ @DoNotStrip
192
+ set(value) {
193
+ onStructuralTransitionSettled = value?.let { it }
194
+ }
175
195
 
176
196
  // Methods
177
197
  @DoNotStrip