11import { useMemo } from 'react' ;
22
3+ // eslint-disable-next-line import/no-extraneous-dependencies
4+ import type { ClientRectObject , VirtualElement } from '@floating-ui/dom' ;
35import {
46 ArrowDown ,
57 ArrowLeft ,
@@ -16,10 +18,13 @@ import {i18n} from 'src/i18n/yfm-table';
1618import type { DnDControlHandler } from '../../dnd/dnd' ;
1719import { FloatingMenu , type FloatingMenuProps } from '../FloatingMenu/FloatingMenu' ;
1820
21+ type ControlType = FloatingMenuProps [ 'dirtype' ] ;
22+
1923export type FloatingMenuControlProps = {
20- acnhorElement : Element ;
24+ cellElement : Element ;
25+ tableElement : Element ;
2126 multiple : boolean ;
22- type : FloatingMenuProps [ 'dirtype' ] ;
27+ type : ControlType ;
2328 dndHandler ?: DnDControlHandler ;
2429 onMenuOpenToggle : FloatingMenuProps [ 'onOpenToggle' ] ;
2530 onClearCellsClick : ( ) => void ;
@@ -34,7 +39,8 @@ export const FloatingMenuControl: React.FC<FloatingMenuControlProps> =
3439 type,
3540 multiple,
3641 dndHandler,
37- acnhorElement,
42+ cellElement,
43+ tableElement,
3844 onMenuOpenToggle,
3945 onClearCellsClick,
4046 onInsertBeforeClick,
@@ -94,12 +100,17 @@ export const FloatingMenuControl: React.FC<FloatingMenuControlProps> =
94100 ] ,
95101 ) ;
96102
103+ const anchor = useMemo (
104+ ( ) => getVirtualAnchor ( type , tableElement , cellElement ) ,
105+ [ type , tableElement , cellElement ] ,
106+ ) ;
107+
97108 return (
98109 < FloatingMenu
99110 dirtype = { type }
100111 canDrag = { dndHandler ? dndHandler . canDrag ( ) : false }
101112 onOpenToggle = { onMenuOpenToggle }
102- anchorElement = { acnhorElement }
113+ anchorElement = { anchor }
103114 switcherMouseProps = {
104115 dndHandler
105116 ? {
@@ -114,3 +125,73 @@ export const FloatingMenuControl: React.FC<FloatingMenuControlProps> =
114125 />
115126 ) ;
116127 } ;
128+
129+ function getVirtualAnchor (
130+ type : ControlType ,
131+ tableElem : Element ,
132+ cellElem : Element ,
133+ ) : VirtualElement {
134+ if ( type === 'row' ) {
135+ return {
136+ contextElement : cellElem ,
137+ getBoundingClientRect ( ) {
138+ const cellRect = cellElem . getBoundingClientRect ( ) ;
139+ const tableRect : ClientRectObject = tableElem . getBoundingClientRect ( ) . toJSON ( ) ;
140+
141+ {
142+ // fix table rect
143+ tableRect . x += 1 ;
144+ tableRect . width -= 2 ;
145+ tableRect . left += 1 ;
146+ tableRect . right -= 1 ;
147+ }
148+
149+ return {
150+ // from table
151+ x : tableRect . x ,
152+ width : tableRect . width ,
153+ left : tableRect . left ,
154+ right : tableRect . right ,
155+ // from cell
156+ y : cellRect . y ,
157+ height : cellRect . height ,
158+ top : cellRect . top ,
159+ bottom : cellRect . top ,
160+ } ;
161+ } ,
162+ } ;
163+ }
164+
165+ if ( type === 'column' ) {
166+ return {
167+ contextElement : cellElem ,
168+ getBoundingClientRect ( ) {
169+ const cellRect : ClientRectObject = cellElem . getBoundingClientRect ( ) . toJSON ( ) ;
170+ const tableRect = tableElem . getBoundingClientRect ( ) ;
171+
172+ const EDGE_OFFSET = 16 ;
173+
174+ const cellMiddle = cellRect . x + cellRect . width / 2 ;
175+
176+ // left border of table
177+ if ( cellMiddle - EDGE_OFFSET <= tableRect . left ) {
178+ const visible = cellRect . right - tableRect . left ;
179+ cellRect . width = ( visible - EDGE_OFFSET ) * 2 ;
180+ cellRect . left = cellRect . right - cellRect . width ;
181+ cellRect . x = cellRect . left ;
182+ }
183+
184+ // right border of table
185+ if ( cellMiddle + EDGE_OFFSET >= tableRect . right ) {
186+ const visible = tableRect . right - cellRect . left ;
187+ cellRect . width = ( visible - EDGE_OFFSET ) * 2 ;
188+ cellRect . right = cellRect . left + cellRect . width ;
189+ }
190+
191+ return cellRect ;
192+ } ,
193+ } ;
194+ }
195+
196+ throw new Error ( `Unknown control type: ${ type } ` ) ;
197+ }
0 commit comments