diff --git a/src/components/left/main/AccountMenuItems.tsx b/src/components/left/main/AccountMenuItems.tsx
index 70b1b9421..071887c60 100644
--- a/src/components/left/main/AccountMenuItems.tsx
+++ b/src/components/left/main/AccountMenuItems.tsx
@@ -69,7 +69,7 @@ const AccountMenuItems = ({
}, [accounts, currentCount, totalLimit]);
return (
-
+ <>
{Object.entries(accounts || {})
.sort(([, account]) => (account.userId === currentUser.id ? -1 : 1))
.map(([slot, account], index, arr) => {
@@ -116,7 +116,7 @@ const AccountMenuItems = ({
{lang('MenuAddAccount')}
)}
-
+ >
);
};
diff --git a/src/components/test/TestFragment2.tsx b/src/components/test/TestFragment2.tsx
index 4e0502408..b22d1ca8f 100644
--- a/src/components/test/TestFragment2.tsx
+++ b/src/components/test/TestFragment2.tsx
@@ -11,12 +11,7 @@ export function App() {
}}
>
Click to update
- {true && (
- <>
- {trigger && fragment}
- {trigger && content}
- >
- )}
+
This should always go last.
@@ -24,4 +19,12 @@ export function App() {
);
}
+function FragmentContainer({ items }: { items: number[] }) {
+ return (
+ <>
+ {items.map((n) => {n}
)}
+ >
+ );
+}
+
export default App;
diff --git a/src/lib/teact/teact-dom.ts b/src/lib/teact/teact-dom.ts
index d42603f2b..169f958ea 100644
--- a/src/lib/teact/teact-dom.ts
+++ b/src/lib/teact/teact-dom.ts
@@ -303,6 +303,15 @@ function mountChildren(
},
) {
const { children } = $element;
+
+ // Add a placeholder comment node for empty fragments to maintain position
+ if ($element.type === VirtualType.Fragment && children.length === 0) {
+ const fragmentEl = $element as VirtualElementFragment;
+ fragmentEl.placeholderTarget = document.createComment('empty-fragment');
+ insertBefore(options.fragment || parentEl, fragmentEl.placeholderTarget, options.nextSibling);
+ return;
+ }
+
for (let i = 0, l = children.length; i < l; i++) {
const $child = children[i];
const $renderedChild = renderWithVirtual(parentEl, undefined, $child, $element, currentContext, i, options);
@@ -390,7 +399,14 @@ function remount(
function unmountRealTree($element: VirtualElement) {
if ($element.type === VirtualType.Component) {
unmountComponent($element.componentInstance);
- } else if ($element.type !== VirtualType.Fragment) {
+ } else if ($element.type === VirtualType.Fragment) {
+ // Remove placeholder for empty fragments
+ const fragment = $element as VirtualElementFragment;
+ if (fragment.placeholderTarget && fragment.children.length === 0) {
+ fragment.placeholderTarget.parentNode?.removeChild(fragment.placeholderTarget);
+ fragment.placeholderTarget = undefined;
+ }
+ } else {
if ($element.type === VirtualType.Tag) {
extraClasses.delete($element.target!);
setElementRef($element, undefined);
@@ -419,6 +435,15 @@ function insertBefore(parentEl: DOMElement | DocumentFragment, node: Node, nextS
function getNextSibling($current: VirtualElement): ChildNode | undefined {
if ($current.type === VirtualType.Component || $current.type === VirtualType.Fragment) {
+ if ($current.children.length === 0) {
+ // For empty fragments, use the placeholder node to track position
+ const fragment = $current as VirtualElementFragment;
+ if (fragment.placeholderTarget) {
+ return fragment.placeholderTarget.nextSibling || undefined;
+ }
+ return undefined;
+ }
+
const lastChild = $current.children[$current.children.length - 1];
return getNextSibling(lastChild);
}
@@ -444,6 +469,28 @@ function renderChildren(
return;
}
+ // Handle transitions between empty and non-empty fragments
+ if ($current.type === VirtualType.Fragment && $new.type === VirtualType.Fragment) {
+ const currentFragment = $current as VirtualElementFragment;
+ const newFragment = $new as VirtualElementFragment;
+
+ // If transitioning from empty to non-empty, use the placeholder's position
+ if (currentFragment.children.length === 0 && newFragment.children.length > 0 && currentFragment.placeholderTarget) {
+ nextSibling = currentFragment.placeholderTarget.nextSibling || undefined;
+ // Remove the placeholder as we're adding real content
+ currentFragment.placeholderTarget.parentNode?.removeChild(currentFragment.placeholderTarget);
+ currentFragment.placeholderTarget = undefined;
+ }
+
+ // If transitioning from non-empty to empty, add a placeholder
+ if (currentFragment.children.length > 0 && newFragment.children.length === 0) {
+ const lastCurrentChild = currentFragment.children[currentFragment.children.length - 1];
+ const siblingAfterFragment = getNextSibling(lastCurrentChild);
+ newFragment.placeholderTarget = document.createComment('empty-fragment');
+ insertBefore(currentEl, newFragment.placeholderTarget, siblingAfterFragment);
+ }
+ }
+
const currentChildren = $current.children;
const newChildren = $new.children;
diff --git a/src/lib/teact/teact.ts b/src/lib/teact/teact.ts
index 8e3382d84..778ccf45d 100644
--- a/src/lib/teact/teact.ts
+++ b/src/lib/teact/teact.ts
@@ -56,6 +56,7 @@ export interface VirtualElementComponent {
export interface VirtualElementFragment {
type: VirtualType.Fragment;
children: VirtualElementChildren;
+ placeholderTarget?: Comment;
}
export type StateHookSetter = (newValue: ((current: T) => T) | T) => void;