@ckeditor/ckeditor5-ui
Version:
The UI framework and standard UI library of CKEditor 5.
335 lines (334 loc) • 11.5 kB
TypeScript
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
/**
* @module ui/dropdown/dropdownview
*/
import View from '../view.js';
import type { default as DropdownButton } from './button/dropdownbutton.js';
import type { default as DropdownPanelView, PanelPosition } from './dropdownpanelview.js';
import type { FocusableView } from '../focuscycler.js';
import type ListView from '../list/listview.js';
import type ToolbarView from '../toolbar/toolbarview.js';
import type DropdownMenuRootListView from './menu/dropdownmenurootlistview.js';
import { KeystrokeHandler, FocusTracker, type Locale, type PositioningFunction } from '@ckeditor/ckeditor5-utils';
import '../../theme/components/dropdown/dropdown.css';
/**
* The dropdown view class. It manages the dropdown button and dropdown panel.
*
* In most cases, the easiest way to create a dropdown is by using the {@link module:ui/dropdown/utils~createDropdown}
* util:
*
* ```ts
* const dropdown = createDropdown( locale );
*
* // Configure dropdown's button properties:
* dropdown.buttonView.set( {
* label: 'A dropdown',
* withText: true
* } );
*
* dropdown.render();
*
* dropdown.panelView.element.textContent = 'Content of the panel';
*
* // Will render a dropdown with a panel containing a "Content of the panel" text.
* document.body.appendChild( dropdown.element );
* ```
*
* If you want to add a richer content to the dropdown panel, you can use the {@link module:ui/dropdown/utils~addListToDropdown}
* and {@link module:ui/dropdown/utils~addToolbarToDropdown} helpers. See more examples in
* {@link module:ui/dropdown/utils~createDropdown} documentation.
*
* If you want to create a completely custom dropdown, then you can compose it manually:
*
* ```ts
* const button = new DropdownButtonView( locale );
* const panel = new DropdownPanelView( locale );
* const dropdown = new DropdownView( locale, button, panel );
*
* button.set( {
* label: 'A dropdown',
* withText: true
* } );
*
* dropdown.render();
*
* panel.element.textContent = 'Content of the panel';
*
* // Will render a dropdown with a panel containing a "Content of the panel" text.
* document.body.appendChild( dropdown.element );
* ```
*
* However, dropdown created this way will contain little behavior. You will need to implement handlers for actions
* such as {@link module:ui/bindings/clickoutsidehandler~clickOutsideHandler clicking outside an open dropdown}
* (which should close it) and support for arrow keys inside the panel. Therefore, unless you really know what
* you do and you really need to do it, it is recommended to use the {@link module:ui/dropdown/utils~createDropdown} helper.
*/
export default class DropdownView extends View<HTMLDivElement> {
/**
* Button of the dropdown view. Clicking the button opens the {@link #panelView}.
*/
readonly buttonView: DropdownButton & FocusableView;
/**
* Panel of the dropdown. It opens when the {@link #buttonView} is
* {@link module:ui/button/button~Button#event:execute executed} (i.e. clicked).
*
* Child views can be added to the panel's `children` collection:
*
* ```ts
* dropdown.panelView.children.add( childView );
* ```
*
* See {@link module:ui/dropdown/dropdownpanelview~DropdownPanelView#children} and
* {@link module:ui/viewcollection~ViewCollection#add}.
*/
readonly panelView: DropdownPanelView;
/**
* Tracks information about the DOM focus in the dropdown.
*/
readonly focusTracker: FocusTracker;
/**
* Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}. It manages
* keystrokes of the dropdown:
*
* * <kbd>▼</kbd> opens the dropdown,
* * <kbd>◀</kbd> and <kbd>Esc</kbd> closes the dropdown.
*/
readonly keystrokes: KeystrokeHandler;
/**
* A child {@link module:ui/list/listview~ListView list view} of the dropdown located
* in its {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel}.
*
* **Note**: Only supported when dropdown has list view added using {@link module:ui/dropdown/utils~addListToDropdown}.
*/
listView?: ListView;
/**
* A child toolbar of the dropdown located in the
* {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel}.
*
* **Note**: Only supported when dropdown has a toolbar added using {@link module:ui/dropdown/utils~addToolbarToDropdown}.
*/
toolbarView?: ToolbarView;
/**
* A child menu component of the dropdown located
* in its {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel}.
*
* **Note**: Only supported when dropdown has a menu added using {@link module:ui/dropdown/utils~addMenuToDropdown}.
*/
menuView?: DropdownMenuRootListView;
/**
* Controls whether the dropdown view is open, i.e. shows or hides the {@link #panelView panel}.
*
* **Note**: When the dropdown gets open, it will attempt to call `focus()` on the first child of its {@link #panelView}.
* See {@link module:ui/dropdown/utils~addToolbarToDropdown}, {@link module:ui/dropdown/utils~addListToDropdown}, and
* {@link module:ui/dropdown/utils~focusChildOnDropdownOpen} to learn more about focus management in dropdowns.
*
* @observable
*/
isOpen: boolean;
/**
* Controls whether the dropdown is enabled, i.e. it can be clicked and execute an action.
*
* See {@link module:ui/button/buttonview~ButtonView#isEnabled}.
*
* @observable
*/
isEnabled: boolean;
/**
* (Optional) The additional CSS class set on the dropdown {@link #element}.
*
* @observable
*/
class: string | undefined;
/**
* (Optional) The `id` attribute of the dropdown (i.e. to pair with a `<label>` element).
*
* @observable
*/
id: string | undefined;
/**
* The position of the panel, relative to the dropdown.
*
* **Note**: When `'auto'`, the panel will use one of the remaining positions to stay
* in the viewport, visible to the user. The positions correspond directly to
* {@link module:ui/dropdown/dropdownview~DropdownView.defaultPanelPositions default panel positions}.
*
* **Note**: This value has an impact on the
* {@link module:ui/dropdown/dropdownpanelview~DropdownPanelView#position} property
* each time the panel becomes {@link #isOpen open}.
*
* @observable
* @default 'auto'
*/
panelPosition: PanelPosition | 'auto';
/**
* @observable
*/
ariaDescribedById: string | undefined;
/**
* Creates an instance of the dropdown.
*
* Also see {@link #render}.
*
* @param locale The localization services instance.
*/
constructor(locale: Locale | undefined, buttonView: DropdownButton & FocusableView, panelView: DropdownPanelView);
/**
* @inheritDoc
*/
render(): void;
/**
* Focuses the {@link #buttonView}.
*/
focus(): void;
/**
* Returns {@link #panelView panel} positions to be used by the
* {@link module:utils/dom/position~getOptimalPosition `getOptimalPosition()`}
* utility considering the direction of the language the UI of the editor is displayed in.
*/
private get _panelPositions();
/**
* Returns the default position of the dropdown panel based on the direction of the UI language.
* It is used when the {@link #panelPosition} is set to `'auto'` and the panel has not found a
* suitable position to fit into the viewport.
*/
private get _defaultPanelPositionName();
/**
* A set of positioning functions used by the dropdown view to determine
* the optimal position (i.e. fitting into the browser viewport) of its
* {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel} when
* {@link module:ui/dropdown/dropdownview~DropdownView#panelPosition} is set to 'auto'`.
*
* The available positioning functions are as follow:
*
* **South**
*
* * `south`
*
* ```
* [ Button ]
* +-----------------+
* | Panel |
* +-----------------+
* ```
*
* * `southEast`
*
* ```
* [ Button ]
* +-----------------+
* | Panel |
* +-----------------+
* ```
*
* * `southWest`
*
* ```
* [ Button ]
* +-----------------+
* | Panel |
* +-----------------+
* ```
*
* * `southMiddleEast`
*
* ```
* [ Button ]
* +-----------------+
* | Panel |
* +-----------------+
* ```
*
* * `southMiddleWest`
*
* ```
* [ Button ]
* +-----------------+
* | Panel |
* +-----------------+
* ```
*
* **North**
*
* * `north`
*
* ```
* +-----------------+
* | Panel |
* +-----------------+
* [ Button ]
* ```
*
* * `northEast`
*
* ```
* +-----------------+
* | Panel |
* +-----------------+
* [ Button ]
* ```
*
* * `northWest`
*
* ```
* +-----------------+
* | Panel |
* +-----------------+
* [ Button ]
* ```
*
* * `northMiddleEast`
*
* ```
* +-----------------+
* | Panel |
* +-----------------+
* [ Button ]
* ```
*
* * `northMiddleWest`
*
* ```
* +-----------------+
* | Panel |
* +-----------------+
* [ Button ]
* ```
*
* Positioning functions are compatible with {@link module:utils/dom/position~DomPoint}.
*
* The name that position function returns will be reflected in dropdown panel's class that
* controls its placement. See {@link module:ui/dropdown/dropdownview~DropdownView#panelPosition}
* to learn more.
*/
static defaultPanelPositions: Record<string, PositioningFunction>;
/**
* A function used to calculate the optimal position for the dropdown panel.
*/
private static _getOptimalPosition;
}
/**
* Fired when an item inside the dropdown is executed.
*
* **Note**: Only supported when dropdown was integrated with its child view using one of the helper functions:
* {@link module:ui/dropdown/utils~addListToDropdown}, {@link module:ui/dropdown/utils~addToolbarToDropdown}, or
* {@link module:ui/dropdown/utils~addMenuToDropdown}.
*
* When integrated with a list, it fires when a child of one of {@link module:ui/list/listitemview~ListItemView}s
* fired `execute` event.
*
* When integrated with a toolbar, it fires when one of the buttons has been {@link module:ui/button/button~Button#event:execute executed}.
*
* When integrated with a nested menu, it fires when one of the menu buttons has been executed.
*
* In each case, the event is delegated from the component which fired it. It does not have additional parameters and `event.source` is the
* original component.
*
* @eventName ~DropdownView#execute
*/
export type DropdownViewEvent = {
name: 'execute';
args: [];
};