feat(richtext-lexical)!: dropdown menu disabled status (#8177)
**Breaking change**: ToolbarDropdown no longer receives
`groupKey={group.key}` and `items={group.items}` as props, but instead
`group={group}`
___
Similar to #8159, but in this case it allows you to disable an entire
dropdown menu, not just individual items in the dropdown.
This adds a new property to `ToolbarGroup` when used with `type:
'dropdown'`.
For example, if you add `isEnabled: () => false,` inside
`packages/richtext-lexical/src/features/shared/toolbar/textDropdownGroup.ts`
and run `pnpm dev fields`, this is what you'll see in the Lexical
editor:

This commit is contained in:
@@ -110,9 +110,8 @@ function ToolbarGroupComponent({
|
|||||||
<ToolbarDropdown
|
<ToolbarDropdown
|
||||||
anchorElem={anchorElem}
|
anchorElem={anchorElem}
|
||||||
editor={editor}
|
editor={editor}
|
||||||
groupKey={group.key}
|
group={group}
|
||||||
Icon={DropdownIcon}
|
Icon={DropdownIcon}
|
||||||
items={group.items}
|
|
||||||
itemsContainerClassNames={['fixed-toolbar__dropdown-items']}
|
itemsContainerClassNames={['fixed-toolbar__dropdown-items']}
|
||||||
label={dropdownLabel}
|
label={dropdownLabel}
|
||||||
maxActiveItems={1}
|
maxActiveItems={1}
|
||||||
@@ -122,8 +121,7 @@ function ToolbarGroupComponent({
|
|||||||
<ToolbarDropdown
|
<ToolbarDropdown
|
||||||
anchorElem={anchorElem}
|
anchorElem={anchorElem}
|
||||||
editor={editor}
|
editor={editor}
|
||||||
groupKey={group.key}
|
group={group}
|
||||||
items={group.items}
|
|
||||||
itemsContainerClassNames={['fixed-toolbar__dropdown-items']}
|
itemsContainerClassNames={['fixed-toolbar__dropdown-items']}
|
||||||
label={dropdownLabel}
|
label={dropdownLabel}
|
||||||
maxActiveItems={1}
|
maxActiveItems={1}
|
||||||
|
|||||||
@@ -101,9 +101,8 @@ function ToolbarGroupComponent({
|
|||||||
<ToolbarDropdown
|
<ToolbarDropdown
|
||||||
anchorElem={anchorElem}
|
anchorElem={anchorElem}
|
||||||
editor={editor}
|
editor={editor}
|
||||||
groupKey={group.key}
|
group={group}
|
||||||
Icon={DropdownIcon}
|
Icon={DropdownIcon}
|
||||||
items={group.items}
|
|
||||||
maxActiveItems={1}
|
maxActiveItems={1}
|
||||||
onActiveChange={onActiveChange}
|
onActiveChange={onActiveChange}
|
||||||
/>
|
/>
|
||||||
@@ -111,8 +110,7 @@ function ToolbarGroupComponent({
|
|||||||
<ToolbarDropdown
|
<ToolbarDropdown
|
||||||
anchorElem={anchorElem}
|
anchorElem={anchorElem}
|
||||||
editor={editor}
|
editor={editor}
|
||||||
groupKey={group.key}
|
group={group}
|
||||||
items={group.items}
|
|
||||||
maxActiveItems={1}
|
maxActiveItems={1}
|
||||||
onActiveChange={onActiveChange}
|
onActiveChange={onActiveChange}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover:not([disabled]) {
|
&:hover:not(.disabled) {
|
||||||
background-color: var(--theme-elevation-100);
|
background-color: var(--theme-elevation-100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,8 @@
|
|||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
|
|
||||||
.icon {
|
|
||||||
opacity: 0.2;
|
opacity: 0.2;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&:hover:not([disabled]) {
|
&:hover:not([disabled]) {
|
||||||
background-color: var(--theme-elevation-100);
|
background-color: var(--theme-elevation-100);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { mergeRegister } from '@lexical/utils'
|
|||||||
import { useTranslation } from '@payloadcms/ui'
|
import { useTranslation } from '@payloadcms/ui'
|
||||||
import { $getSelection } from 'lexical'
|
import { $getSelection } from 'lexical'
|
||||||
|
|
||||||
import type { ToolbarGroupItem } from '../../types.js'
|
import type { ToolbarDropdownGroup, ToolbarGroupItem } from '../../types.js'
|
||||||
|
|
||||||
import { useEditorConfigContext } from '../../../../lexical/config/client/EditorConfigProvider.js'
|
import { useEditorConfigContext } from '../../../../lexical/config/client/EditorConfigProvider.js'
|
||||||
import { DropDown, DropDownItem } from './DropDown.js'
|
import { DropDown, DropDownItem } from './DropDown.js'
|
||||||
@@ -70,9 +70,8 @@ export const ToolbarDropdown = ({
|
|||||||
anchorElem,
|
anchorElem,
|
||||||
classNames,
|
classNames,
|
||||||
editor,
|
editor,
|
||||||
groupKey,
|
group,
|
||||||
Icon,
|
Icon,
|
||||||
items,
|
|
||||||
itemsContainerClassNames,
|
itemsContainerClassNames,
|
||||||
label,
|
label,
|
||||||
maxActiveItems,
|
maxActiveItems,
|
||||||
@@ -81,9 +80,8 @@ export const ToolbarDropdown = ({
|
|||||||
anchorElem: HTMLElement
|
anchorElem: HTMLElement
|
||||||
classNames?: string[]
|
classNames?: string[]
|
||||||
editor: LexicalEditor
|
editor: LexicalEditor
|
||||||
groupKey: string
|
group: ToolbarDropdownGroup
|
||||||
Icon?: React.FC
|
Icon?: React.FC
|
||||||
items: ToolbarGroupItem[]
|
|
||||||
itemsContainerClassNames?: string[]
|
itemsContainerClassNames?: string[]
|
||||||
label?: string
|
label?: string
|
||||||
/**
|
/**
|
||||||
@@ -95,7 +93,9 @@ export const ToolbarDropdown = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [activeItemKeys, setActiveItemKeys] = React.useState<string[]>([])
|
const [activeItemKeys, setActiveItemKeys] = React.useState<string[]>([])
|
||||||
const [enabledItemKeys, setEnabledItemKeys] = React.useState<string[]>([])
|
const [enabledItemKeys, setEnabledItemKeys] = React.useState<string[]>([])
|
||||||
|
const [enabledGroup, setEnabledGroup] = React.useState<boolean>(true)
|
||||||
const editorConfigContext = useEditorConfigContext()
|
const editorConfigContext = useEditorConfigContext()
|
||||||
|
const { items, key: groupKey } = group
|
||||||
|
|
||||||
const updateStates = useCallback(() => {
|
const updateStates = useCallback(() => {
|
||||||
editor.getEditorState().read(() => {
|
editor.getEditorState().read(() => {
|
||||||
@@ -125,6 +125,9 @@ export const ToolbarDropdown = ({
|
|||||||
_enabledItemKeys.push(item.key)
|
_enabledItemKeys.push(item.key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (group.isEnabled) {
|
||||||
|
setEnabledGroup(group.isEnabled({ editor, editorConfigContext, selection }))
|
||||||
|
}
|
||||||
setActiveItemKeys(_activeItemKeys)
|
setActiveItemKeys(_activeItemKeys)
|
||||||
setEnabledItemKeys(_enabledItemKeys)
|
setEnabledItemKeys(_enabledItemKeys)
|
||||||
|
|
||||||
@@ -132,7 +135,7 @@ export const ToolbarDropdown = ({
|
|||||||
onActiveChange({ activeItems: _activeItems })
|
onActiveChange({ activeItems: _activeItems })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [editor, editorConfigContext, items, maxActiveItems, onActiveChange])
|
}, [editor, editorConfigContext, group, items, maxActiveItems, onActiveChange])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateStates()
|
updateStates()
|
||||||
@@ -152,6 +155,7 @@ export const ToolbarDropdown = ({
|
|||||||
buttonClassName={[baseClass, `${baseClass}-${groupKey}`, ...(classNames || [])]
|
buttonClassName={[baseClass, `${baseClass}-${groupKey}`, ...(classNames || [])]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(' ')}
|
.join(' ')}
|
||||||
|
disabled={!enabledGroup}
|
||||||
Icon={Icon}
|
Icon={Icon}
|
||||||
itemsContainerClassNames={[`${baseClass}-items`, ...(itemsContainerClassNames || [])]}
|
itemsContainerClassNames={[`${baseClass}-items`, ...(itemsContainerClassNames || [])]}
|
||||||
key={groupKey}
|
key={groupKey}
|
||||||
|
|||||||
@@ -4,30 +4,25 @@ import type React from 'react'
|
|||||||
|
|
||||||
import type { EditorConfigContextType } from '../../lexical/config/client/EditorConfigProvider.js'
|
import type { EditorConfigContextType } from '../../lexical/config/client/EditorConfigProvider.js'
|
||||||
|
|
||||||
export type ToolbarGroup =
|
export type ToolbarGroup = ToolbarButtonsGroup | ToolbarDropdownGroup
|
||||||
| {
|
|
||||||
/**
|
export type ToolbarDropdownGroup = {
|
||||||
* All toolbar items part of this toolbar group need to be added here.
|
|
||||||
*/
|
|
||||||
items: Array<ToolbarGroupItem>
|
|
||||||
/**
|
|
||||||
* Each toolbar group needs to have a unique key. Groups with the same keys will have their items merged together.
|
|
||||||
*/
|
|
||||||
key: string
|
|
||||||
/**
|
|
||||||
* Determines where the toolbar group will be.
|
|
||||||
*/
|
|
||||||
order?: number
|
|
||||||
/**
|
|
||||||
* Controls the toolbar group type. Set to `buttons` to create a buttons toolbar group, which displays toolbar items horizontally using only their icons.
|
|
||||||
*/
|
|
||||||
type: 'buttons'
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
/**
|
/**
|
||||||
* The dropdown toolbar ChildComponent allows you to pass in a React Component which will be displayed within the dropdown button.
|
* The dropdown toolbar ChildComponent allows you to pass in a React Component which will be displayed within the dropdown button.
|
||||||
*/
|
*/
|
||||||
ChildComponent?: React.FC
|
ChildComponent?: React.FC
|
||||||
|
/**
|
||||||
|
* This is optional and controls if the toolbar group is highlighted or not.
|
||||||
|
*/
|
||||||
|
isEnabled?: ({
|
||||||
|
editor,
|
||||||
|
editorConfigContext,
|
||||||
|
selection,
|
||||||
|
}: {
|
||||||
|
editor: LexicalEditor
|
||||||
|
editorConfigContext: EditorConfigContextType
|
||||||
|
selection: BaseSelection
|
||||||
|
}) => boolean
|
||||||
/**
|
/**
|
||||||
* All toolbar items part of this toolbar group need to be added here.
|
* All toolbar items part of this toolbar group need to be added here.
|
||||||
*/
|
*/
|
||||||
@@ -46,6 +41,25 @@ export type ToolbarGroup =
|
|||||||
type: 'dropdown'
|
type: 'dropdown'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ToolbarButtonsGroup = {
|
||||||
|
/**
|
||||||
|
* All toolbar items part of this toolbar group need to be added here.
|
||||||
|
*/
|
||||||
|
items: Array<ToolbarGroupItem>
|
||||||
|
/**
|
||||||
|
* Each toolbar group needs to have a unique key. Groups with the same keys will have their items merged together.
|
||||||
|
*/
|
||||||
|
key: string
|
||||||
|
/**
|
||||||
|
* Determines where the toolbar group will be.
|
||||||
|
*/
|
||||||
|
order?: number
|
||||||
|
/**
|
||||||
|
* Controls the toolbar group type. Set to `buttons` to create a buttons toolbar group, which displays toolbar items horizontally using only their icons.
|
||||||
|
*/
|
||||||
|
type: 'buttons'
|
||||||
|
}
|
||||||
|
|
||||||
export type ToolbarGroupItem = {
|
export type ToolbarGroupItem = {
|
||||||
/** A React component which is rendered within your toolbar item's default button component. Usually, you want this to be an icon. */
|
/** A React component which is rendered within your toolbar item's default button component. Usually, you want this to be an icon. */
|
||||||
ChildComponent?: React.FC
|
ChildComponent?: React.FC
|
||||||
|
|||||||
Reference in New Issue
Block a user