Skip to content

Commit 0b2f551

Browse files
authored
Support rtl in floating.tsx (#1109)
* Support rtl in floating.tsx * changeset * minor docs rtl note * pass shift in dropdowns * fix negative x edgecase
1 parent 7733395 commit 0b2f551

File tree

5 files changed

+64
-13
lines changed

5 files changed

+64
-13
lines changed

.changeset/warm-groups-reply.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@qwik-ui/headless': patch
3+
---
4+
5+
Support rtl for elements using floating ui

apps/website/src/routes/docs/headless/popover/index.mdx

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,31 @@ title: Qwik UI | Popover
55
import { statusByComponent } from '~/_state/component-statuses';
66
import Styles from './examples/styles';
77

8-
import { ShowcaseHero, ShowcaseBasic, ShowcaseInspect, ShowcaseAuto, ShowcaseManual, ShowcaseProgrammatic, ShowcaseToggleEvent, ShowcaseFloating, ShowcasePlacement, ShowcaseCorners, ShowcaseFlip, ShowcaseGutter, ShowcaseStyling, ShowcaseAnimation, ShowcaseTransition } from './showcase-components';
9-
import { CodeSnippetFloatingCss, CodeSnippetPopoverCss, CodeSnippetBuildingBlocks } from './code-snippets';
8+
import {
9+
ShowcaseHero,
10+
ShowcaseBasic,
11+
ShowcaseInspect,
12+
ShowcaseAuto,
13+
ShowcaseManual,
14+
ShowcaseProgrammatic,
15+
ShowcaseToggleEvent,
16+
ShowcaseFloating,
17+
ShowcasePlacement,
18+
ShowcaseCorners,
19+
ShowcaseFlip,
20+
ShowcaseGutter,
21+
ShowcaseStyling,
22+
ShowcaseAnimation,
23+
ShowcaseTransition,
24+
} from './showcase-components';
25+
import {
26+
CodeSnippetFloatingCss,
27+
CodeSnippetPopoverCss,
28+
CodeSnippetBuildingBlocks,
29+
} from './code-snippets';
1030

1131
<StatusBanner status={statusByComponent.headless.Popover} />
1232

13-
1433
# Popover
1534

1635
A popup that goes above other content on the page. You can still interact with the rest of the page while the popover is open.
@@ -24,6 +43,7 @@ A popup that goes above other content on the page. You can still interact with t
2443
'Polyfill for unsupported browsers',
2544
'Executes code on interaction',
2645
'Float and position the popover',
46+
'Supports RTL',
2747
]}
2848
/>
2949

apps/website/src/routes/docs/headless/tooltip/index.mdx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,19 @@ title: Qwik UI | Tooltip
44

55
import { statusByComponent } from '~/_state/component-statuses';
66

7-
import { ShowcaseHero, ShowcaseFloating, ShowcasePlacement, ShowcaseFlip, ShowcaseGutter, ShowcaseStyling, ShowcaseAnimation, ShowcaseTransition, ShowcaseOnChange, ShowcaseBasic, ShowcaseComplex } from './showcase-components';
7+
import {
8+
ShowcaseHero,
9+
ShowcaseFloating,
10+
ShowcasePlacement,
11+
ShowcaseFlip,
12+
ShowcaseGutter,
13+
ShowcaseStyling,
14+
ShowcaseAnimation,
15+
ShowcaseTransition,
16+
ShowcaseOnChange,
17+
ShowcaseBasic,
18+
ShowcaseComplex,
19+
} from './showcase-components';
820

921
<StatusBanner status={statusByComponent.headless.Tooltip} />
1022

@@ -25,6 +37,7 @@ A text label that appears when a user hovers, focuses, or touches an element.
2537
'Accessibility with ARIA roles and keyboard interactions',
2638
'Flipping to avoid overflow',
2739
'Automatic placement adjustment',
40+
'Supports RTL',
2841
]}
2942
/>
3043

@@ -42,9 +55,7 @@ export default component$(() => {
4255
<Tooltip.Trigger>
4356
<button>Hover or Focus me</button>
4457
</Tooltip.Trigger>
45-
<Tooltip.Panel aria-label="Tooltip content">
46-
Tooltip content here
47-
</Tooltip.Panel>
58+
<Tooltip.Panel aria-label="Tooltip content">Tooltip content here</Tooltip.Panel>
4859
</Tooltip.Root>
4960
);
5061
});

packages/kit-headless/src/components/dropdown/dropdown-popover.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const HDropdownPopover = component$<PropsOf<typeof HPopoverRoot>>((props)
2323
const { showPopover, hidePopover } = usePopover(context.localId);
2424
const initialLoadSig = useSignal<boolean>(true);
2525

26-
const { floating, flip, hover, gutter, ...rest } = props;
26+
const { floating, flip, hover, gutter, shift, ...rest } = props;
2727

2828
useTask$(async ({ track }) => {
2929
track(() => context.isOpenSig.value);
@@ -103,6 +103,7 @@ export const HDropdownPopover = component$<PropsOf<typeof HPopoverRoot>>((props)
103103
manual
104104
id={context.localId}
105105
style={{ display: 'contents' }}
106+
shift={shift}
106107
>
107108
<HPopoverPanel
108109
id={menuId}

packages/kit-headless/src/components/popover/floating.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,25 @@ export const FloatingPopover = component$((props: PropsOf<'div'>) => {
6161
}).then(async (resolvedData) => {
6262
const { x, y } = resolvedData;
6363

64-
Object.assign(popover.style, {
65-
left: `${x}px`,
66-
top: `${y}px`,
67-
transform: context.transform,
68-
});
64+
const isRTL = document.documentElement.dir === 'rtl';
65+
66+
if (isRTL) {
67+
const documentWidth = document.body.getBoundingClientRect().width;
68+
const popoverWidth = popover.getBoundingClientRect().width;
69+
const boundaryX = Math.max(x, 0);
70+
71+
Object.assign(popover.style, {
72+
right: `${documentWidth - boundaryX - popoverWidth}px`,
73+
top: `${y}px`,
74+
transform: context.transform,
75+
});
76+
} else {
77+
Object.assign(popover.style, {
78+
left: `${x}px`,
79+
top: `${y}px`,
80+
transform: context.transform,
81+
});
82+
}
6983

7084
if (resolvedData.middlewareData.arrow && context.arrowRef?.value) {
7185
const { x, y } = resolvedData.middlewareData.arrow;

0 commit comments

Comments
 (0)