Skip to content

Commit

Permalink
feat: observe resize segment for better indicator display (#565)
Browse files Browse the repository at this point in the history
# Motivation

Tests in #563 were failing. After debugging, I figured out that the
potential display issue actually already existed on the main branch.
Specifically, since the segment buttons have no fixed width, depending
on the rendering, it's possible that on mount, the buttons are not yet
fully rendered—meaning they haven't occupied their full width
yet—resulting in the indicator position not being accurately calculated.
Similarly, the buttons might be rendered, but the font could take time
to load, causing the indicator position to be calculated with the
fallback font instead of the final one. Additionally, if the language is
changed at runtime, it might result in a change in the buttons' length.

Long story short, observing the size of the container and repositioning
the indicator when the size changes ensures that the indicator is always
correctly positioned.

# Changes

- Use a `ResizeObserver` to set the indicator position.
- Mock `ResizeObserver` globally for vitest

# Screenshots

Before on main:

<img width="1536" alt="Capture d’écran 2025-01-21 à 07 19 52"
src="https://github.com/user-attachments/assets/615979f4-fb10-45c1-a1c2-d841d3ea8795"
/>

After:

<img width="1536" alt="Capture d’écran 2025-01-21 à 07 19 37"
src="https://github.com/user-attachments/assets/745806a2-cf0b-497a-8924-0aa638c8aa0c"
/>

# Tests

Tests of #563 should pass.
  • Loading branch information
peterpeterparker authored Jan 21, 2025
1 parent 40efecf commit 2dbd432
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 2 deletions.
27 changes: 25 additions & 2 deletions src/lib/components/Segment.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { writable } from "svelte/store";
import type { SegmentContext, SelectedSegment } from "$lib/types/segment";
import { SEGMENT_CONTEXT_KEY } from "$lib/types/segment";
import { setContext, tick } from "svelte";
import { onDestroy, setContext, tick } from "svelte";
import { isNullish, nonNullish } from "@dfinity/utils";
export let selectedSegmentId: symbol | undefined = undefined;
Expand Down Expand Up @@ -59,14 +59,37 @@
};
};
$: selectedElement, (() => initIndicator())();
$: selectedElement, initIndicator();
// TODO: support adding segmebt buttons dynamically
let segmentsCount = 0;
$: segment,
(() =>
(segmentsCount =
segment?.querySelectorAll(".segment-button").length ?? 0))();
// The SegmentButton has a width set to 100%—i.e., not fixed. Therefore, its size might change.
// Likewise, on mount, when the segment is bound and the indicator is set for the first time, the buttons might not be fully rendered in terms of size yet.
// Furthermore, if the content of the button dynamically changes—such as in applications that support runtime translations—their size might change.
// That is why, if the overall size of the component changes, we re-evaluate the position of the indicator.
let resizeObserver: ResizeObserver | undefined;
const disconnectResizeObserver = () => resizeObserver?.disconnect();
onDestroy(disconnectResizeObserver);
const observeSegmentResize = () => {
disconnectResizeObserver();
if (isNullish(segment)) {
return;
}
resizeObserver = new ResizeObserver(initIndicator);
resizeObserver.observe(segment);
};
$: segment, observeSegmentResize();
</script>

<svelte:window on:resize={initIndicator} />
Expand Down
12 changes: 12 additions & 0 deletions vitest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,15 @@ const purify = DOMPurify(window as unknown as Window);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: used for testing only
global.DOMPurify = purify;

global.ResizeObserver = class ResizeObserver {
observe() {
// do nothing
}
unobserve() {
// do nothing
}
disconnect() {
// do nothing
}
};

0 comments on commit 2dbd432

Please sign in to comment.