@@ -82,7 +82,13 @@ const componentEditorHeaderLabel = document.querySelector('#editor-header-compon
8282const stylesEditorHeaderLabel = document . querySelector ( '#editor-header-styles span' )
8383const aiControlsToggle = document . getElementById ( 'ai-controls-toggle' )
8484const appThemeButtons = document . querySelectorAll ( '[data-app-theme]' )
85+ const workspaceTabsShell = document . getElementById ( 'workspace-tabs-shell' )
8586const workspaceTabsStrip = document . getElementById ( 'workspace-tabs-strip' )
87+ const workspaceTabAddWrap = document . getElementById ( 'workspace-tab-add-wrap' )
88+ const workspaceTabAddButton = document . getElementById ( 'workspace-tab-add' )
89+ const workspaceTabAddMenu = document . getElementById ( 'workspace-tab-add-menu' )
90+ const workspaceTabAddModule = document . getElementById ( 'workspace-tab-add-module' )
91+ const workspaceTabAddStyles = document . getElementById ( 'workspace-tab-add-styles' )
8692const editorToolsButtons = document . querySelectorAll ( '[data-editor-tools-toggle]' )
8793const panelCollapseButtons = document . querySelectorAll ( '[data-panel-collapse]' )
8894const componentEditorPanel = document . getElementById ( 'editor-panel-component' )
@@ -182,6 +188,7 @@ const editorPool = createEditorPoolManager({ maxMounted: 2 })
182188let workspaceTabRenameState = {
183189 tabId : '' ,
184190}
191+ let workspaceTabAddMenuOpen = false
185192let isRenderingWorkspaceTabs = false
186193let hasPendingWorkspaceTabsRender = false
187194const clipboardSupported = Boolean ( navigator . clipboard ?. writeText )
@@ -1407,6 +1414,7 @@ const syncEditorFromActiveWorkspaceTab = () => {
14071414}
14081415
14091416const beginWorkspaceTabRename = tabId => {
1417+ setWorkspaceTabAddMenuOpen ( false )
14101418 workspaceTabRenameState = {
14111419 tabId : toNonEmptyWorkspaceText ( tabId ) ,
14121420 }
@@ -1469,6 +1477,7 @@ const finishWorkspaceTabRename = ({ tabId, nextName, cancelled = false }) => {
14691477}
14701478
14711479const removeWorkspaceTab = tabId => {
1480+ setWorkspaceTabAddMenuOpen ( false )
14721481 const tab = workspaceTabsState . getTab ( tabId )
14731482 if ( ! tab ) {
14741483 return
@@ -1523,9 +1532,14 @@ const removeWorkspaceTab = tabId => {
15231532 } )
15241533}
15251534
1526- const addWorkspaceTab = ( ) => {
1527- const activeTab = getActiveWorkspaceTab ( )
1528- const normalizedKind = getTabKind ( activeTab ) === 'styles' ? 'styles' : 'component'
1535+ const addWorkspaceTab = kind => {
1536+ const normalizedKind =
1537+ kind === 'styles' ? 'styles' : kind === 'component' ? 'component' : ''
1538+ if ( ! normalizedKind ) {
1539+ setStatus ( 'Choose a tab type before adding a tab.' , 'neutral' )
1540+ return
1541+ }
1542+
15291543 const basePath =
15301544 normalizedKind === 'styles' ? 'src/styles/module.css' : 'src/components/module.tsx'
15311545 const language = normalizedKind === 'styles' ? 'css' : 'javascript-jsx'
@@ -1546,6 +1560,7 @@ const addWorkspaceTab = () => {
15461560 lastModified : Date . now ( ) ,
15471561 } )
15481562
1563+ setWorkspaceTabAddMenuOpen ( false )
15491564 setActiveWorkspaceTab ( tabId )
15501565
15511566 if ( normalizedKind === 'styles' ) {
@@ -1555,6 +1570,22 @@ const addWorkspaceTab = () => {
15551570 }
15561571}
15571572
1573+ const setWorkspaceTabAddMenuOpen = isOpen => {
1574+ const nextOpen = Boolean ( isOpen )
1575+ if ( workspaceTabAddMenuOpen === nextOpen ) {
1576+ return
1577+ }
1578+
1579+ workspaceTabAddMenuOpen = nextOpen
1580+ if ( workspaceTabAddButton instanceof HTMLButtonElement ) {
1581+ workspaceTabAddButton . setAttribute ( 'aria-expanded' , nextOpen ? 'true' : 'false' )
1582+ }
1583+
1584+ if ( workspaceTabAddMenu instanceof HTMLElement ) {
1585+ workspaceTabAddMenu . hidden = ! nextOpen
1586+ }
1587+ }
1588+
15581589const renderWorkspaceTabs = ( ) => {
15591590 if ( ! ( workspaceTabsStrip instanceof HTMLElement ) ) {
15601591 return
@@ -1708,17 +1739,12 @@ const renderWorkspaceTabs = () => {
17081739 workspaceTabsStrip . append ( tabContainer )
17091740 }
17101741
1711- const addButton = document . createElement ( 'button' )
1712- addButton . className = 'workspace-tab-add workspace-tab-add--strip'
1713- addButton . id = 'workspace-tab-add'
1714- addButton . type = 'button'
1715- addButton . textContent = '+'
1716- addButton . setAttribute ( 'aria-label' , 'Add tab' )
1717- addButton . title = 'Add tab'
1718- addButton . addEventListener ( 'click' , ( ) => {
1719- addWorkspaceTab ( )
1720- } )
1721- workspaceTabsStrip . append ( addButton )
1742+ if (
1743+ workspaceTabAddWrap instanceof HTMLElement &&
1744+ workspaceTabsShell instanceof HTMLElement
1745+ ) {
1746+ workspaceTabsShell . append ( workspaceTabAddWrap )
1747+ }
17221748 } finally {
17231749 isRenderingWorkspaceTabs = false
17241750 }
@@ -2977,6 +3003,56 @@ window.addEventListener('beforeunload', () => {
29773003 prDrawerController . dispose ( )
29783004} )
29793005
3006+ document . addEventListener ( 'pointerdown' , event => {
3007+ if ( ! workspaceTabAddMenuOpen ) {
3008+ return
3009+ }
3010+
3011+ const target = event . target
3012+ if ( target instanceof Element && target . closest ( '#workspace-tab-add-wrap' ) ) {
3013+ return
3014+ }
3015+
3016+ setWorkspaceTabAddMenuOpen ( false )
3017+ } )
3018+
3019+ document . addEventListener ( 'keydown' , event => {
3020+ if ( ! workspaceTabAddMenuOpen || event . key !== 'Escape' ) {
3021+ return
3022+ }
3023+
3024+ event . preventDefault ( )
3025+ setWorkspaceTabAddMenuOpen ( false )
3026+ } )
3027+
3028+ if ( workspaceTabAddButton instanceof HTMLButtonElement ) {
3029+ workspaceTabAddButton . addEventListener ( 'click' , event => {
3030+ event . stopPropagation ( )
3031+ setWorkspaceTabAddMenuOpen ( ! workspaceTabAddMenuOpen )
3032+ } )
3033+
3034+ workspaceTabAddButton . addEventListener ( 'keydown' , event => {
3035+ if ( event . key === 'ArrowDown' || event . key === 'Enter' || event . key === ' ' ) {
3036+ event . preventDefault ( )
3037+ setWorkspaceTabAddMenuOpen ( true )
3038+ }
3039+ } )
3040+ }
3041+
3042+ if ( workspaceTabAddModule instanceof HTMLButtonElement ) {
3043+ workspaceTabAddModule . addEventListener ( 'click' , event => {
3044+ event . stopPropagation ( )
3045+ addWorkspaceTab ( 'component' )
3046+ } )
3047+ }
3048+
3049+ if ( workspaceTabAddStyles instanceof HTMLButtonElement ) {
3050+ workspaceTabAddStyles . addEventListener ( 'click' , event => {
3051+ event . stopPropagation ( )
3052+ addWorkspaceTab ( 'styles' )
3053+ } )
3054+ }
3055+
29803056applyTheme ( getInitialTheme ( ) , { persist : false } )
29813057applyEditorToolsVisibility ( )
29823058applyPanelCollapseState ( )
0 commit comments