diff --git a/packages/docs/docs/core/panels/contextMenus.mdx b/packages/docs/docs/core/panels/contextMenus.mdx new file mode 100644 index 000000000..3c843665a --- /dev/null +++ b/packages/docs/docs/core/panels/contextMenus.mdx @@ -0,0 +1,300 @@ +--- +title: 'Context menus' +description: Right-click menus for tabs and tab group chips, with built-in item shortcuts, custom label and component items, and per-case suppression. +sidebar_position: 13 +enterprise: true +sidebar_custom_props: + enterprise: true +--- + +import { CodeRunner } from '@site/src/components/ui/codeRunner'; +import { DocRef } from '@site/src/components/ui/reference/docRef'; + +Dockview can show a context menu when you right-click a tab or a tab group chip. +Menus are opt-in: nothing is shown unless you supply a builder function. Each +builder returns a list mixing built-in string shortcuts with your own custom +items. + +:::info Enterprise feature +Context menus are provided by the `ContextMenuModule` in the +[`dockview-enterprise`](/docs/overview/editions) package. Importing +`dockview-enterprise` registers the module for every Dockview instance in the +process. Without it, `getTabContextMenuItems` and +`getTabGroupChipContextMenuItems` are ignored and no menu appears. +::: + + + +## Tab context menu + +Provide `getTabContextMenuItems` to build the menu shown when a tab is +right-clicked. It receives the panel, its group, the `DockviewApi` and the +originating `MouseEvent`, and returns the items to render. Return an empty array +to suppress the menu for a specific tab. + + + + + + + + + + + + + + + + + +### Built-in items + +Pass string shortcuts to render standard entries without writing any handlers. +Each item wires itself to the panel and group from the builder's params: + +| Value | Behaviour | +| -------------- | -------------------------------------------------------------------------------------------------- | +| `'close'` | Close this panel | +| `'closeOthers'`| Close every other panel in the group | +| `'closeAll'` | Close every panel in the group | +| `'closeLeft'` | Close the panels before this one in the tab strip | +| `'closeRight'` | Close the panels after this one in the tab strip | +| `'maximize'` | Maximize the group. Renders as `Restore` and disables for non-grid panels, tracking the live state | +| `'float'` | Move the panel into a floating group. Disabled when the panel is already floating | +| `'popout'` | Move the panel into a new browser window. Disabled when already popped out | +| `'pin'` | Toggle the panel's pinned state. Renders as `Pin tab` / `Unpin tab` (see [Pinned tabs](/docs/core/panels/pinnedTabs)) | +| `'separator'` | Render a visual divider | + +```ts +getTabContextMenuItems: (params) => [ + 'close', + 'closeOthers', + 'closeAll', + 'separator', + 'maximize', + 'popout', +]; +``` + +### Custom label items + +Return an object with a `label` and an `action` for a simple clickable entry. +The `action` runs when the item is chosen; the menu then closes on its own. + +```ts +getTabContextMenuItems: (params) => [ + 'close', + 'separator', + { + label: 'Log panel id', + action: () => console.log(params.panel.id), + }, + { + label: 'Float tab', + action: () => params.api.addFloatingGroup(params.panel), + }, +]; +``` + +Set `disabled: true` to render an item greyed out and non-interactive: + +```ts +{ + label: 'Close', + action: () => params.panel.api.close(), + disabled: params.api.panels.length === 1, +} +``` + +### Custom component items + +For richer entries, render your own framework component instead of a plain +label. The component receives the panel, group, api and a `close` callback +through `IContextMenuItemComponentProps`; call `close()` when you are done to +dismiss the menu. + + + + +```tsx +const FloatMenuItem = ({ panel, api, close }: IContextMenuItemComponentProps) => ( +
{ + api.addFloatingGroup(panel); + close(); + }} + > + Float tab +
+); + +// then reference it as a component item +getTabContextMenuItems={(params) => [ + 'close', + 'separator', + { component: FloatMenuItem }, +]} +``` +
+ + +```ts +const FloatMenuItem = defineComponent({ + name: 'FloatMenuItem', + props: { + params: { + type: Object as PropType, + required: true, + }, + }, + methods: { + onClick() { + this.params.api.addFloatingGroup(this.params.panel); + this.params.close(); + }, + }, + template: `
Float tab
`, +}); + +// reference the registered component by name +getTabContextMenuItems(params) { + return ['close', 'separator', { component: 'floatMenuItem' }]; +} +``` +
+ + +```ts +getTabContextMenuItems = (params: GetTabContextMenuItemsParams) => [ + 'close', + 'separator', + { component: FloatMenuItemComponent }, +]; +``` + + + +With vanilla TypeScript there is no framework component layer, so use a `label` +plus `action`, or embed a raw DOM node with the `element` field: + +```ts +getTabContextMenuItems: (params) => [ + 'close', + 'separator', + { + label: 'Float tab', + action: () => params.api.addFloatingGroup(params.panel), + }, +]; +``` + + +Pass extra data to a component item with `componentProps`; it is forwarded to +the component as `props.componentProps`. + +### Raw element items + +To render custom content without a framework component, hand over a DOM node +with the `element` field. Dockview embeds it as-is: + +```ts +const el = document.createElement('div'); +el.className = 'dv-context-menu-item'; +el.textContent = 'Custom item'; + +getTabContextMenuItems: (params) => ['close', 'separator', { element: el }]; +``` + +## Chip context menu + +Provide `getTabGroupChipContextMenuItems` to build the menu shown when a +[tab group chip](/docs/core/panels/tabGroups) is right-clicked. It receives the +tab group, its group, the `DockviewApi` and the `MouseEvent`, and returns the +items. As with tabs, return an empty array to suppress the menu for a specific +chip. + + + + + + + + + + + + + + + + + +### Built-in chip items + +| Value | Behaviour | +| --------------- | ------------------------------------------------------------------ | +| `'rename'` | An inline text input to rename the tab group | +| `'colorPicker'` | A grid of colour swatches to change the tab group colour | +| `'collapse'` | Collapse the tab group. Renders as `Expand` when already collapsed | +| `'close'` | Close every panel belonging to the tab group | +| `'separator'` | Render a visual divider | + +Custom label, component and element items work the same way as for tabs: + +```ts +getTabGroupChipContextMenuItems: (params) => [ + 'rename', + 'colorPicker', + 'separator', + { + label: 'Dissolve group', + action: () => + params.api.dissolveTabGroup({ + groupId: params.group.id, + tabGroupId: params.tabGroup.id, + }), + }, +]; +``` + +See [Tab groups](/docs/core/panels/tabGroups#chip-context-menu) for the full +chip API. + +## Suppressing the menu + +Both builders are called on every right-click. Return an empty array to skip the +menu in specific cases while keeping it for the rest: + +```ts +getTabContextMenuItems: (params) => + params.panel.api.isActive ? ['close', 'separator', 'maximize'] : []; +``` + +Omitting the builder entirely disables the menu everywhere and lets the native +browser context menu through. diff --git a/packages/docs/docs/overview/editions.mdx b/packages/docs/docs/overview/editions.mdx index 2dd559837..60a88e080 100644 --- a/packages/docs/docs/overview/editions.mdx +++ b/packages/docs/docs/overview/editions.mdx @@ -42,7 +42,7 @@ All of the following are provided by the `dockview-enterprise` package: - **Tool windows and edges**: [auto-hide edge groups](/docs/core/groups/autoHideEdgeGroups) that collapse to a strip and peek on demand, and [dock-to-edge groups](/docs/core/groups/autoEdgeGroups). - **Keyboard and navigation**: [keyboard navigation](/docs/advanced/keyboard) with F6 and spatial movement, and [focus navigation](/docs/advanced/focus-navigation) across groups and popout windows. - **Layout lifecycle**: [layout history](/docs/core/state/history) with undo and redo. -- **Context menus**: built-in right-click menus for tabs and tab group chips. +- **Context menus**: [right-click menus](/docs/core/panels/contextMenus) for tabs and tab group chips. For the exact, feature-by-feature breakdown, see the [full feature comparison](/docs/overview/features). diff --git a/packages/docs/docs/overview/features.mdx b/packages/docs/docs/overview/features.mdx index 46a6a70f0..2c8b85fa7 100644 --- a/packages/docs/docs/overview/features.mdx +++ b/packages/docs/docs/overview/features.mdx @@ -35,8 +35,8 @@ The guiding rule: capabilities that other free layout managers already offer (fl | Pinned tabs | Keep tabs first in the strip, out of the overflow menu. See [Pinned tabs](/docs/core/panels/pinnedTabs) | | | | Tab group chips | Colour-coded chips that group related tabs together | | | | Custom chip renderer | Replace the default chip with your own component | | | -| Tab context menus | Custom right-click menus on tabs | | | -| Chip context menus | Right-click menus on tab group chips | | | +| Tab context menus | Custom right-click menus on tabs. See [Context menus](/docs/core/panels/contextMenus) | | | +| Chip context menus | Right-click menus on tab group chips. See [Context menus](/docs/core/panels/contextMenus) | | | ### Drag and drop