Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a2f0390
chore: initial commit - making elements focusable and react to enter
kbangelov Dec 15, 2025
06d2d62
feat: added some accessability with arrow logic
kbangelov Dec 19, 2025
34b18df
chore: addressed copilot stuff
kbangelov Dec 19, 2025
1c05d24
feat: refactored dropdown menu logic
kbangelov Dec 22, 2025
9914e61
feat: more dropdowns in new files and stuff
kbangelov Dec 23, 2025
328b234
chore: completed functionality and refactored code inconsistencies
kbangelov Dec 29, 2025
0c20327
chore: added aria-expanded everywhere on dropdowns
kbangelov Dec 29, 2025
6f3a80d
chore: code redacting
kbangelov Dec 29, 2025
05fb1da
chore: cleanup of isOpen logic for menus, since it is reimplemented
kbangelov Dec 29, 2025
333f1f8
chore: adjusted key press logic to match wanted functionality
kbangelov Dec 29, 2025
f1ea8f6
Merge branch 'develop' into task/uepr-445-ensure-navigable-toolbar
kbangelov Dec 30, 2025
2ce4eac
chore: post-merge accessibility readjustments
kbangelov Dec 30, 2025
fdac2f4
chore: minor code changes
kbangelov Dec 30, 2025
77f2ac6
chore: translated labels and some more adjustments
kbangelov Dec 30, 2025
3f518b5
chore: undeleted a line
kbangelov Jan 5, 2026
83bdad7
chore: moved file
kbangelov Jan 6, 2026
5640a76
chore: beginning to remove now obsolete old logic related to opening …
kbangelov Jan 7, 2026
4f92988
chore: refactored menu navigation logic via a hook
kbangelov Jan 8, 2026
287e1a5
chore: more refactoring
kbangelov Jan 8, 2026
19fef13
chore: removed old menus logic
kbangelov Jan 8, 2026
d2fd053
chore: package-lock.json back to original
kbangelov Jan 8, 2026
016f46f
chore: deleting rows
kbangelov Jan 8, 2026
d75933d
chore: refactored some menuRef, itemRef code
kbangelov Jan 9, 2026
e186ba9
chore: passing down remix message
kbangelov Jan 9, 2026
37c9974
chore: added some isRequired-s
kbangelov Jan 9, 2026
fa75484
chore: brought some elements inside file menu
kbangelov Jan 9, 2026
8626a1a
chore: fixed some aria labels
kbangelov Jan 9, 2026
965434b
chore: context is function instead of class now
kbangelov Jan 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 45 additions & 41 deletions packages/scratch-gui/src/components/gui/gui.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import DebugModal from '../debug-modal/debug-modal.jsx';
import {setPlatform} from '../../reducers/platform.js';
import {setTheme} from '../../reducers/settings.js';
import {PLATFORM} from '../../lib/platform.js';
import {MenuRefProvider} from '../../contexts/menu-ref-context.jsx';

// Cache this value to only retrieve it once the first time.
// Assume that it doesn't change for a session.
Expand Down Expand Up @@ -272,47 +273,50 @@ const GUIComponent = props => {
onRequestClose={onRequestCloseBackdropLibrary}
/>
) : null}
{!menuBarHidden && <MenuBar
ariaRole="banner"
ariaLabel="Menu topbar"
accountNavOpen={accountNavOpen}
authorId={authorId}
authorThumbnailUrl={authorThumbnailUrl}
authorUsername={authorUsername}
authorAvatarBadge={authorAvatarBadge}
canChangeLanguage={canChangeLanguage}
canChangeColorMode={canChangeColorMode}
canChangeTheme={canChangeTheme}
canCreateCopy={canCreateCopy}
canCreateNew={canCreateNew}
canEditTitle={canEditTitle}
canManageFiles={canManageFiles}
canRemix={canRemix}
canSave={canSave}
canShare={canShare}
className={styles.menuBarPosition}
enableCommunity={enableCommunity}
hasActiveMembership={hasActiveMembership}
isShared={isShared}
isTotallyNormal={isTotallyNormal}
logo={logo}
renderLogin={renderLogin}
showComingSoon={showComingSoon}
onClickAbout={onClickAbout}
onClickAccountNav={onClickAccountNav}
onClickLogo={onClickLogo}
onCloseAccountNav={onCloseAccountNav}
onLogOut={onLogOut}
onOpenRegistration={onOpenRegistration}
onProjectTelemetryEvent={onProjectTelemetryEvent}
onSeeCommunity={onSeeCommunity}
onShare={onShare}
onStartSelectingFileUpload={onStartSelectingFileUpload}
onToggleLoginOpen={onToggleLoginOpen}
userOwnsProject={userOwnsProject}
username={username}
accountMenuOptions={accountMenuOptions}
/>}
{!menuBarHidden && <MenuRefProvider>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we only need to manage menu refs on the Menu Bar level? If there are other cases where we'll be managing menu refs outside of here, we'd want to move this to an outer level - otherwise it's fine to stay as-is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose I should have done it here but I do move it in my next task. Although it is illogical in the long term, I think it's fine to stay there in this PR.

<MenuBar
ariaRole="banner"
ariaLabel="Menu topbar"
accountNavOpen={accountNavOpen}
authorId={authorId}
authorThumbnailUrl={authorThumbnailUrl}
authorUsername={authorUsername}
authorAvatarBadge={authorAvatarBadge}
canChangeLanguage={canChangeLanguage}
canChangeColorMode={canChangeColorMode}
canChangeTheme={canChangeTheme}
canCreateCopy={canCreateCopy}
canCreateNew={canCreateNew}
canEditTitle={canEditTitle}
canManageFiles={canManageFiles}
canRemix={canRemix}
canSave={canSave}
canShare={canShare}
className={styles.menuBarPosition}
enableCommunity={enableCommunity}
hasActiveMembership={hasActiveMembership}
isShared={isShared}
isTotallyNormal={isTotallyNormal}
logo={logo}
renderLogin={renderLogin}
showComingSoon={showComingSoon}
onClickAbout={onClickAbout}
onClickAccountNav={onClickAccountNav}
onClickLogo={onClickLogo}
onCloseAccountNav={onCloseAccountNav}
onLogOut={onLogOut}
onOpenRegistration={onOpenRegistration}
onProjectTelemetryEvent={onProjectTelemetryEvent}
onSeeCommunity={onSeeCommunity}
onShare={onShare}
onStartSelectingFileUpload={onStartSelectingFileUpload}
onToggleLoginOpen={onToggleLoginOpen}
userOwnsProject={userOwnsProject}
username={username}
accountMenuOptions={accountMenuOptions}
/>
</MenuRefProvider>
}
<Box className={classNames(boxStyles, styles.flexWrapper)}>
<Box
role="main"
Expand Down
131 changes: 131 additions & 0 deletions packages/scratch-gui/src/components/menu-bar/edit-menu.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import React, {useRef} from 'react';
import styles from './menu-bar.css';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';

