diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index 6b4bc880..8d23e377 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -20,11 +20,11 @@ jobs: - uses: actions/setup-node@v3 with: - node-version: 14.17.0 + node-version: 16.16.0 cache: yarn - name: Install Dependencies 🔧 - run: yarn + run: yarn install --immutable build_and_test: runs-on: ubuntu-latest @@ -40,11 +40,11 @@ jobs: - uses: actions/setup-node@v3 with: - node-version: 14.17.0 + node-version: 16.16.0 cache: yarn - name: Install Dependencies 🔧 - run: yarn + run: yarn install --immutable - name: Type Check ʦ run: yarn run type-check @@ -72,7 +72,7 @@ jobs: matrix: group: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] runs-on: ubuntu-latest # note: macos doesn't have docker installed! - container: cypress/browsers:node14.17.0-chrome91-ff89 + container: cypress/browsers:node16.16.0-chrome107-ff107-edge env: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} @@ -89,11 +89,11 @@ jobs: - uses: actions/setup-node@v3 with: - node-version: 14.17.0 + node-version: 16.16.0 cache: yarn - name: Install Dependencies 🔧 - run: yarn + run: yarn install --immutable - name: Run Cypress Tests ✅ if: ${{ env.IS_PR_JUST_MERGED == 'true' || env.IS_PR_WITH_PERCY == 'true' }} diff --git a/README.md b/README.md index f3d778c7..6d45b313 100644 --- a/README.md +++ b/README.md @@ -119,15 +119,15 @@ https://user-images.githubusercontent.com/3150694/232305636-e8b63780-4777-4d27-8 ❌ - Action Button + Icon Button (aka ActionButton) ✅ - Action Button with menu 🧬 + Icon Button with menu 🧬 ✅ - Action Toolbar + Toolbar ✅ diff --git a/packages/example-app/package.json b/packages/example-app/package.json index d8e964cb..70be8023 100644 --- a/packages/example-app/package.json +++ b/packages/example-app/package.json @@ -10,7 +10,6 @@ "alias": { "caf": "caf/dist/esm/index.mjs", "@intellij-platform/core/utils/tree-utils": "@intellij-platform/core/src/utils/tree-utils", - "@intellij-platform/core/ActionSystem/components": "@intellij-platform/core/src/ActionSystem/components", "@intellij-platform/core/utils/array-utils": "@intellij-platform/core/src/utils/array-utils" }, "dependencies": { diff --git a/packages/example-app/src/Project/Project.tsx b/packages/example-app/src/Project/Project.tsx index b2f46da0..12c56e61 100644 --- a/packages/example-app/src/Project/Project.tsx +++ b/packages/example-app/src/Project/Project.tsx @@ -69,9 +69,6 @@ export const Project = ({ }} windows={toolWindows} containerProps={shortcutHandlerProps} - // To make it not annoying when the whole app is a part of a bigger page. It's fine to disable focus trap, - // because the focusable element, the editor, fills the whole main content. - allowBlurOnInteractionOutside > diff --git a/packages/example-app/src/ProjectView/ProjectToolWindow.tsx b/packages/example-app/src/ProjectView/ProjectToolWindow.tsx index abb0a8af..4ac73369 100644 --- a/packages/example-app/src/ProjectView/ProjectToolWindow.tsx +++ b/packages/example-app/src/ProjectView/ProjectToolWindow.tsx @@ -1,13 +1,13 @@ import React from "react"; import { useRecoilValue } from "recoil"; import { + ActionButton, ActionDefinition, CommonActionId, DefaultToolWindow, PlatformIcon, useTreeActions, } from "@intellij-platform/core"; -import { Action } from "@intellij-platform/core/ActionSystem/components"; import { projectViewTreeRefState, @@ -33,9 +33,9 @@ export function ProjectToolWindow() { actions={[...actions, ...projectViewActions]} additionalActions={ <> - - - + + + } > diff --git a/packages/example-app/src/SearchEverywhere/SearchEverywherePopup.tsx b/packages/example-app/src/SearchEverywhere/SearchEverywherePopup.tsx index 80e2d635..074a534c 100644 --- a/packages/example-app/src/SearchEverywhere/SearchEverywherePopup.tsx +++ b/packages/example-app/src/SearchEverywhere/SearchEverywherePopup.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useMemo, useRef, useState } from "react"; import { useRecoilState, useSetRecoilState } from "recoil"; import { - ActionButton, + IconButton, ActionDefinition, ActionsProvider, FocusScope, @@ -350,9 +350,9 @@ export function SearchEverywherePopup() { {currentTabContributor?.headerFilters} - + - + diff --git a/packages/example-app/src/VersionControl/Branches/BranchesPopup.tsx b/packages/example-app/src/VersionControl/Branches/BranchesPopup.tsx index 5733b484..a16749c4 100644 --- a/packages/example-app/src/VersionControl/Branches/BranchesPopup.tsx +++ b/packages/example-app/src/VersionControl/Branches/BranchesPopup.tsx @@ -1,8 +1,8 @@ import path from "path"; import React, { useState } from "react"; import { - ActionButton, - ActionToolbar, + IconButton, + Toolbar, ActionTooltip, BalloonActionLink, Bounds, @@ -108,21 +108,21 @@ export function BranchesPopup({ onClose }: { onClose: () => void }) { {title} - + }> - { notImplemented(); onClose(); }} > - + } > - { setBranchesPopupPersistedSize(undefined); @@ -134,9 +134,9 @@ export function BranchesPopup({ onClose }: { onClose: () => void }) { }} > - + - + } diff --git a/packages/example-app/src/VersionControl/Changes/ChangesView/ActionButtons/ChangeListsActionButton.tsx b/packages/example-app/src/VersionControl/Changes/ChangesView/ActionButtons/ChangeListsActionButton.tsx index 1d07a964..379ca91f 100644 --- a/packages/example-app/src/VersionControl/Changes/ChangesView/ActionButtons/ChangeListsActionButton.tsx +++ b/packages/example-app/src/VersionControl/Changes/ChangesView/ActionButtons/ChangeListsActionButton.tsx @@ -1,11 +1,11 @@ import React from "react"; import { - ActionButtonWithMenu, + IconButtonWithMenu, PlatformIcon, useAction, } from "@intellij-platform/core"; import { VcsActionIds } from "../../../VcsActionIds"; -import { ActionsMenu } from "@intellij-platform/core/ActionSystem/components"; +import { ActionsMenu } from "@intellij-platform/core"; import { notNull } from "@intellij-platform/core/utils/array-utils"; export const ChangeListsActionButton = (): React.ReactElement => { @@ -18,12 +18,12 @@ export const ChangeListsActionButton = (): React.ReactElement => { ].filter(notNull); return ( - ( )} > - + ); }; diff --git a/packages/example-app/src/VersionControl/Changes/ChangesView/ActionButtons/GroupByActionButton.tsx b/packages/example-app/src/VersionControl/Changes/ChangesView/ActionButtons/GroupByActionButton.tsx index 58c60b59..50ac4b64 100644 --- a/packages/example-app/src/VersionControl/Changes/ChangesView/ActionButtons/GroupByActionButton.tsx +++ b/packages/example-app/src/VersionControl/Changes/ChangesView/ActionButtons/GroupByActionButton.tsx @@ -6,7 +6,7 @@ import { GroupingIds, } from "../ChangesView.state"; import { - ActionButtonWithMenu, + IconButtonWithMenu, Item, Menu, PlatformIcon, @@ -27,7 +27,7 @@ export const GroupByActionButton = (): React.ReactElement => { ); return ( - ( { )} > - + ); }; diff --git a/packages/example-app/src/VersionControl/Changes/ChangesView/ActionButtons/ViewOptionsActionButton.tsx b/packages/example-app/src/VersionControl/Changes/ChangesView/ActionButtons/ViewOptionsActionButton.tsx index 0b4fb6ec..e7731247 100644 --- a/packages/example-app/src/VersionControl/Changes/ChangesView/ActionButtons/ViewOptionsActionButton.tsx +++ b/packages/example-app/src/VersionControl/Changes/ChangesView/ActionButtons/ViewOptionsActionButton.tsx @@ -5,7 +5,7 @@ import { showRelatedFilesState, } from "../ChangesView.state"; import { - ActionButtonWithMenu, + IconButtonWithMenu, Item, Menu, PlatformIcon, @@ -21,7 +21,7 @@ export const ViewOptionsActionButton = (): React.ReactElement => { const viewOptions = { showRelatedFiles, showIgnoredFiles }; return ( - ( { )} > - + ); }; diff --git a/packages/example-app/src/VersionControl/Changes/ChangesView/ChangesViewToolbar.tsx b/packages/example-app/src/VersionControl/Changes/ChangesView/ChangesViewToolbar.tsx index 27349305..7b93462c 100644 --- a/packages/example-app/src/VersionControl/Changes/ChangesView/ChangesViewToolbar.tsx +++ b/packages/example-app/src/VersionControl/Changes/ChangesView/ChangesViewToolbar.tsx @@ -1,37 +1,37 @@ import { - ActionToolbar, - ActionToolbarSeparator, + Toolbar, + ToolbarSeparator, ActionTooltip, CommonActionId, TooltipTrigger, + ActionButton, } from "@intellij-platform/core"; import { ChangeListsActionButton } from "./ActionButtons/ChangeListsActionButton"; import { GroupByActionButton } from "./ActionButtons/GroupByActionButton"; import { ViewOptionsActionButton } from "./ActionButtons/ViewOptionsActionButton"; import React from "react"; -import { Action } from "@intellij-platform/core/ActionSystem/components"; import { VcsActionIds } from "../../VcsActionIds"; export function ChangesViewToolbar() { return ( - - - - + + + + }> - - + + }> }> - - - + + + ); } diff --git a/packages/example-app/src/VersionControl/Changes/ChangesView/ChangesViewTreeContextMenu.tsx b/packages/example-app/src/VersionControl/Changes/ChangesView/ChangesViewTreeContextMenu.tsx index cdf5d07f..2535ce6c 100644 --- a/packages/example-app/src/VersionControl/Changes/ChangesView/ChangesViewTreeContextMenu.tsx +++ b/packages/example-app/src/VersionControl/Changes/ChangesView/ChangesViewTreeContextMenu.tsx @@ -3,7 +3,7 @@ import { selectedKeysState } from "./ChangesView.state"; import { DividerItem, useAction } from "@intellij-platform/core"; import React from "react"; import { VcsActionIds } from "../../VcsActionIds"; -import { ActionsMenu } from "@intellij-platform/core/ActionSystem/components"; +import { ActionsMenu } from "@intellij-platform/core"; import { notNull } from "@intellij-platform/core/utils/array-utils"; export const ChangesViewTreeContextMenu = () => { diff --git a/packages/example-app/src/VersionControl/Changes/ChangesView/CommitActionsRow.tsx b/packages/example-app/src/VersionControl/Changes/ChangesView/CommitActionsRow.tsx index 6688023a..ed28dc6e 100644 --- a/packages/example-app/src/VersionControl/Changes/ChangesView/CommitActionsRow.tsx +++ b/packages/example-app/src/VersionControl/Changes/ChangesView/CommitActionsRow.tsx @@ -1,7 +1,7 @@ import React from "react"; import { useRecoilState, useRecoilValue } from "recoil"; import { - ActionButton, + IconButton, ActionHelpTooltip, ActionTooltip, Checkbox, @@ -68,16 +68,16 @@ export function CommitActionsRow() { } > - + - + } > - + - + diff --git a/packages/example-app/src/VersionControl/Changes/Rollback/RollbackWindow.tsx b/packages/example-app/src/VersionControl/Changes/Rollback/RollbackWindow.tsx index cc313ec3..cc58fccb 100644 --- a/packages/example-app/src/VersionControl/Changes/Rollback/RollbackWindow.tsx +++ b/packages/example-app/src/VersionControl/Changes/Rollback/RollbackWindow.tsx @@ -2,10 +2,10 @@ import React, { Key, useRef, useState } from "react"; import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"; import { Selection } from "@react-types/shared"; import { - ActionButton, - ActionButtonWithMenu, + IconButton, + IconButtonWithMenu, ActionsProvider, - ActionToolbar, + Toolbar, Button, Checkbox, CommonActionId, @@ -23,8 +23,8 @@ import { useNestedSelectionState, useTreeActions, WindowLayout, + ActionButton, } from "@intellij-platform/core"; -import { Action } from "@intellij-platform/core/ActionSystem/components"; import { changesTreeNodesState } from "../ChangesView/ChangesView.state"; import { getChangeListTreeItemProps } from "../ChangesView/changesTreeNodeRenderers"; @@ -116,11 +116,11 @@ export function RollbackWindow() { {({ shortcutHandlerProps }) => (
- - + + - - + ( - - + + - - - - + + + +
diff --git a/packages/jui/integration-tests/modal-window_menu.cy.tsx b/packages/jui/integration-tests/modal-window_menu.cy.tsx index 1f864712..29c98264 100644 --- a/packages/jui/integration-tests/modal-window_menu.cy.tsx +++ b/packages/jui/integration-tests/modal-window_menu.cy.tsx @@ -1,6 +1,6 @@ import React, { useState } from "react"; import { - ActionButton, + IconButton, FocusScope, Item, Menu, @@ -31,9 +31,9 @@ const ModalOnMenuItem = () => { )} > {(props, ref) => ( - + - + )} {isOpen && ( diff --git a/packages/jui/package.json b/packages/jui/package.json index 7e730f7d..c95c957f 100644 --- a/packages/jui/package.json +++ b/packages/jui/package.json @@ -81,7 +81,7 @@ "@babel/core": "^7.13.15", "@babel/plugin-proposal-decorators": "^7.17.12", "@babel/preset-typescript": "7.13.0", - "@percy/cli": "^1.16.0", + "@percy/cli": "^1.27.1", "@percy/cypress": "^3.1.2", "@react-stately/data": "^3.4.2", "@react-types/button": "^3.4.1", @@ -103,9 +103,9 @@ "buffer": "^6.0.3", "circular-dependency-plugin": "^5.2.2", "crypto-browserify": "^3.12.0", - "cypress": "^12.1.0", + "cypress": "^13.2.0", "cypress-plugin-snapshots": "1.4.4", - "cypress-real-events": "^1.7.4", + "cypress-real-events": "1.7.4", "hygen": "^6.2.11", "jest": "^29.0.3", "path-browserify": "^1.0.1", diff --git a/packages/jui/src/ActionButton/index.ts b/packages/jui/src/ActionButton/index.ts deleted file mode 100644 index 4b6341ed..00000000 --- a/packages/jui/src/ActionButton/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./ActionButton"; diff --git a/packages/jui/src/ActionSystem/Action.ts b/packages/jui/src/ActionSystem/Action.ts new file mode 100644 index 00000000..e22fc737 --- /dev/null +++ b/packages/jui/src/ActionSystem/Action.ts @@ -0,0 +1,72 @@ +import React from "react"; +import { Shortcut } from "@intellij-platform/core/ActionSystem/Shortcut"; + +export interface ActionContext { + element: Element | null; + /** + * UI event that triggered the action, if a shortcut triggered the action. + */ + event: + | React.MouseEvent + | React.KeyboardEvent + | null; +} + +/** + * Represents the definition of an action. + * @interface + */ +export interface ActionDefinition { + /** + * The unique identifier for the action. Used to assign shortcuts to the action, via a {@link Keymap}. + */ + id: string; + /** + * The title of an action. + * This value will be used as the text in UI display for the action. + */ + title: string; + /** + * The function that will be executed when the action is performed. + * @param context It provides further information about the action event. + */ + actionPerformed: (context: ActionContext) => void; + /** + * An optional icon for an action. + * If provided, it will be displayed along with the title in the UI. + */ + icon?: React.ReactNode; + /** + * An optional description for an action. + * If provided, it can be displayed as additional information about the action in the UI. + */ + description?: string; + /** + * An optional disable state for an action. + * If set to `true`, this action would be in disabled state and cannot be performed. + */ + isDisabled?: boolean; +} + +export interface MutableAction + extends Pick< + ActionDefinition, + "title" | "icon" | "description" | "isDisabled" + > { + id: string; + /** + * shortcuts assigned to this action based on the keymap context + */ + shortcuts: readonly Shortcut[] | undefined; + /** + * string representation of the shortcuts + */ + shortcut: string | undefined; + + /** + * Performs the action, if it's enabled. + */ + perform: (context?: ActionContext) => void; +} + +export type Action = Readonly; diff --git a/packages/jui/src/ActionSystem/ActionGroup.tsx b/packages/jui/src/ActionSystem/ActionGroup.tsx index 72c6e34c..f6cc757c 100644 --- a/packages/jui/src/ActionSystem/ActionGroup.tsx +++ b/packages/jui/src/ActionSystem/ActionGroup.tsx @@ -1,7 +1,7 @@ import { Action, ActionDefinition, -} from "@intellij-platform/core/ActionSystem/ActionsProvider"; +} from "@intellij-platform/core/ActionSystem/Action"; export type ActionInResolvedGroup = Action & { parent: ResolvedActionGroup }; diff --git a/packages/jui/src/ActionSystem/ActionsProvider.tsx b/packages/jui/src/ActionSystem/ActionsProvider.tsx index 01ca9bdf..4af23e7e 100644 --- a/packages/jui/src/ActionSystem/ActionsProvider.tsx +++ b/packages/jui/src/ActionSystem/ActionsProvider.tsx @@ -1,12 +1,11 @@ -import { - Keymap, - useKeymap, -} from "@intellij-platform/core/ActionSystem/KeymapProvider"; import { pick, sortBy } from "ramda"; import React, { HTMLAttributes, useContext, useEffect, useState } from "react"; -import { shortcutToString } from "@intellij-platform/core/ActionSystem/shortcutToString"; -import { useShortcuts } from "@intellij-platform/core/ActionSystem/useShortcut"; -import { Shortcut } from "@intellij-platform/core/ActionSystem/Shortcut"; +import { useEventCallback } from "@intellij-platform/core/utils/useEventCallback"; +import { dfsVisit } from "@intellij-platform/core/utils/tree-utils"; + +import { Keymap, useKeymap } from "./KeymapProvider"; +import { shortcutToString } from "./shortcutToString"; +import { useShortcuts } from "./useShortcut"; import { ActionGroup, ActionInResolvedGroup, @@ -14,54 +13,20 @@ import { isActionGroupDefinition, MutableActionGroup, } from "./ActionGroup"; -import { useEventCallback } from "@intellij-platform/core/utils/useEventCallback"; -import { dfsVisit } from "@intellij-platform/core/utils/tree-utils"; - -export interface ActionContext { - element: Element | null; - event: - | React.MouseEvent - | React.KeyboardEvent - | null; -} - -export interface ActionDefinition { - id: string; - title: string; - actionPerformed: ( - /** - * UI event that triggered the action, if a shortcut triggered the action. - */ - context: ActionContext - ) => void; - icon?: React.ReactNode; - description?: string; - isDisabled?: boolean; -} - -export interface MutableAction - extends Pick< - ActionDefinition, - "title" | "icon" | "description" | "isDisabled" - > { - id: string; - /** - * shortcuts assigned to this action based on the keymap context - */ - shortcuts: readonly Shortcut[] | undefined; - /** - * string representation of the shortcuts - */ - shortcut: string | undefined; +import { + Action, + ActionContext, + ActionDefinition, + MutableAction, +} from "@intellij-platform/core/ActionSystem/Action"; +/** + * Represents the properties required for the ActionsProvider component. + */ +interface ActionsProviderProps { /** - * Performs the action, if it's enabled. + * A collection of action definitions. */ - perform: (context?: ActionContext) => void; -} -export type Action = Readonly; - -interface ActionsProviderProps { actions: ActionDefinition[]; children: (args: { shortcutHandlerProps: HTMLAttributes; @@ -83,6 +48,15 @@ function generateId() { const ACTION_PROVIDER_ID_ATTRIBUTE = "data-action-provider"; const ACTION_PROVIDER_ID_DATA_PREFIX = "action_provider_id_"; const actionProvidersMap = new Map(); + +/** + * Provides a set of actions for the wrapped UI. Uses the currently provided keymap to find the shortcuts + * for each action, and passes the necessary event handlers for the shortcuts, to the `children` render function. + * + * @param {Array} props.actions - The actions to be provided. + * @param {boolean} [props.useCapture] - Specifies whether to use capture phase for event handling. + * @param {Function} props.children - Render function that accepts shortcutHandlerProps as argument. + */ export function ActionsProvider(props: ActionsProviderProps): JSX.Element { const parentContext = useContext(ActionsContext); const keymap = useKeymap(); diff --git a/packages/jui/src/ActionSystem/KeymapProvider.tsx b/packages/jui/src/ActionSystem/KeymapProvider.tsx index 586c383b..42030dc8 100644 --- a/packages/jui/src/ActionSystem/KeymapProvider.tsx +++ b/packages/jui/src/ActionSystem/KeymapProvider.tsx @@ -1,6 +1,6 @@ import React, { useContext } from "react"; -import { Shortcut } from "@intellij-platform/core/ActionSystem/Shortcut"; -import { defaultKeymap } from "@intellij-platform/core/ActionSystem/defaultKeymap"; +import { Shortcut } from "./Shortcut"; +import { defaultKeymap } from "./defaultKeymap"; export interface Keymap { [actionId: string]: ReadonlyArray; diff --git a/packages/jui/src/ActionSystem/components/ActionButton.tsx b/packages/jui/src/ActionSystem/components/ActionButton.tsx index 8a6cb676..2030548a 100644 --- a/packages/jui/src/ActionSystem/components/ActionButton.tsx +++ b/packages/jui/src/ActionSystem/components/ActionButton.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { useAction } from "@intellij-platform/core/ActionSystem"; -import { ActionButton as ActionButtonUI } from "@intellij-platform/core/ActionButton"; +import { useAction } from "@intellij-platform/core/ActionSystem/ActionsProvider"; +import { IconButton } from "@intellij-platform/core/IconButton"; import { ActionTooltip, TooltipTrigger } from "@intellij-platform/core/Tooltip"; export const ActionButton = ({ @@ -18,12 +18,12 @@ export const ActionButton = ({ return <>; } const actionButton = ( - action?.perform()} isDisabled={action.isDisabled} > {action.icon || children} - + ); if (action.title) { return ( diff --git a/packages/jui/src/ActionSystem/components/ActionGroupMenu.tsx b/packages/jui/src/ActionSystem/components/ActionGroupMenu.tsx index 51aa93a6..1eb71310 100644 --- a/packages/jui/src/ActionSystem/components/ActionGroupMenu.tsx +++ b/packages/jui/src/ActionSystem/components/ActionGroupMenu.tsx @@ -1,14 +1,12 @@ -import { ActionGroup } from "@intellij-platform/core/ActionSystem"; import React from "react"; -import { ActionMenuProps, ActionsMenu } from "./ActionsMenu"; +import { type ActionGroup } from "@intellij-platform/core/ActionSystem/ActionGroup"; +import { type ActionMenuProps, ActionsMenu } from "./ActionsMenu"; export type ActionGroupMenuProps = Omit & { actionGroup: ActionGroup; }; /** - * Renders children of an action group as a menu - * - * TODO: handle isPopup in children groups to render the child group as either a section or submenu + * Renders children of an action group as a menu. */ export const ActionGroupMenu = ({ actionGroup, diff --git a/packages/jui/src/ActionSystem/components/ActionsMenu.cy.tsx b/packages/jui/src/ActionSystem/components/ActionsMenu.cy.tsx index 5e2c5def..eafc1569 100644 --- a/packages/jui/src/ActionSystem/components/ActionsMenu.cy.tsx +++ b/packages/jui/src/ActionSystem/components/ActionsMenu.cy.tsx @@ -1,8 +1,5 @@ import React from "react"; -import { - ActionItem, - ActionsMenu, -} from "@intellij-platform/core/ActionSystem/components"; +import { ActionItem, ActionsMenu } from "@intellij-platform/core"; import { ActionGroupDefinition, ActionsProvider, @@ -75,6 +72,7 @@ describe("ActionsMenu", () => { ); cy.findByRole("menuitem", { name: "Action 1" }).should("not.exist"); + cy.findByRole("group", { name: "Action Group 1" }).should("not.exist"); cy.findByRole("menuitem", { name: "Action Group 1" }).click(); cy.findByRole("menuitem", { name: "Action 1" }); }); @@ -109,7 +107,7 @@ describe("ActionsMenu", () => { ); cy.findByRole("menuitem", { name: "Action 1" }); - cy.findByRole("group", { name: "Action Group 1" }); + cy.findByRole("group"); }); it("performs selected action", () => { diff --git a/packages/jui/src/ActionSystem/components/ActionsMenu.tsx b/packages/jui/src/ActionSystem/components/ActionsMenu.tsx index dbd963d2..f28bf973 100644 --- a/packages/jui/src/ActionSystem/components/ActionsMenu.tsx +++ b/packages/jui/src/ActionSystem/components/ActionsMenu.tsx @@ -1,13 +1,10 @@ import React from "react"; import { flatten } from "ramda"; import { Menu, MenuItemLayout } from "@intellij-platform/core/Menu"; -import { - Divider, - DividerItem, - Item, -} from "@intellij-platform/core/Collections"; -import { Action, ActionGroup } from "@intellij-platform/core/ActionSystem"; -import { Section } from "@react-stately/collections"; +import { Divider, Item, Section } from "@intellij-platform/core/Collections"; +import { DividerItem } from "@intellij-platform/core/Collections/Divider"; // Importing from /Collections breaks the build for some reason +import { type ActionGroup } from "@intellij-platform/core/ActionSystem/ActionGroup"; +import { type Action } from "@intellij-platform/core/ActionSystem/Action"; type ActionGroupAsMenuItem = Pick< ActionGroup, @@ -16,7 +13,7 @@ type ActionGroupAsMenuItem = Pick< export type ActionItem = ActionGroupAsMenuItem | Action | DividerItem; function isAction(item: ActionItem): item is Action { - return "actionPerformed" in item; + return "perform" in item; } export type ActionMenuProps = { @@ -70,7 +67,10 @@ export function renderActionAsMenuItem( const isGroup = "children" in action; if (isGroup && !action.isPopup) { return ( -
+ // `title` is intentionally not passed, as menu sections created from action groups usually don't have title. + // Maybe it should be an option? + // @ts-expect-error: hasDivider is not yet made a public API. +
{renderActionAsMenuItem}
); diff --git a/packages/jui/src/ActionSystem/components/index.ts b/packages/jui/src/ActionSystem/components/index.ts index 12338391..6291bfde 100644 --- a/packages/jui/src/ActionSystem/components/index.ts +++ b/packages/jui/src/ActionSystem/components/index.ts @@ -1,13 +1,14 @@ -import { ActionButton } from "./ActionButton"; +/** + * Action system components. Intentionally re-exported only from the root index file, and not the index.ts in + * ActionSystem. + */ +export { ActionButton } from "./ActionButton"; export { ActionsMenu, + renderActionAsMenuItem, type ActionMenuProps, type ActionItem, } from "./ActionsMenu"; export { ActionGroupMenu, type ActionGroupMenuProps } from "./ActionGroupMenu"; -export const Action = { - Button: ActionButton, -}; - export { useCreateDefaultActionGroup } from "./useCreateDefaultActionGroup"; diff --git a/packages/jui/src/ActionSystem/components/useCreateDefaultActionGroup.tsx b/packages/jui/src/ActionSystem/components/useCreateDefaultActionGroup.tsx index 3cfd3c3d..4d327491 100644 --- a/packages/jui/src/ActionSystem/components/useCreateDefaultActionGroup.tsx +++ b/packages/jui/src/ActionSystem/components/useCreateDefaultActionGroup.tsx @@ -1,17 +1,15 @@ +import { flatten } from "ramda"; import React from "react"; import { - ActionGroupDefinition, + type ActionGroupDefinition, isActionGroupDefinition, } from "@intellij-platform/core/ActionSystem/ActionGroup"; +import { useGetActionShortcut } from "@intellij-platform/core/ActionSystem/ActionShortcut"; import { Popup, usePopupManager } from "@intellij-platform/core/Popup"; -import { - ActionContext, - useGetActionShortcut, -} from "@intellij-platform/core/ActionSystem"; import { SpeedSearchMenu } from "@intellij-platform/core/Menu"; import { useEventCallback } from "@intellij-platform/core/utils/useEventCallback"; -import { renderActionAsMenuItem } from "@intellij-platform/core/ActionSystem/components/ActionsMenu"; -import { flatten } from "ramda"; +import { renderActionAsMenuItem } from "./ActionsMenu"; +import { ActionContext } from "@intellij-platform/core/ActionSystem/Action"; export const useCreateDefaultActionGroup = () => { const { show } = usePopupManager(); @@ -22,42 +20,44 @@ export const useCreateDefaultActionGroup = () => { context: ActionContext ) => { show(({ close }) => ( - { - // The need for calculating `allActions` is a consequence of the issue explained in the note above. - const allActions = flatten( - children.map((item) => - isActionGroupDefinition(item) ? item.children : item - ) - ); - const action = allActions.find((action) => action.id === key); - if (action && !action.isDisabled) { - action.actionPerformed(context); + + { + // The need for calculating `allActions` is a consequence of the issue explained in the note above. + const allActions = flatten( + children.map((item) => + isActionGroupDefinition(item) ? item.children : item + ) + ); + const action = allActions.find((action) => action.id === key); + if (action && !action.isDisabled) { + action.actionPerformed(context); + } + }} + onClose={close} + autoFocus="first" + > + {(item) => + renderActionAsMenuItem({ + ...item, + // a consequence of the issue explained in the note above. + shortcut: getActionShortcut(item.id), + }) } - }} - onClose={close} - autoFocus="first" - > - {(item) => - renderActionAsMenuItem({ - ...item, - // a consequence of the issue explained in the note above. - shortcut: getActionShortcut(item.id), - }) - } - - } - header={title} - /> + + } + header={title} + /> + )); } ); diff --git a/packages/jui/src/ActionSystem/defaultKeymap.tsx b/packages/jui/src/ActionSystem/defaultKeymap.tsx index de24ed82..41023d11 100644 --- a/packages/jui/src/ActionSystem/defaultKeymap.tsx +++ b/packages/jui/src/ActionSystem/defaultKeymap.tsx @@ -1,4 +1,3 @@ -import { Keymap } from "@intellij-platform/core/ActionSystem/KeymapProvider"; import { FOCUS_EDITOR_ACTION_ID, HIDE_ACTIVE_WINDOW_ACTION_ID, @@ -12,11 +11,17 @@ import { // For some reason importing from shorter paths doesn't work as expected in cypress ¯\_(ツ)_/¯ // Weirdly, `import *` works in that case. } from "@intellij-platform/core/ToolWindowsImpl/ToolWindowActionIds"; -import { CommonActionId } from "@intellij-platform/core/ActionSystem/CommonActionIds"; + +import { Keymap } from "./KeymapProvider"; +import { CommonActionId } from "./CommonActionIds"; // TODO: OS specific defaults // TODO: extract and export action ids // NOTE: defaultKeymap doesn't belong to ActionSystem semantically. Would be something to be moved to a separate module +/** + * Default Intellij Idea keymapping for common action ids, including tool window actions. + * @see CommonActionId + */ export const defaultKeymap: Keymap = { [RESIZE_TOOL_WINDOW_RIGHT_ACTION_ID]: [ { diff --git a/packages/jui/src/ActionSystem/index.ts b/packages/jui/src/ActionSystem/index.ts index 88a6b26c..07efa74c 100644 --- a/packages/jui/src/ActionSystem/index.ts +++ b/packages/jui/src/ActionSystem/index.ts @@ -6,3 +6,7 @@ export * from "./ActionShortcut"; export * from "./CommonActionIds"; export * from "./shortcutToString"; export * from "./ActionGroup"; +export { Action } from "@intellij-platform/core/ActionSystem/Action"; +export { MutableAction } from "@intellij-platform/core/ActionSystem/Action"; +export { ActionDefinition } from "@intellij-platform/core/ActionSystem/Action"; +export { ActionContext } from "@intellij-platform/core/ActionSystem/Action"; diff --git a/packages/jui/src/ActionSystem/useActionGroup.tsx b/packages/jui/src/ActionSystem/useActionGroup.tsx index 0a0e359e..0a4ff64d 100644 --- a/packages/jui/src/ActionSystem/useActionGroup.tsx +++ b/packages/jui/src/ActionSystem/useActionGroup.tsx @@ -1,8 +1,5 @@ import { useAction } from "./ActionsProvider"; -import { - isResolvedActionGroup, - ResolvedActionGroup, -} from "@intellij-platform/core/ActionSystem/ActionGroup"; +import { isResolvedActionGroup, ResolvedActionGroup } from "./ActionGroup"; export const useActionGroup = ( actionGroupId: string diff --git a/packages/jui/src/Balloon/index.ts b/packages/jui/src/Balloon/index.ts index 89768b64..7ce96ddd 100644 --- a/packages/jui/src/Balloon/index.ts +++ b/packages/jui/src/Balloon/index.ts @@ -1,3 +1,3 @@ export * from "./Balloon"; export * from "./BalloonManager"; -export { StyledBalloonsStack } from "@intellij-platform/core/Balloon/StyledBalloonsStack"; +export { StyledBalloonsStack } from "./StyledBalloonsStack"; diff --git a/packages/jui/src/Checkbox/Checkbox.cy.tsx b/packages/jui/src/Checkbox/Checkbox.cy.tsx index f37285f6..6aef6491 100644 --- a/packages/jui/src/Checkbox/Checkbox.cy.tsx +++ b/packages/jui/src/Checkbox/Checkbox.cy.tsx @@ -40,7 +40,7 @@ describe("Checkbox", () => { ); cy.get("#dummyInput").focus(); // tabbing to the text input cy.realPress("Tab"); // next tab should move focus to the checkbox - cy.focused().should("have.attr", "type", "checkbox"); + cy.findByRole("checkbox").should("be.focused"); cy.mount(
@@ -50,7 +50,7 @@ describe("Checkbox", () => { ); cy.get("#dummyInput").focus(); // tabbing to the text input cy.realPress("Tab"); // next tab should not focus the checkbox since excludeFromTabOrder is passed - cy.focused().should("not.exist"); + cy.findByRole("checkbox").should("not.be.focused"); }); it("supports preventFocus", () => { diff --git a/packages/jui/src/Checkbox/Checkbox.tsx b/packages/jui/src/Checkbox/Checkbox.tsx index f4bb2b14..de2c3064 100644 --- a/packages/jui/src/Checkbox/Checkbox.tsx +++ b/packages/jui/src/Checkbox/Checkbox.tsx @@ -28,7 +28,7 @@ export interface CheckboxProps * a questionably better UX. * Note: Passing {@link excludeFromTabOrder} will still let the checkbox be focusable, while `preventFocus`, doesn't * let the component get focused at all. - * TODO(potential): it might be nicer to have a `preventFocusOnPress` prop consistent with ActionButton, instead. + * TODO(potential): it might be nicer to have a `preventFocusOnPress` prop consistent with IconButton, instead. * In that case preventing focus completely would be achieved with `preventFocusOnPres` and `excludeFromTabOrder`. */ preventFocus?: boolean; diff --git a/packages/jui/src/Collections/Divider.ts b/packages/jui/src/Collections/Divider.ts index 7a8a604f..b656f223 100644 --- a/packages/jui/src/Collections/Divider.ts +++ b/packages/jui/src/Collections/Divider.ts @@ -15,6 +15,19 @@ import { ItemProps } from "@react-types/shared"; import { PartialNode } from "@react-stately/collections"; interface DividerProps {} + +/** + * To be used in dynamic collections, just to provide a key and make it easy to check in the render + * function to figure out what to render (an Item or a Divider) + */ +export class DividerItem { + private static seq = 0; + key = "divider_" + DividerItem.seq++; + get id() { + return this.key; + } +} + function Divider({}: DividerProps): ReactElement { // eslint-disable-line @typescript-eslint/no-unused-vars return null as any; @@ -36,15 +49,3 @@ Divider.getCollectionNode = function* getCollectionNode( hasChildNodes: false, }; }; - -/** - * To be used in dynamic collections, just to provide a key and make it easy to check in the render - * function to figure out what to render (an Item or a Divider) - */ -export class DividerItem { - private static seq = 0; - key = "divider_" + DividerItem.seq++; - get id() { - return this.key; - } -} diff --git a/packages/jui/src/ActionButton/ActionButton.tsx b/packages/jui/src/IconButton/IconButton.tsx similarity index 85% rename from packages/jui/src/ActionButton/ActionButton.tsx rename to packages/jui/src/IconButton/IconButton.tsx index 6946e2cd..4f6e282c 100644 --- a/packages/jui/src/ActionButton/ActionButton.tsx +++ b/packages/jui/src/IconButton/IconButton.tsx @@ -4,7 +4,7 @@ import { styled } from "../styled"; import { mergeProps, useObjectRef } from "@react-aria/utils"; import { useFocusable } from "@react-aria/focus"; -export interface ActionButtonProps +export interface IconButtonProps extends PressProps, // Maybe we should allow any arbitrary HTMLProps props, instead of whitelisting? Pick< @@ -12,10 +12,13 @@ export interface ActionButtonProps "onFocus" | "onBlur" | "style" | "className" > { children?: React.ReactNode; + /** + * The minimum width/height of the button. + */ minSize?: number; /** - * Whether the button should be focusable by pressing tab. The default is true for action buttons, which means they - * are not included in the tab order. + * Whether the button should be focusable by pressing tab. The default is true for icon buttons (aka. action buttons), + * which means they are not included in the tab order. */ excludeFromTabOrder?: boolean; } @@ -23,7 +26,7 @@ export interface ActionButtonProps export const DEFAULT_MINIMUM_BUTTON_SIZE = 22; export const NAVBAR_MINIMUM_BUTTON_SIZE = 20; -export const StyledActionButton = styled.button<{ minSize: number }>` +export const StyledIconButton = styled.button<{ minSize: number }>` position: relative; // to allow absolutely positioned overlays like an dropdown icon at the bottom right corner background: none; color: inherit; @@ -58,7 +61,11 @@ export const StyledActionButton = styled.button<{ minSize: number }>` } `; -export const ActionButton = React.forwardRef(function ActionButton( +/** + * Icon button, aka Action Button, in the reference implementation. + * @see https://jetbrains.github.io/ui/controls/icon_button/ + */ +export const IconButton = React.forwardRef(function IconButton( { minSize = DEFAULT_MINIMUM_BUTTON_SIZE, preventFocusOnPress = true, @@ -72,7 +79,7 @@ export const ActionButton = React.forwardRef(function ActionButton( onPressUp, shouldCancelOnPointerExit, ...otherProps - }: ActionButtonProps, + }: IconButtonProps, forwardedRef: ForwardedRef ) { // FIXME: use useButton @@ -93,7 +100,7 @@ export const ActionButton = React.forwardRef(function ActionButton( }); return ( - & { /** * whether the default arrow should be removed or not. false by default. @@ -22,22 +22,22 @@ type ActionButtonWithMenuProps = ActionButtonProps & noArrow?: boolean; }; /** - * Renders an ActionButton which opens a menu. by default a down arrow icon is shown as an overlay on the rendered + * Renders an IconButton which opens a menu. by default a down arrow icon is shown as an overlay on the rendered * icon, but it can be disabled by passing `noArrow`. It also restores the focus to the previously focused element, * when the menu is closed. * @param renderMenu: render prop for rendering the menu - * @param children: the content of the action button + * @param children: the content of the icon button * @param noArrow: whether the default arrow should be removed or not. false by default. - * @param buttonProps: the rest of the props that will be passed down to ActionButton + * @param buttonProps: the rest of the props that will be passed down to IconButton * * TODO: Add story and write test for focus restoration, noArrow, and basic functionality. */ -export const ActionButtonWithMenu = ({ +export const IconButtonWithMenu = ({ renderMenu, children, noArrow = false, ...buttonProps -}: ActionButtonWithMenuProps) => { +}: IconButtonWithMenuProps) => { const previouslyFocusedElementRef = useRef(); return ( {(props, ref) => ( - { if (e.relatedTarget && e.relatedTarget instanceof HTMLElement) { @@ -61,7 +61,7 @@ export const ActionButtonWithMenu = ({ > {children} {!noArrow && } - + )} ); diff --git a/packages/jui/src/Menu/Menu.cy.tsx b/packages/jui/src/Menu/Menu.cy.tsx index 8aa21db2..16428b12 100644 --- a/packages/jui/src/Menu/Menu.cy.tsx +++ b/packages/jui/src/Menu/Menu.cy.tsx @@ -734,9 +734,11 @@ describe("ContextMenu", () => { // to viewport. cy.mount(); cy.scrollTo("bottom", { duration: 0 }); - cy.get("#context-menu-container").rightclick("bottomRight", { - scrollBehavior: false, - }); + cy.get("#context-menu-container") + .realMouseMove(0, 0) // this fixes a flakiness in screenshots, which depends on whether other test cases are run before this + .rightclick("bottomRight", { + scrollBehavior: false, + }); matchImageSnapshot("context-menu-opened"); }); diff --git a/packages/jui/src/Menu/Menu.stories.tsx b/packages/jui/src/Menu/Menu.stories.tsx index f8495f7d..89900912 100644 --- a/packages/jui/src/Menu/Menu.stories.tsx +++ b/packages/jui/src/Menu/Menu.stories.tsx @@ -3,8 +3,8 @@ import { StoryObj, StoryFn, Meta } from "@storybook/react"; import { Item } from "@react-stately/collections"; import { ContextMenuContainer, styled } from "@intellij-platform/core"; -import { ActionButton } from "../ActionButton"; -import { ActionToolbar } from "../ActionToolbar/ActionToolbar"; +import { IconButton } from "../IconButton"; +import { Toolbar } from "../Toolbar/Toolbar"; import { Divider, DividerItem } from "../Collections/Divider"; import { PlatformIcon } from "../Icon"; import { styledComponentsControlsExclude } from "../story-helpers"; @@ -198,7 +198,7 @@ export const MenuWithTrigger: StoryObj< : undefined, }} > - + ( @@ -216,12 +216,12 @@ export const MenuWithTrigger: StoryObj< )} > {(props, ref) => ( - + - + )} - +
); }, diff --git a/packages/jui/src/Menu/SpeedSearchMenu.stories.tsx b/packages/jui/src/Menu/SpeedSearchMenu.stories.tsx index b059eeb3..95b29b0c 100644 --- a/packages/jui/src/Menu/SpeedSearchMenu.stories.tsx +++ b/packages/jui/src/Menu/SpeedSearchMenu.stories.tsx @@ -2,11 +2,7 @@ import React from "react"; import { Meta, StoryFn } from "@storybook/react"; import { PlatformIcon } from "@intellij-platform/core/Icon"; import { DividerItem, Item } from "@intellij-platform/core/Collections"; -import { - ActionButton, - ActionToolbar, - MenuTrigger, -} from "@intellij-platform/core"; +import { IconButton, Toolbar, MenuTrigger } from "@intellij-platform/core"; import { Section } from "@react-stately/collections"; import { styledComponentsControlsExclude } from "../story-helpers"; @@ -93,7 +89,7 @@ export const WithTrigger = { menuProps: Partial>; }) => { return ( - + ( {(props, ref) => ( - + - + )} - + ); }, }; diff --git a/packages/jui/src/Menu/SpeedSearchMenu.tsx b/packages/jui/src/Menu/SpeedSearchMenu.tsx index 9b3c781c..98c7a17f 100644 --- a/packages/jui/src/Menu/SpeedSearchMenu.tsx +++ b/packages/jui/src/Menu/SpeedSearchMenu.tsx @@ -127,27 +127,38 @@ function useSpeedSearchMenu( } }); - const lastSize = useRef({ width: 0, height: 0 }); + const lastSize = useRef<{ width: number; height: number } | null>(null); const [size, setSize] = useState<{ width: number; height: number } | null>( null ); + const measureSize = () => { + const { offsetWidth = 0, offsetHeight = 0 } = containerRef.current || {}; + if (offsetWidth > 0 && offsetHeight > 0) { + lastSize.current = { + width: offsetWidth, + height: offsetHeight, + }; + } + }; const isSearchActive = speedSearch.active && speedSearch.searchTerm.length > 0; useResizeObserver({ ref: containerRef, onResize: useEventCallback(() => { if (!isSearchActive) { - lastSize.current = { - width: containerRef.current?.offsetWidth ?? 0, - height: containerRef.current?.offsetHeight ?? 0, - }; + measureSize(); } }), }); useLayoutEffect(() => { if (isSearchActive) { - setSize(lastSize.current); + if (lastSize.current) { + setSize(lastSize.current); + } } else { + if (!lastSize.current) { + measureSize(); + } setSize(null); } }, [isSearchActive]); diff --git a/packages/jui/src/Menu/renderMenuNodes.tsx b/packages/jui/src/Menu/renderMenuNodes.tsx index 616674d0..cfaa2f4c 100644 --- a/packages/jui/src/Menu/renderMenuNodes.tsx +++ b/packages/jui/src/Menu/renderMenuNodes.tsx @@ -17,12 +17,17 @@ export function renderMenuNodes( return ; case "section": return ( - + <> + {node.props.hasDivider && ( + + )} + + ); case "divider": return ; diff --git a/packages/jui/src/ModalWindow/ModalWindow.stories.tsx b/packages/jui/src/ModalWindow/ModalWindow.stories.tsx index 3b334b6b..6e766ea6 100644 --- a/packages/jui/src/ModalWindow/ModalWindow.stories.tsx +++ b/packages/jui/src/ModalWindow/ModalWindow.stories.tsx @@ -4,8 +4,8 @@ import { ModalWindow, ModalWindowProps } from "./ModalWindow"; import { SpeedSearchTreeSample } from "@intellij-platform/core/story-components"; import { Bounds, containedWithin } from "@intellij-platform/core/Overlay"; import { - ActionButton, - ActionToolbar, + IconButton, + Toolbar, Button, Checkbox, PlatformIcon, @@ -234,23 +234,23 @@ export const WithTallFooter: StoryObj = { content={
- - + + - - + + - - + + - - + + - - + + - - + +
diff --git a/packages/jui/src/Popup/Popup.stories.tsx b/packages/jui/src/Popup/Popup.stories.tsx index 06cfea86..a0e27b17 100644 --- a/packages/jui/src/Popup/Popup.stories.tsx +++ b/packages/jui/src/Popup/Popup.stories.tsx @@ -1,7 +1,7 @@ import React from "react"; import { Meta, StoryFn, StoryObj } from "@storybook/react"; import { - ActionButton, + IconButton, Checkbox, FocusScope, PlatformIcon, @@ -197,9 +197,9 @@ export const CustomHeader: StoryObj = { 6+ usages - + - + } diff --git a/packages/jui/src/Popup/PopupManager.tsx b/packages/jui/src/Popup/PopupManager.tsx index e53b0c5e..6dd997ff 100644 --- a/packages/jui/src/Popup/PopupManager.tsx +++ b/packages/jui/src/Popup/PopupManager.tsx @@ -7,7 +7,6 @@ import React, { useState, } from "react"; import { Popup, PopupProps } from "./Popup"; -import { props } from "ramda"; import { PopupControllerContext } from "@intellij-platform/core/Popup/PopupContext"; interface PopupManagerAPI { diff --git a/packages/jui/src/Popup/PopupTrigger.stories.tsx b/packages/jui/src/Popup/PopupTrigger.stories.tsx index f3a27525..906e4675 100644 --- a/packages/jui/src/Popup/PopupTrigger.stories.tsx +++ b/packages/jui/src/Popup/PopupTrigger.stories.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import { Meta, StoryFn, StoryObj } from "@storybook/react"; import { - ActionButton, + IconButton, Checkbox, PlatformIcon, Popup, @@ -20,9 +20,9 @@ export default { component: PopupTrigger, args: { children: ( - + - + ), popup: ( diff --git a/packages/jui/src/Popup/PopupTrigger.tsx b/packages/jui/src/Popup/PopupTrigger.tsx index d02f1656..335e9f72 100644 --- a/packages/jui/src/Popup/PopupTrigger.tsx +++ b/packages/jui/src/Popup/PopupTrigger.tsx @@ -22,7 +22,7 @@ export interface PopupTriggerProps /** * Popup opened by a trigger. `trigger` can be an element of any pressable component (such as {@link Button} or - * {@link ActionButton}), and is rendered in place. Similar to {@link Popup component}, `children` defines the content + * {@link IconButton}), and is rendered in place. Similar to {@link Popup component}, `children` defines the content * of Popup. */ export const PopupTrigger = React.forwardRef(function PopupTrigger( diff --git a/packages/jui/src/Tabs/TabsOverflowMenu.tsx b/packages/jui/src/Tabs/TabsOverflowMenu.tsx index fa2a5fa4..2fd57a38 100644 --- a/packages/jui/src/Tabs/TabsOverflowMenu.tsx +++ b/packages/jui/src/Tabs/TabsOverflowMenu.tsx @@ -1,7 +1,7 @@ import { Collection, Node } from "@react-types/shared"; import { Item } from "@react-stately/collections"; import { Menu, MenuTrigger } from "@intellij-platform/core/Menu"; -import { ActionButton } from "@intellij-platform/core/ActionButton"; +import { IconButton } from "@intellij-platform/core/IconButton"; import { PlatformIcon } from "@intellij-platform/core/Icon"; import React, { Key } from "react"; @@ -40,9 +40,9 @@ export const TabsOverflowMenu = ({ }} > {(props, ref) => ( - + - + )} )} diff --git a/packages/jui/src/ToolWindows/ToolWindowStripe.tsx b/packages/jui/src/ToolWindows/ToolWindowStripe.tsx index e35b7246..dad7cfe8 100644 --- a/packages/jui/src/ToolWindows/ToolWindowStripe.tsx +++ b/packages/jui/src/ToolWindows/ToolWindowStripe.tsx @@ -172,6 +172,9 @@ function ToolWindowStripeButton({ const { pressProps } = { pressProps: { onPointerUp: onPress, + onMouseDown: (e) => { + e.preventDefault(); + }, } as HTMLAttributes, }; //usePress({ onPress }); const props = useElementMove({ diff --git a/packages/jui/src/ToolWindows/ToolWindows.cy.tsx b/packages/jui/src/ToolWindows/ToolWindows.cy.tsx index 7dfa9744..deba7f3e 100644 --- a/packages/jui/src/ToolWindows/ToolWindows.cy.tsx +++ b/packages/jui/src/ToolWindows/ToolWindows.cy.tsx @@ -42,6 +42,7 @@ const SimpleToolWindows = ({ >