| 1 |
import { |
| 2 |
MenuGroup, |
| 3 |
MenuItem, |
| 4 |
ToolbarDropdownMenu, |
| 5 |
} from "@wordpress/components"; |
| 6 |
import { BlockControls } from "@wordpress/block-editor"; |
| 7 |
import { __ } from "@wordpress/i18n"; |
| 8 |
import { moreVertical } from "@wordpress/icons"; |
| 9 |
|
| 10 |
import { createElement } from "../elements"; |
| 11 |
import { |
| 12 |
applyElementStyleClipboardPayload, |
| 13 |
parseElementStyleClipboardPayload, |
| 14 |
readClipboardText, |
| 15 |
serializeElementClipboardPayload, |
| 16 |
serializeElementStyleClipboardPayload, |
| 17 |
writeClipboardText, |
| 18 |
} from "../hooks/block-editor-compat/elementClipboard"; |
| 19 |
import { CellKey } from "../attributes"; |
| 20 |
import { useTableStore } from "../store"; |
| 21 |
|
| 22 |
function getShortcutRepresentation(name: string): string | undefined { |
| 23 |
const store = window.wp?.keyboardShortcuts?.store; |
| 24 |
const select = window.wp?.data?.select; |
| 25 |
|
| 26 |
if (!store || !select) { |
| 27 |
return undefined; |
| 28 |
} |
| 29 |
|
| 30 |
return select(store).getShortcutRepresentation?.(name); |
| 31 |
} |
| 32 |
|
| 33 |
export function ElementOptionsButton({ |
| 34 |
cellCoords, |
| 35 |
elementIndex, |
| 36 |
}: { |
| 37 |
cellCoords: CellKey; |
| 38 |
elementIndex: number; |
| 39 |
}) { |
| 40 |
const cells = useTableStore(state => state.cells); |
| 41 |
const insertElementInCell = useTableStore( |
| 42 |
state => state.insertElementInCell |
| 43 |
); |
| 44 |
const duplicateElementInCell = useTableStore( |
| 45 |
state => state.duplicateElementInCell |
| 46 |
); |
| 47 |
const removeElementFromCell = useTableStore( |
| 48 |
state => state.removeElementFromCell |
| 49 |
); |
| 50 |
const updateCellElement = useTableStore(state => state.updateCellElement); |
| 51 |
|
| 52 |
const selectedElement = cells[cellCoords]?.elements?.[elementIndex] || null; |
| 53 |
const shortcuts = { |
| 54 |
copy: getShortcutRepresentation("core/block-editor/copy"), |
| 55 |
cut: getShortcutRepresentation("core/block-editor/cut"), |
| 56 |
duplicate: getShortcutRepresentation("core/block-editor/duplicate"), |
| 57 |
insertBefore: getShortcutRepresentation( |
| 58 |
"core/block-editor/insert-before" |
| 59 |
), |
| 60 |
insertAfter: getShortcutRepresentation( |
| 61 |
"core/block-editor/insert-after" |
| 62 |
), |
| 63 |
remove: getShortcutRepresentation("core/block-editor/remove"), |
| 64 |
}; |
| 65 |
|
| 66 |
if (!selectedElement) { |
| 67 |
return null; |
| 68 |
} |
| 69 |
|
| 70 |
const insertTextElement = (targetIndex: number) => { |
| 71 |
const textElement = createElement("text"); |
| 72 |
|
| 73 |
if (!textElement) { |
| 74 |
return; |
| 75 |
} |
| 76 |
|
| 77 |
insertElementInCell(cellCoords, targetIndex, textElement); |
| 78 |
}; |
| 79 |
|
| 80 |
return ( |
| 81 |
<ToolbarDropdownMenu |
| 82 |
icon={moreVertical} |
| 83 |
label={__("Element options", "tableberg")} |
| 84 |
toggleProps={{ |
| 85 |
title: __("Element options", "tableberg"), |
| 86 |
showTooltip: true, |
| 87 |
}} |
| 88 |
popoverProps={{ placement: "bottom-start" }} |
| 89 |
> |
| 90 |
{({ onClose }) => ( |
| 91 |
<> |
| 92 |
<MenuGroup> |
| 93 |
<MenuItem |
| 94 |
shortcut={shortcuts.copy} |
| 95 |
onClick={() => { |
| 96 |
void writeClipboardText( |
| 97 |
serializeElementClipboardPayload( |
| 98 |
selectedElement |
| 99 |
) |
| 100 |
); |
| 101 |
onClose(); |
| 102 |
}} |
| 103 |
> |
| 104 |
{__("Copy", "tableberg")} |
| 105 |
</MenuItem> |
| 106 |
<MenuItem |
| 107 |
onClick={() => { |
| 108 |
void writeClipboardText( |
| 109 |
serializeElementStyleClipboardPayload( |
| 110 |
selectedElement |
| 111 |
) |
| 112 |
); |
| 113 |
onClose(); |
| 114 |
}} |
| 115 |
> |
| 116 |
{__("Copy styles", "tableberg")} |
| 117 |
</MenuItem> |
| 118 |
<MenuItem |
| 119 |
onClick={() => { |
| 120 |
void (async () => { |
| 121 |
const clipboardText = |
| 122 |
await readClipboardText(); |
| 123 |
const stylePayload = |
| 124 |
parseElementStyleClipboardPayload( |
| 125 |
clipboardText |
| 126 |
); |
| 127 |
|
| 128 |
if (!stylePayload) { |
| 129 |
return; |
| 130 |
} |
| 131 |
|
| 132 |
const styledElement = |
| 133 |
applyElementStyleClipboardPayload( |
| 134 |
selectedElement, |
| 135 |
stylePayload |
| 136 |
); |
| 137 |
|
| 138 |
updateCellElement( |
| 139 |
cellCoords, |
| 140 |
elementIndex, |
| 141 |
{ |
| 142 |
attributes: |
| 143 |
styledElement.attributes, |
| 144 |
} |
| 145 |
); |
| 146 |
})(); |
| 147 |
onClose(); |
| 148 |
}} |
| 149 |
> |
| 150 |
{__("Paste styles", "tableberg")} |
| 151 |
</MenuItem> |
| 152 |
<MenuItem |
| 153 |
shortcut={shortcuts.cut} |
| 154 |
onClick={() => { |
| 155 |
void (async () => { |
| 156 |
await writeClipboardText( |
| 157 |
serializeElementClipboardPayload( |
| 158 |
selectedElement |
| 159 |
) |
| 160 |
); |
| 161 |
removeElementFromCell( |
| 162 |
cellCoords, |
| 163 |
elementIndex |
| 164 |
); |
| 165 |
})(); |
| 166 |
onClose(); |
| 167 |
}} |
| 168 |
> |
| 169 |
{__("Cut", "tableberg")} |
| 170 |
</MenuItem> |
| 171 |
<MenuItem |
| 172 |
shortcut={shortcuts.duplicate} |
| 173 |
onClick={() => { |
| 174 |
duplicateElementInCell( |
| 175 |
cellCoords, |
| 176 |
elementIndex |
| 177 |
); |
| 178 |
onClose(); |
| 179 |
}} |
| 180 |
> |
| 181 |
{__("Duplicate", "tableberg")} |
| 182 |
</MenuItem> |
| 183 |
</MenuGroup> |
| 184 |
<MenuGroup> |
| 185 |
<MenuItem |
| 186 |
shortcut={shortcuts.insertBefore} |
| 187 |
onClick={() => { |
| 188 |
insertTextElement(elementIndex); |
| 189 |
onClose(); |
| 190 |
}} |
| 191 |
> |
| 192 |
{__("Add before", "tableberg")} |
| 193 |
</MenuItem> |
| 194 |
<MenuItem |
| 195 |
shortcut={shortcuts.insertAfter} |
| 196 |
onClick={() => { |
| 197 |
insertTextElement(elementIndex + 1); |
| 198 |
onClose(); |
| 199 |
}} |
| 200 |
> |
| 201 |
{__("Add after", "tableberg")} |
| 202 |
</MenuItem> |
| 203 |
</MenuGroup> |
| 204 |
<MenuGroup> |
| 205 |
<MenuItem |
| 206 |
shortcut={shortcuts.remove} |
| 207 |
onClick={() => { |
| 208 |
removeElementFromCell(cellCoords, elementIndex); |
| 209 |
onClose(); |
| 210 |
}} |
| 211 |
> |
| 212 |
{__("Delete", "tableberg")} |
| 213 |
</MenuItem> |
| 214 |
</MenuGroup> |
| 215 |
</> |
| 216 |
)} |
| 217 |
</ToolbarDropdownMenu> |
| 218 |
); |
| 219 |
} |
| 220 |
|
| 221 |
export function ElementOptionsBlockControls({ |
| 222 |
cellCoords, |
| 223 |
elementIndex, |
| 224 |
}: { |
| 225 |
cellCoords: CellKey; |
| 226 |
elementIndex: number; |
| 227 |
}) { |
| 228 |
return ( |
| 229 |
<BlockControls group="other"> |
| 230 |
<ElementOptionsButton |
| 231 |
cellCoords={cellCoords} |
| 232 |
elementIndex={elementIndex} |
| 233 |
/> |
| 234 |
</BlockControls> |
| 235 |
); |
| 236 |
} |
| 237 |
|