Skip to content

Commit 28a6901

Browse files
committed
feat(json-crdt-peritext-ui): 🎸 use entangled portal to position focus bottom overlay
1 parent 1dad5fb commit 28a6901

File tree

6 files changed

+58
-40
lines changed

6 files changed

+58
-40
lines changed

‎src/json-crdt-peritext-ui/plugins/toolbar/ToolbarPlugin.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {RenderPeritext, type RenderPeritextProps} from './RenderPeritext';
44
import {text} from '../minimal/text';
55
import {RenderBlock} from './block/RenderBlock';
66
import {RenderCaret} from './cursor/caret/RenderCaret';
7-
import {RenderFocus} from './cursor/RenderFocus';
7+
import {RenderFocus} from './cursor/focus/RenderFocus';
88
import type {PeritextPlugin} from '../../web/react/types';
99
import type {DebugState} from '../debug/state';
1010

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,10 @@
11
// biome-ignore lint: lint/style/useImportType
22
import * as React from 'react';
3-
import {rule} from 'nano-theme';
43
import {FormattingsManagePane} from '../../../formatting/FormattingsManagePane';
5-
import {EntangledPortal, type EntangledPortalStateOpts} from '../../../../../components/EntangledPortal';
4+
import {BottomPanePortal} from '../../util/BottomPanePortal';
65
import type {CaretViewProps} from '../../../../../web/react/cursor/CaretView';
76

8-
const spanClass = rule({
9-
pe: 'none',
10-
});
11-
12-
const gap = 4;
13-
const position: EntangledPortalStateOpts['position'] = (base, dest) => {
14-
let x = base.x - (dest.width >> 1);
15-
let y = base.y;
16-
if (x < gap) x = gap;
17-
else if (x + dest.width + gap > window.innerWidth) x = window.innerWidth - dest.width - gap;
18-
const {scrollY} = window;
19-
const body = document.body;
20-
const html = document.documentElement;
21-
const pageHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
22-
if (base.y + dest.height + scrollY > pageHeight) y = base.y - (base.y + dest.height + scrollY - pageHeight);
23-
return [x, y];
24-
};
25-
26-
const span = {className: spanClass};
27-
28-
const entangledProps = {
29-
position,
30-
span,
31-
};
32-
33-
export interface CaretBottomOverlayProps extends CaretViewProps {
34-
children: React.ReactNode;
35-
}
7+
export interface CaretBottomOverlayProps extends CaretViewProps {}
368

379
export const CaretBottomOverlay: React.FC<CaretBottomOverlayProps> = (props) => {
3810
const {fwd, bwd} = props;
@@ -41,8 +13,8 @@ export const CaretBottomOverlay: React.FC<CaretBottomOverlayProps> = (props) =>
4113
if (!inline) return;
4214

4315
return (
44-
<EntangledPortal {...entangledProps}>
16+
<BottomPanePortal>
4517
<FormattingsManagePane inline={inline} />
46-
</EntangledPortal>
18+
</BottomPanePortal>
4719
);
4820
};

‎src/json-crdt-peritext-ui/plugins/toolbar/cursor/caret/RenderCaret.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// biome-ignore lint: lint/style/useImportType
22
import * as React from 'react';
3-
import {CaretFrame} from '../CaretFrame';
3+
import {CaretFrame} from '../util/CaretFrame';
44
import {CaretTopOverlay} from './CaretTopOverlay';
55
import {CaretBottomOverlay} from './CaretBottomOverlay';
66
import type {CaretViewProps} from '../../../../web/react/cursor/CaretView';
Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import * as React from 'react';
22
import {CaretToolbar} from 'nice-ui/lib/4-card/Toolbar/ToolbarMenu/CaretToolbar';
33
import {MoveToViewport} from 'nice-ui/lib/utils/popup/MoveToViewport';
4-
import {useToolbarPlugin} from '../context';
5-
import {useSyncStore, useSyncStoreOpt, useTimeout} from '../../../web/react/hooks';
6-
import {CaretFrame} from './CaretFrame';
7-
import {FormattingsNewPane} from '../formatting/FormattingsNewPane';
8-
import type {CaretViewProps} from '../../../web/react/cursor/CaretView';
4+
import {useToolbarPlugin} from '../../context';
5+
import {useSyncStore, useSyncStoreOpt, useTimeout} from '../../../../web/react/hooks';
6+
import {CaretFrame} from '../util/CaretFrame';
7+
import {FormattingsNewPane} from '../../formatting/FormattingsNewPane';
8+
import {BottomPanePortal} from '../util/BottomPanePortal';
9+
import type {CaretViewProps} from '../../../../web/react/cursor/CaretView';
910

1011
export interface RenderFocusProps extends CaretViewProps {
1112
children: React.ReactNode;
@@ -41,7 +42,11 @@ export const RenderFocus: React.FC<RenderFocusProps> = ({children, cursor}) => {
4142
);
4243

4344
if (!!formatting && showInlineToolbarValue && !isScrubbing && toolbar.txt.editor.mainCursor() === cursor) {
44-
under = <FormattingsNewPane formatting={formatting} onSave={() => formatting.save()} />;
45+
under = (
46+
<BottomPanePortal>
47+
<FormattingsNewPane formatting={formatting} onSave={() => formatting.save()} />
48+
</BottomPanePortal>
49+
);
4550
}
4651

4752
return (
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// biome-ignore lint: lint/style/useImportType
2+
import * as React from 'react';
3+
import {rule} from 'nano-theme';
4+
import {EntangledPortal, type EntangledPortalStateOpts} from '../../../../components/EntangledPortal';
5+
6+
const spanClass = rule({
7+
pe: 'none',
8+
});
9+
10+
const gap = 4;
11+
const position: EntangledPortalStateOpts['position'] = (base, dest) => {
12+
let x = base.x - (dest.width >> 1);
13+
let y = base.y;
14+
if (x < gap) x = gap;
15+
else if (x + dest.width + gap > window.innerWidth) x = window.innerWidth - dest.width - gap;
16+
const {scrollY} = window;
17+
const body = document.body;
18+
const html = document.documentElement;
19+
const pageHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
20+
if (base.y + dest.height + scrollY > pageHeight) y = base.y - (base.y + dest.height + scrollY - pageHeight);
21+
return [x, y];
22+
};
23+
24+
const span = {className: spanClass};
25+
26+
const entangledProps = {
27+
position,
28+
span,
29+
};
30+
31+
export interface BottomPanePortalProps {
32+
children: React.ReactNode;
33+
}
34+
35+
export const BottomPanePortal: React.FC<BottomPanePortalProps> = ({children}) => {
36+
return (
37+
<EntangledPortal {...entangledProps}>
38+
{children}
39+
</EntangledPortal>
40+
);
41+
};
File renamed without changes.

0 commit comments

Comments
 (0)