1
1
import { generateID } from '@diplodoc/transform/lib/plugins/utils' ;
2
- import { Command , Plugin , PluginView , TextSelection , Transaction } from 'prosemirror-state' ;
3
- import type { Transform } from 'prosemirror-transform' ;
2
+ import { type Command , Plugin , type PluginView , TextSelection } from 'prosemirror-state' ;
4
3
import {
5
- NodeWithPos ,
4
+ type NodeWithPos ,
6
5
findChildren ,
7
6
findDomRefAtPos ,
8
7
findParentNodeOfType ,
@@ -24,7 +23,6 @@ import {get$Cursor, isTextSelection} from '../../../utils/selection';
24
23
25
24
import { TabAttrs , TabPanelAttrs } from './YfmTabsSpecs/const' ;
26
25
import {
27
- tabActiveClassname ,
28
26
tabInactiveClassname ,
29
27
tabPanelActiveClassname ,
30
28
tabPanelInactiveClassname ,
@@ -33,7 +31,7 @@ import {
33
31
tabsListType ,
34
32
tabsType ,
35
33
} from './const' ;
36
- import { atEndOfPanel } from './utils' ;
34
+ import { atEndOfPanel , execAfterPaint , switchTabByElem , switchTabById } from './utils' ;
37
35
38
36
export const dragAutoSwitch = ( ) =>
39
37
new Plugin ( {
@@ -75,10 +73,10 @@ class TabsAutoSwitchOnDragOver implements PluginView {
75
73
const pos = view . posAtCoords ( { left : event . clientX , top : event . clientY } ) ;
76
74
if ( pos ) {
77
75
const elem = findDomRefAtPos ( pos . pos , view . domAtPos . bind ( view ) ) as HTMLElement ;
78
- const cutElem = elem . closest ( TabsAutoSwitchOnDragOver . TAB_SELECTOR ) ;
79
- if ( cutElem === this . _tabElem ) return ;
76
+ const tabElem = elem . closest ( TabsAutoSwitchOnDragOver . TAB_SELECTOR ) ;
77
+ if ( tabElem === this . _tabElem ) return ;
80
78
this . _clear ( ) ;
81
- if ( cutElem ) this . _setTabElem ( cutElem as HTMLElement ) ;
79
+ if ( tabElem ) this . _setTabElem ( tabElem as HTMLElement ) ;
82
80
}
83
81
}
84
82
@@ -98,98 +96,12 @@ class TabsAutoSwitchOnDragOver implements PluginView {
98
96
99
97
private _switchTab ( ) {
100
98
if ( this . _editorView . dragging && this . _tabElem ) {
101
- const pos = this . _editorView . posAtDOM ( this . _tabElem , 0 , - 1 ) ;
102
- const $pos = this . _editorView . state . doc . resolve ( pos ) ;
103
- const { state} = this . _editorView ;
104
-
105
- let { depth} = $pos ;
106
- let tabId = '' ;
107
- let tabsNode : NodeWithPos | null = null ;
108
- do {
109
- const node = $pos . node ( depth ) ;
110
- if ( node . type === tabType ( state . schema ) ) {
111
- tabId = node . attrs [ TabAttrs . dataDiplodocid ] ;
112
- continue ;
113
- }
114
-
115
- if ( node . type === tabsType ( state . schema ) ) {
116
- tabsNode = { node, pos : $pos . before ( depth ) } ;
117
- break ;
118
- }
119
- } while ( -- depth >= 0 ) ;
120
-
121
- if ( tabId && tabsNode ) {
122
- const { tr} = state ;
123
- if ( switchYfmTab ( tabsNode , tabId , tr ) ) {
124
- this . _editorView . dispatch ( tr . setMeta ( 'addToHistory' , false ) ) ;
125
- }
126
- }
99
+ switchTabByElem ( this . _tabElem ) ;
127
100
}
128
101
this . _clear ( ) ;
129
102
}
130
103
}
131
104
132
- function switchYfmTab (
133
- { node : tabsNode , pos : tabsPos } : NodeWithPos ,
134
- tabId : string ,
135
- tr : Transform ,
136
- ) : boolean {
137
- const { schema} = tabsNode . type ;
138
- if ( tabsNode . type !== tabsType ( schema ) ) return false ;
139
-
140
- const tabsList = tabsNode . firstChild ;
141
- if ( tabsList ?. type !== tabsListType ( schema ) ) return false ;
142
-
143
- const tabsListPos = tabsPos + 1 ;
144
-
145
- let panelId : string | null = null ;
146
- tabsList . forEach ( ( node , offset ) => {
147
- if ( node . type !== tabType ( schema ) ) return ;
148
-
149
- const tabPos = tabsListPos + 1 + offset ;
150
- const tabAttrs = {
151
- ...node . attrs ,
152
- [ TabAttrs . ariaSelected ] : 'false' ,
153
- [ TabAttrs . dataDiplodocIsActive ] : 'false' ,
154
- } ;
155
-
156
- if ( node . attrs [ TabAttrs . dataDiplodocid ] === tabId ) {
157
- panelId = node . attrs [ TabAttrs . ariaControls ] ;
158
- tabAttrs [ TabAttrs . ariaSelected ] = 'true' ;
159
- tabAttrs [ TabAttrs . dataDiplodocIsActive ] = 'true' ;
160
- }
161
-
162
- tr . setNodeMarkup ( tabPos , null , tabAttrs ) ;
163
- } ) ;
164
-
165
- if ( ! panelId ) return false ;
166
-
167
- tabsNode . forEach ( ( node , offset ) => {
168
- if ( node . type !== tabPanelType ( schema ) ) return ;
169
-
170
- const tabPanelPos = tabsPos + 1 + offset ;
171
- const tabPanelAttrs = {
172
- ...node . attrs ,
173
- } ;
174
- const tabPanelClassList = new Set (
175
- ( ( node . attrs [ TabPanelAttrs . class ] as string ) ?? '' )
176
- . split ( ' ' )
177
- . filter ( ( val ) => Boolean ( val . trim ( ) ) ) ,
178
- ) ;
179
-
180
- if ( node . attrs [ TabPanelAttrs . id ] === panelId ) {
181
- tabPanelClassList . add ( 'active' ) ;
182
- } else {
183
- tabPanelClassList . delete ( 'active' ) ;
184
- }
185
-
186
- tabPanelAttrs [ TabPanelAttrs . class ] = Array . from ( tabPanelClassList ) . join ( ' ' ) ;
187
- tr . setNodeMarkup ( tabPanelPos , null , tabPanelAttrs ) ;
188
- } ) ;
189
-
190
- return true ;
191
- }
192
-
193
105
export const tabPanelArrowDown : Command = ( state , dispatch , view ) => {
194
106
const { selection : sel } = state ;
195
107
const tabsParentNode = findParentNodeOfType ( tabsType ( state . schema ) ) ( state . selection ) ;
@@ -253,36 +165,6 @@ export const liftEmptyBlockFromTabPanel: Command = (state, dispatch) => {
253
165
return false ;
254
166
} ;
255
167
256
- const makeTabsInactive = ( tabNodes : NodeWithPos [ ] , tabPanels : NodeWithPos [ ] , tr : Transaction ) => {
257
- // Find all active tabs and make them inactive
258
- const activeTabs = tabNodes . filter (
259
- ( v ) => v . node . attrs [ TabAttrs . dataDiplodocIsActive ] === 'true' ,
260
- ) ;
261
-
262
- if ( activeTabs . length ) {
263
- activeTabs . forEach ( ( tab ) => {
264
- tr . setNodeMarkup ( tab . pos , null , {
265
- ...tab . node . attrs ,
266
- class : tabInactiveClassname ,
267
- [ TabAttrs . dataDiplodocIsActive ] : 'false' ,
268
- } ) ;
269
- } ) ;
270
- }
271
-
272
- // Find all active panels and make them inactive
273
- const activePanels = tabPanels . filter (
274
- ( v ) => v . node . attrs [ TabPanelAttrs . class ] === tabPanelActiveClassname ,
275
- ) ;
276
- if ( activePanels . length ) {
277
- activePanels . forEach ( ( tabPanel ) => {
278
- tr . setNodeMarkup ( tr . mapping . map ( tabPanel . pos ) , null , {
279
- ...tabPanel . node . attrs ,
280
- class : tabPanelInactiveClassname ,
281
- } ) ;
282
- } ) ;
283
- }
284
- } ;
285
-
286
168
export const createTab : ( afterTab : NodeWithPos , tabsParentNode : NodeWithPos ) => Command =
287
169
( afterTab , tabsParentNode ) => ( state , dispatch , view ) => {
288
170
const tabNodes = findChildren (
@@ -307,16 +189,16 @@ export const createTab: (afterTab: NodeWithPos, tabsParentNode: NodeWithPos) =>
307
189
{
308
190
[ TabPanelAttrs . ariaLabelledby ] : tabId ,
309
191
[ TabPanelAttrs . id ] : panelId ,
310
- [ TabPanelAttrs . class ] : tabPanelActiveClassname ,
192
+ [ TabPanelAttrs . class ] : tabPanelInactiveClassname ,
311
193
} ,
312
194
pType ( state . schema ) . createAndFill ( ) ,
313
195
) ;
314
196
const newTab = tabType ( state . schema ) . create ( {
315
197
[ TabAttrs . id ] : tabId ,
316
198
[ TabAttrs . dataDiplodocid ] : tabId ,
317
199
[ TabAttrs . dataDiplodocKey ] : tabId ,
318
- [ TabAttrs . dataDiplodocIsActive ] : 'true ' ,
319
- [ TabAttrs . class ] : tabActiveClassname ,
200
+ [ TabAttrs . dataDiplodocIsActive ] : 'false ' ,
201
+ [ TabAttrs . class ] : tabInactiveClassname ,
320
202
[ TabAttrs . role ] : 'tab' ,
321
203
[ TabAttrs . ariaControls ] : panelId ,
322
204
} ) ;
@@ -332,8 +214,6 @@ export const createTab: (afterTab: NodeWithPos, tabsParentNode: NodeWithPos) =>
332
214
v . pos = v . pos + tabsParentNode . pos + 1 ;
333
215
} ) ;
334
216
335
- makeTabsInactive ( tabNodes , tabPanels , tr ) ;
336
-
337
217
dispatch ?.(
338
218
tr
339
219
. insert ( afterPanelNode . pos + afterPanelNode . node . nodeSize , newPanel )
@@ -345,6 +225,10 @@ export const createTab: (afterTab: NodeWithPos, tabsParentNode: NodeWithPos) =>
345
225
346
226
view ?. focus ( ) ;
347
227
228
+ if ( view ) {
229
+ execAfterPaint ( ( ) => switchTabById ( view . dom , tabId ) ) ;
230
+ }
231
+
348
232
return true ;
349
233
} ;
350
234
@@ -388,33 +272,22 @@ export const removeTab: (tabToRemove: NodeWithPos, tabsParentNode: NodeWithPos)
388
272
} ) ;
389
273
390
274
const newTabNode = tabNodes [ newTabIdx ] ;
391
-
392
- const newTabPanelNode = tabPanels [ newTabIdx ] ;
393
-
394
- makeTabsInactive ( tabNodes , tabPanels , tr ) ;
275
+ const newActiveTabId : string = newTabNode . node . attrs [ TabAttrs . dataDiplodocid ] ;
395
276
396
277
tr
397
278
// Delete panel
398
279
. delete ( panelToRemove . pos , panelToRemove . pos + panelToRemove . node . nodeSize )
399
280
// Delete tab
400
281
. delete ( tabToRemove . pos , tabToRemove . pos + tabToRemove . node . nodeSize )
401
- // Set new active tab
402
- . setNodeMarkup ( tr . mapping . map ( newTabNode . pos ) , null , {
403
- ...newTabNode . node . attrs ,
404
- class : tabActiveClassname ,
405
- [ TabAttrs . dataDiplodocIsActive ] : 'true' ,
406
- } )
407
- // Set new active panel
408
- . setNodeMarkup ( tr . mapping . map ( newTabPanelNode . pos ) , null , {
409
- ...newTabPanelNode . node . attrs ,
410
- class : tabPanelActiveClassname ,
411
- } )
412
282
. setSelection (
413
283
TextSelection . create (
414
284
tr . doc ,
415
285
tr . mapping . map ( newTabNode . pos + newTabNode . node . nodeSize - 1 ) ,
416
286
) ,
417
287
) ;
288
+
289
+ // Set new active tab
290
+ if ( view ) execAfterPaint ( ( ) => switchTabById ( view . dom , newActiveTabId ) ) ;
418
291
}
419
292
dispatch ( tr ) ;
420
293
view ?. focus ( ) ;
0 commit comments