import editIcon from './icon--edit.svg';
import {FormattedMessage, defineMessage} from 'react-intl';
import MenuBarMenu from './menu-bar-menu.jsx';
import {MenuItem, MenuSection} from '../menu/menu.jsx';
import useMenuNavigation from '../../hooks/use-menu-navigation.jsx';
import dropdownCaret from './dropdown-caret.svg';
import DeletionRestorer from '../../containers/deletion-restorer.jsx';
import TurboMode from '../../containers/turbo-mode.jsx';
import intlShape from '../../lib/intlShape.js';
import propTypes from '../../lib/prop-types.js';

const editMenu = defineMessage({
id: 'gui.aria.editMenu',
defaultMessage: 'Edit menu',
description: 'ARIA label for edit menu'
});

const EditMenu = props => {
const {
menuRef,
intl,
isRtl,
onRestoreOption,
restoreOptionMessage
} = props;

const restoreRef = useRef(null);
const turboRef = useRef(null);

const itemRefs = [restoreRef, turboRef];

const {
isExpanded,
handleKeyPress,
handleKeyPressOpenMenu,
handleOnOpen,
handleOnClose
} = useMenuNavigation({
menuRef,
itemRefs,
depth: 1
});

return (
<div
className={classNames(styles.menuBarItem, styles.hoverable, {
[styles.active]: isExpanded()
})}
onClick={handleOnOpen}
role="button"
aria-label={intl.formatMessage(editMenu)}
aria-expanded={isExpanded()}
tabIndex={0}
onKeyDown={handleKeyPress}
ref={menuRef}
>
<img src={editIcon} />
<span className={styles.collapsibleLabel}>
<FormattedMessage
defaultMessage="Edit"
description="Text for edit dropdown menu"
id="gui.menuBar.edit"
/>
</span>
<img src={dropdownCaret} />
<MenuBarMenu
className={classNames(styles.menuBarMenu)}
open={isExpanded()}
place={isRtl ? 'left' : 'right'}
onRequestClose={handleOnClose}
>
<DeletionRestorer>{(handleRestore, {restorable, deletedItem}) => (
<MenuItem
className={classNames({[styles.disabled]: !restorable})}
onClick={onRestoreOption(handleRestore)}
itemRef={restoreRef}
onParentKeyPress={handleKeyPressOpenMenu}
isDisabled={!restorable}
>
{restoreOptionMessage(deletedItem)}
</MenuItem>
)}</DeletionRestorer>
<MenuSection>
<TurboMode>{(toggleTurboMode, {turboMode}) => (
<MenuItem
onClick={toggleTurboMode}
itemRef={turboRef}
onParentKeyPress={handleKeyPressOpenMenu}
>
{turboMode ? (
<FormattedMessage
defaultMessage="Turn off Turbo Mode"
description="Menu bar item for turning off turbo mode"
id="gui.menuBar.turboModeOff"
/>
) : (
<FormattedMessage
defaultMessage="Turn on Turbo Mode"
description="Menu bar item for turning on turbo mode"
id="gui.menuBar.turboModeOn"
/>
)}
</MenuItem>
)}</TurboMode>
</MenuSection>
</MenuBarMenu>
</div>
);
};

EditMenu.propTypes = {
intl: intlShape.isRequired,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to use intl from the props you need to call injectIntl to the component, for example:

EditMenuIntl = injectIntl(EditMenu);
export default EditMenuIntl;

Same comment for the other menus where intl is used from the props.

Edit: I just noticed that you're passing it from the MenuBar component. I still think it's better to inject it here rather than passing it from the parent. By the way, if we switch to function components we can use intl from the useIntl hook.

menuRef: propTypes.ref.isRequired,
isRtl: PropTypes.bool,
restoreOptionMessage: PropTypes.func.isRequired,
onRestoreOption: PropTypes.func.isRequired
};

const mapStateToProps = state => ({
isRtl: state.locales.isRtl
});

export default connect(
mapStateToProps
)(EditMenu);
Loading