import type React from 'react'; import type { IntlShape } from 'react-intl-next'; import type { Node, NodeType } from '@atlaskit/editor-prosemirror/model'; import type { EditorState } from '@atlaskit/editor-prosemirror/state'; import type { EditorView } from '@atlaskit/editor-prosemirror/view'; import type { EmojiId } from '@atlaskit/emoji/types'; import type { TooltipProps } from '@atlaskit/tooltip'; import type { DispatchAnalyticsEvent } from '../analytics/types/dispatch-analytics-event'; import type { DropdownMenuItemProps } from '../floating-toolbar'; import type { ProviderFactory } from '../provider-factory'; import type { PaletteColor } from '../ui-color/ColorPalette/Palettes/type'; import type { Command, CommandDispatch } from './command'; import type { MarkOptions, NodeOptions } from './copy-button'; /** * New dropdown types to support editor controls */ export type OverflowDropdownHeading = { title: string; type: 'overflow-dropdown-heading'; }; type OverflowDropdownCustom = { fallback: Array>; hidden?: boolean; render: (view?: EditorView, dropdownOption?: Omit) => React.ReactNode; type: 'custom'; }; export type OverflowDropdownOption = DropdownOptionT & { rank?: number; }; export type FloatingToolbarOverflowDropdownOptions = Array | FloatingToolbarSeparator | OverflowDropdownHeading | OverflowDropdownCustom>; export type FloatingToolbarOverflowDropdown = { alignDropdownWithToolbar?: boolean; disabled?: boolean; dropdownWidth?: number; hidden?: boolean; id?: string; onClick?: () => void; options: FloatingToolbarOverflowDropdownOptions; showSelected?: boolean; supportsViewMode?: boolean; testId?: string; tooltip?: string; type: 'overflow-dropdown'; }; export interface RenderOptionsPropsT { dispatchCommand: (command: T) => void; hide: () => void; } export interface DropdownOptionT { confirmDialog?: ConfirmDialogOptions | (() => ConfirmDialogOptions); description?: string; disabled?: boolean; domItemOptions?: { type: typeOption; }; elemAfter?: React.ReactNode; hidden?: boolean; icon?: React.ReactNode; id?: string; onBlur?: T; onClick: T; onFocus?: T; onMouseDown?: T; onMouseEnter?: T; onMouseLeave?: T; onMouseOut?: T; onMouseOver?: T; selected?: boolean; testId?: string; title: string; tooltip?: string; } export type typeOption = /** Dropdown menu item type * @default 'item' */ 'item' | 'item-checkbox'; export type DropdownOptions = Array> | { height: number; render: (props: RenderOptionsPropsT) => React.ReactElement | null; width: number; }; export interface SelectOption { data?: T; disabled?: boolean; hidden?: boolean; label: string; selected?: boolean; value: string; } export type ButtonAppearance = 'subtle' | 'danger'; export type Icon = React.ComponentType>; export type RenderOptionsProps = RenderOptionsPropsT; export type AlignType = 'left' | 'center' | 'right'; interface Position { bottom?: number; left?: number; right?: number; top?: number; } type PositionOffset = Position; export type ConfirmDialogChildInfo = { amount: number; id: string; name: string | null; }; export interface ConfirmDialogOptions { cancelButtonLabel?: string; checkboxLabel?: string; getChildrenInfo?: () => ConfirmDialogChildInfo[]; isReferentialityDialog?: boolean; message: string; messagePrefix?: string; okButtonLabel?: string; onConfirm?: (...args: any[]) => Command; title?: string; } export type ConfirmationDialogProps = { /** * onClose is called every time when the dialog is closed. * Either clicking on 'Confirm' button or 'Cancel' button, * which means it is being called after onConfirm, or by itself when clicking 'Cancel' button. */ onClose: () => void; onConfirm: (isCheck?: boolean) => void; options?: ConfirmDialogOptions; testId?: string; }; export type FloatingToolbarCopyButton = { hidden?: boolean; items: Array; supportsViewMode?: boolean; type: 'copy-button'; }; export type FloatingToolbarButton = { appearance?: ButtonAppearance; ariaHasPopup?: boolean | 'dialog' | 'menu' | 'listbox' | 'tree' | 'grid' | undefined; ariaLabel?: string; className?: string; confirmDialog?: ConfirmDialogOptions | (() => ConfirmDialogOptions); disabled?: boolean; focusEditoronEnter?: boolean; hidden?: boolean; hideTooltipOnClick?: boolean; href?: string; icon?: Icon; iconAfter?: Icon; iconFallback?: Icon; id?: string; interactionName?: string; isRadioButton?: boolean; metadata?: { [key: string]: string; }; onBlur?: T; onClick: T; onFocus?: T; onMount?: () => void; onMouseEnter?: T; onMouseLeave?: T; onUnmount?: () => void; /** If true, the component will have pulse onboarding effect around it. */ pulse?: boolean; selected?: boolean; showTitle?: boolean; supportsViewMode?: boolean; tabIndex?: number | null | undefined; target?: string; testId?: string; title: string; tooltipContent?: TooltipProps['content']; type: 'button'; }; export type FloatingToolbarInput = { defaultValue?: string; description?: string; hidden?: boolean; id: string; onBlur: (...args: any[]) => T; onSubmit: (...args: any[]) => T; placeholder?: string; title?: string; type: 'input'; }; export type FloatingToolbarCustom = { /** * By default -- the floating toolbar supports navigating between * items using arrow keys (to meet aria guidelines). * In some cases the floating toolbar is being used to present * non toolbar content -- such as the link editing experience. * In these cases you can opt out of arrow navigation using the * this property. * * @default false */ disableArrowNavigation?: boolean; fallback: Array>; hidden?: boolean; render: (view?: EditorView, idx?: number, dispatchAnalyticsEvent?: DispatchAnalyticsEvent) => React.ReactNode; supportsViewMode?: boolean; type: 'custom'; }; type FloatingToolbarSelectBase = { defaultValue?: V | null; filterOption?: ((option: V, rawInput: string) => boolean) | null; hidden?: boolean; hideExpandIcon?: boolean; id: string; isAriaExpanded?: boolean; onChange: (selected: V) => T; options: V[]; placeholder?: string; returnEscToButton?: boolean; selectType: 'list' | 'emoji' | 'date' | 'color'; title?: string; type: 'select'; }; export type FloatingToolbarListPicker = FloatingToolbarSelectBase & { selectType: 'list'; }; export type FloatingToolbarColorPicker = FloatingToolbarSelectBase & { selectType: 'color'; }; export type FloatingToolbarEmojiPicker = FloatingToolbarSelectBase & { options: never[]; selected?: boolean; selectType: 'emoji'; }; export type FloatingToolbarDatePicker = FloatingToolbarSelectBase & { options: never[]; selectType: 'date'; }; export type FloatingToolbarSelect = FloatingToolbarEmojiPicker | FloatingToolbarColorPicker | FloatingToolbarListPicker | FloatingToolbarDatePicker; export type FloatingToolbarSeparator = { fullHeight?: boolean; hidden?: boolean; supportsViewMode?: boolean; type: 'separator'; }; export type ExtensionDropdownOptions = () => DropdownOptions; export type FloatingToolbarDropdown = { alignDropdownWithToolbar?: boolean; disabled?: boolean; dropdownWidth?: number; footer?: React.ReactNode; hidden?: boolean; hideExpandIcon?: boolean; icon?: Icon; /** * Places an icon before the title as a representation */ iconBefore?: Icon; id?: string; onClick?: () => void; onMount?: () => void; onToggle?: (state: EditorState, dispatch: CommandDispatch | undefined) => boolean; options: DropdownOptions | ExtensionDropdownOptions; /** If true, the component will have pulse onboarding effect around it. */ pulse?: boolean; shouldFitContainer?: boolean; showSelected?: boolean; testId?: string; title: string; tooltip?: string; type: 'dropdown'; }; type FloatingToolbarExtensionsPlaceholder = { hidden?: boolean; separator?: 'start' | 'end' | 'both'; type: 'extensions-placeholder'; }; /** * This additional type is introduced in order to prevent infinite loop due to * `extract-react-types-loader`. The issue occurs when custom type `fallback` field * is an array of FloatingToolbarItem. Since FloatingToolbarItem is a FloatingToolbarCustom * type, it stucks in an infinite loop. Custom - Item -> Custom .... go on. * * This type is restricted with the items that can be used for fallback. * Make sure that this type is not a FloatingToolbarCustom type. */ export type FloatingToolbarFallbackItem = FloatingToolbarButton | FloatingToolbarCopyButton | FloatingToolbarDropdown | FloatingToolbarSelect | FloatingToolbarInput | FloatingToolbarSeparator; export type FloatingToolbarItem = FloatingToolbarButton | FloatingToolbarCopyButton | FloatingToolbarDropdown | FloatingToolbarSelect | FloatingToolbarInput | FloatingToolbarCustom | FloatingToolbarSeparator | FloatingToolbarExtensionsPlaceholder | FloatingToolbarOverflowDropdown; export interface FloatingToolbarConfig { /** * @deprecated To suppress visibility of toolbars, set user intent state in userIntentPlugin instead. * If any config has __suppressAllToolbars set to true, no floating toolbar will be rendered. * Use case: * When a node is nested inside a table and the cursor is inside of the nested node. * Nested node's toolbar is active. When table's menu opens, we provide table's config with * __suppressAllToolbars set to true. * To hide floating toolbar, use user intent API instead. */ __suppressAllToolbars?: boolean; /** Absolute offset of the toolbar */ absoluteOffset?: PositionOffset; align?: AlignType; /** Class added to Toolbar wrapper */ className?: string; /** * Enable Popup component's focus trap */ focusTrap?: boolean; forcePlacement?: boolean; /** * Override the DOM reference used to apply as the target for the * floating toolbar, if the config matches. * * By default, it will find the DOM reference of the node from the * head of the current selection. */ getDomRef?: (view: EditorView) => HTMLElement | undefined; /** aria-label added to role='radiogroup'element */ groupLabel?: string; /** Toolbar height */ height?: number; /** Items that will populate the Toolbar. * * See: `FloatingToolbarItem` */ items: Array> | ((node: Node) => Array>); mediaAssistiveMessage?: string; /** * nodeType or list of `nodeType`s this floating toolbar should be shown for. **/ nodeType: NodeType | NodeType[]; /** Offset the position of the toolbar. */ offset?: [ number, number ]; onPositionCalculated?: (editorView: EditorView, nextPos: Position) => Position; preventPopupOverflow?: boolean; scrollable?: boolean; stick?: boolean; /** Used for the ariaLabel on the component */ title: string; /** Can prevent the Toolbar from rendering */ visible?: boolean; /** Toolbar width */ width?: number; zIndex?: number; } export type FloatingToolbarHandler = (state: EditorState, intl: IntlShape, providerFactory: ProviderFactory, processedConfigs?: Array) => FloatingToolbarConfig | undefined; export {};