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:


![image](https://github.com/user-attachments/assets/4efe2e92-2e78-473f-8c97-0995e3d44671)
This commit is contained in:
Germán Jabloñski
2024-09-20 16:55:34 -03:00
committed by GitHub
parent 493b121ae8
commit 7d2022f28b
6 changed files with 71 additions and 60 deletions

View File

@@ -110,9 +110,8 @@ function ToolbarGroupComponent({
<ToolbarDropdown
anchorElem={anchorElem}
editor={editor}
groupKey={group.key}
group={group}
Icon={DropdownIcon}
items={group.items}
itemsContainerClassNames={['fixed-toolbar__dropdown-items']}
label={dropdownLabel}
maxActiveItems={1}
@@ -122,8 +121,7 @@ function ToolbarGroupComponent({
<ToolbarDropdown
anchorElem={anchorElem}
editor={editor}
groupKey={group.key}
items={group.items}
group={group}
itemsContainerClassNames={['fixed-toolbar__dropdown-items']}
label={dropdownLabel}
maxActiveItems={1}

View File

@@ -101,9 +101,8 @@ function ToolbarGroupComponent({
<ToolbarDropdown
anchorElem={anchorElem}
editor={editor}
groupKey={group.key}
group={group}
Icon={DropdownIcon}
items={group.items}
maxActiveItems={1}
onActiveChange={onActiveChange}
/>
@@ -111,8 +110,7 @@ function ToolbarGroupComponent({
<ToolbarDropdown
anchorElem={anchorElem}
editor={editor}
groupKey={group.key}
items={group.items}
group={group}
maxActiveItems={1}
onActiveChange={onActiveChange}
/>

View File

@@ -18,7 +18,7 @@
margin-right: 2px;
}
&:hover:not([disabled]) {
&:hover:not(.disabled) {
background-color: var(--theme-elevation-100);
}

View File

@@ -23,10 +23,7 @@
&:disabled {
cursor: not-allowed;
.icon {
opacity: 0.2;
}
opacity: 0.2;
}
&:hover:not([disabled]) {

View File

@@ -9,7 +9,7 @@ import { mergeRegister } from '@lexical/utils'
import { useTranslation } from '@payloadcms/ui'
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 { DropDown, DropDownItem } from './DropDown.js'
@@ -70,9 +70,8 @@ export const ToolbarDropdown = ({
anchorElem,
classNames,
editor,
groupKey,
group,
Icon,
items,
itemsContainerClassNames,
label,
maxActiveItems,
@@ -81,9 +80,8 @@ export const ToolbarDropdown = ({
anchorElem: HTMLElement
classNames?: string[]
editor: LexicalEditor
groupKey: string
group: ToolbarDropdownGroup
Icon?: React.FC
items: ToolbarGroupItem[]
itemsContainerClassNames?: string[]
label?: string
/**
@@ -95,7 +93,9 @@ export const ToolbarDropdown = ({
}) => {
const [activeItemKeys, setActiveItemKeys] = React.useState<string[]>([])
const [enabledItemKeys, setEnabledItemKeys] = React.useState<string[]>([])
const [enabledGroup, setEnabledGroup] = React.useState<boolean>(true)
const editorConfigContext = useEditorConfigContext()
const { items, key: groupKey } = group
const updateStates = useCallback(() => {
editor.getEditorState().read(() => {
@@ -125,6 +125,9 @@ export const ToolbarDropdown = ({
_enabledItemKeys.push(item.key)
}
}
if (group.isEnabled) {
setEnabledGroup(group.isEnabled({ editor, editorConfigContext, selection }))
}
setActiveItemKeys(_activeItemKeys)
setEnabledItemKeys(_enabledItemKeys)
@@ -132,7 +135,7 @@ export const ToolbarDropdown = ({
onActiveChange({ activeItems: _activeItems })
}
})
}, [editor, editorConfigContext, items, maxActiveItems, onActiveChange])
}, [editor, editorConfigContext, group, items, maxActiveItems, onActiveChange])
useEffect(() => {
updateStates()
@@ -152,6 +155,7 @@ export const ToolbarDropdown = ({
buttonClassName={[baseClass, `${baseClass}-${groupKey}`, ...(classNames || [])]
.filter(Boolean)
.join(' ')}
disabled={!enabledGroup}
Icon={Icon}
itemsContainerClassNames={[`${baseClass}-items`, ...(itemsContainerClassNames || [])]}
key={groupKey}

View File

@@ -4,47 +4,61 @@ import type React from 'react'
import type { EditorConfigContextType } from '../../lexical/config/client/EditorConfigProvider.js'
export type ToolbarGroup =
| {
/**
* 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.
*/
ChildComponent?: React.FC
/**
* 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 `dropdown` to create a buttons toolbar group, which displays toolbar items vertically using their icons and labels, if the dropdown is open.
*/
type: 'dropdown'
}
export type ToolbarGroup = ToolbarButtonsGroup | ToolbarDropdownGroup
export type ToolbarDropdownGroup = {
/**
* The dropdown toolbar ChildComponent allows you to pass in a React Component which will be displayed within the dropdown button.
*/
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.
*/
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 `dropdown` to create a buttons toolbar group, which displays toolbar items vertically using their icons and labels, if the dropdown is open.
*/
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 = {
/** A React component which is rendered within your toolbar item's default button component. Usually, you want this to be an icon. */