| 1 |
import { InspectorControls, FontSizePicker } from "@wordpress/block-editor"; |
| 2 |
import { __ } from "@wordpress/i18n"; |
| 3 |
import { |
| 4 |
PanelBody, |
| 5 |
SelectControl, |
| 6 |
Button, |
| 7 |
PanelRow, |
| 8 |
BaseControl, |
| 9 |
} from "@wordpress/components"; |
| 10 |
import { |
| 11 |
ColorControl, |
| 12 |
SizeControl, |
| 13 |
SpacingControlSingle, |
| 14 |
} from "@tableberg/components"; |
| 15 |
|
| 16 |
import { useTableStore } from "../../store"; |
| 17 |
import { DynamicDataPanel } from "../../components/DynamicDataPanel"; |
| 18 |
import LockedControl from "../../components/LockedControl"; |
| 19 |
import { ListElementAttributes, listAttrDefaults } from "./element"; |
| 20 |
import { CellKey } from "../../attributes"; |
| 21 |
import { ElementBindings } from "../../dynamic-data/types"; |
| 22 |
import { isProAvailable } from "../../pro-status"; |
| 23 |
|
| 24 |
interface ListElementControlsProps { |
| 25 |
attributes: ListElementAttributes; |
| 26 |
bindings?: ElementBindings; |
| 27 |
cellCoords: CellKey; |
| 28 |
elementIndex: number; |
| 29 |
allowListTypeSwitch?: boolean; |
| 30 |
// Injected by the pro plugin; null when pro is not installed. |
| 31 |
ProListIconSettings?: React.ReactNode; |
| 32 |
// Native block edits inject a setAttributes-based updater; store-backed |
| 33 |
// element renderers use the table-store fallback. |
| 34 |
updateAttrs?: (attrs: Partial<ListElementAttributes>) => void; |
| 35 |
} |
| 36 |
|
| 37 |
export function ListElementControls({ |
| 38 |
attributes, |
| 39 |
bindings, |
| 40 |
cellCoords, |
| 41 |
elementIndex, |
| 42 |
allowListTypeSwitch = true, |
| 43 |
updateAttrs, |
| 44 |
ProListIconSettings = null, |
| 45 |
}: ListElementControlsProps) { |
| 46 |
const isPro = isProAvailable(); |
| 47 |
|
| 48 |
const updateCellElement = useTableStore(state => state.updateCellElement); |
| 49 |
|
| 50 |
const applyAttrs = |
| 51 |
updateAttrs ?? |
| 52 |
((attrs: Partial<ListElementAttributes>) => |
| 53 |
updateCellElement(cellCoords, elementIndex, { |
| 54 |
attributes: attrs, |
| 55 |
})); |
| 56 |
|
| 57 |
const updateListType = (listType: "basic" | "styled") => { |
| 58 |
applyAttrs({ listType }); |
| 59 |
}; |
| 60 |
|
| 61 |
const updateListStyle = (listStyle: ListElementAttributes["listStyle"]) => { |
| 62 |
applyAttrs({ listStyle }); |
| 63 |
}; |
| 64 |
|
| 65 |
const updateStyle = <K extends keyof ListElementAttributes["styles"]>( |
| 66 |
key: K, |
| 67 |
value: ListElementAttributes["styles"][K] |
| 68 |
) => { |
| 69 |
applyAttrs({ |
| 70 |
styles: { |
| 71 |
...attributes.styles, |
| 72 |
[key]: value, |
| 73 |
}, |
| 74 |
}); |
| 75 |
}; |
| 76 |
|
| 77 |
return ( |
| 78 |
<> |
| 79 |
<InspectorControls> |
| 80 |
<PanelBody title={__("List Settings", "tableberg")} initialOpen> |
| 81 |
{allowListTypeSwitch && isPro && ( |
| 82 |
<SelectControl |
| 83 |
label={__("List Type", "tableberg")} |
| 84 |
value={attributes.listType} |
| 85 |
options={[ |
| 86 |
{ |
| 87 |
label: __("Basic", "tableberg"), |
| 88 |
value: "basic", |
| 89 |
}, |
| 90 |
{ |
| 91 |
label: __("Styled", "tableberg"), |
| 92 |
value: "styled", |
| 93 |
}, |
| 94 |
]} |
| 95 |
onChange={value => { |
| 96 |
updateListType(value as "basic" | "styled"); |
| 97 |
}} |
| 98 |
/> |
| 99 |
)} |
| 100 |
{allowListTypeSwitch && !isPro && ( |
| 101 |
<LockedControl selected="tableberg/styled-list"> |
| 102 |
<SelectControl |
| 103 |
label={__("List Type", "tableberg")} |
| 104 |
value={attributes.listType} |
| 105 |
options={[ |
| 106 |
{ |
| 107 |
label: __("Basic", "tableberg"), |
| 108 |
value: "basic", |
| 109 |
}, |
| 110 |
{ |
| 111 |
label: __("Styled", "tableberg"), |
| 112 |
value: "styled", |
| 113 |
}, |
| 114 |
]} |
| 115 |
onChange={() => null} |
| 116 |
/> |
| 117 |
</LockedControl> |
| 118 |
)} |
| 119 |
{attributes.listType === "basic" && ( |
| 120 |
<SelectControl |
| 121 |
label={__("List Style", "tableberg")} |
| 122 |
value={attributes.listStyle} |
| 123 |
options={[ |
| 124 |
{ |
| 125 |
label: __("Disc", "tableberg"), |
| 126 |
value: "disc", |
| 127 |
}, |
| 128 |
{ |
| 129 |
label: __("Circle", "tableberg"), |
| 130 |
value: "circle", |
| 131 |
}, |
| 132 |
{ |
| 133 |
label: __("Square", "tableberg"), |
| 134 |
value: "square", |
| 135 |
}, |
| 136 |
{ |
| 137 |
label: __("Numbered", "tableberg"), |
| 138 |
value: "decimal", |
| 139 |
}, |
| 140 |
{ |
| 141 |
label: __("None", "tableberg"), |
| 142 |
value: "none", |
| 143 |
}, |
| 144 |
]} |
| 145 |
onChange={value => { |
| 146 |
updateListStyle( |
| 147 |
value as ListElementAttributes["listStyle"] |
| 148 |
); |
| 149 |
}} |
| 150 |
/> |
| 151 |
)} |
| 152 |
<SpacingControlSingle |
| 153 |
label={__("Item Spacing", "tableberg")} |
| 154 |
value={attributes.styles.itemSpacing} |
| 155 |
onChange={value => updateStyle("itemSpacing", value)} |
| 156 |
/> |
| 157 |
</PanelBody> |
| 158 |
{/* |
| 159 |
* Icon markers are a pro feature: pro hands the whole Icon |
| 160 |
* Settings panel down. Free has no icon implementation. |
| 161 |
*/} |
| 162 |
{attributes.listType === "styled" && ProListIconSettings} |
| 163 |
<PanelBody title="Font Size" initialOpen={true}> |
| 164 |
<BaseControl __nextHasNoMarginBottom> |
| 165 |
<FontSizePicker |
| 166 |
value={attributes.styles.fontSize || undefined} |
| 167 |
onChange={value => { |
| 168 |
if (!value) { |
| 169 |
return; |
| 170 |
} |
| 171 |
updateStyle("fontSize", String(value)); |
| 172 |
}} |
| 173 |
/> |
| 174 |
</BaseControl> |
| 175 |
</PanelBody> |
| 176 |
<DynamicDataPanel elementType="list" bindings={bindings} /> |
| 177 |
</InspectorControls> |
| 178 |
<InspectorControls group="color"> |
| 179 |
<ColorControl |
| 180 |
label={__("Icon Color", "tableberg")} |
| 181 |
value={attributes.styles.iconColor} |
| 182 |
onChange={value => updateStyle("iconColor", value)} |
| 183 |
onDeselect={() => |
| 184 |
updateStyle( |
| 185 |
"iconColor", |
| 186 |
listAttrDefaults.styles.iconColor |
| 187 |
) |
| 188 |
} |
| 189 |
/> |
| 190 |
<ColorControl |
| 191 |
label={__("Text Color", "tableberg")} |
| 192 |
value={attributes.styles.textColor} |
| 193 |
onChange={value => updateStyle("textColor", value)} |
| 194 |
onDeselect={() => |
| 195 |
updateStyle( |
| 196 |
"textColor", |
| 197 |
listAttrDefaults.styles.textColor |
| 198 |
) |
| 199 |
} |
| 200 |
/> |
| 201 |
<ColorControl |
| 202 |
label={__("Link Color", "tableberg")} |
| 203 |
value={attributes.styles.linkColor} |
| 204 |
onChange={value => updateStyle("linkColor", value)} |
| 205 |
onDeselect={() => |
| 206 |
updateStyle( |
| 207 |
"linkColor", |
| 208 |
listAttrDefaults.styles.linkColor |
| 209 |
) |
| 210 |
} |
| 211 |
/> |
| 212 |
<ColorControl |
| 213 |
label={__("Background Color", "tableberg")} |
| 214 |
value={attributes.styles.backgroundColor} |
| 215 |
onChange={value => updateStyle("backgroundColor", value)} |
| 216 |
onDeselect={() => |
| 217 |
updateStyle( |
| 218 |
"backgroundColor", |
| 219 |
listAttrDefaults.styles.backgroundColor |
| 220 |
) |
| 221 |
} |
| 222 |
/> |
| 223 |
</InspectorControls> |
| 224 |
</> |
| 225 |
); |
| 226 |
} |
| 227 |
|