PluginProbe
Tableberg – Simple Gutenberg Table Block / 1.1.5
Tableberg – Simple Gutenberg Table Block v1.1.5
1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 trunk 0.0.2 0.2.1 0.3.2 0.3.3 0.4.1 0.5.0 0.5.1 0.5.2 0.5.3 0.5.4 0.5.5 0.5.6 0.5.7 All 42 releases
tableberg / src / blocks / button / controls.tsx

controls.tsx in Tableberg – Simple Gutenberg Table Block 1.1.5, at src/blocks/button/controls.tsx

369 lines 14.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { useState, useMemo } from "react";
2 import {
3 InspectorControls,
4 BlockControls,
5 AlignmentControl,
6 FontSizePicker,
7 __experimentalLinkControl as LinkControl,
8 } from "@wordpress/block-editor";
9 import {
10 justifyLeft,
11 justifyCenter,
12 justifyRight,
13 link,
14 linkOff,
15 } from "@wordpress/icons";
16 import {
17 PanelBody,
18 BaseControl,
19 ToolbarButton,
20 Popover,
21 TextControl,
22 __experimentalToggleGroupControl as ToggleGroupControl,
23 __experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon,
24 __experimentalToggleGroupControlOption as ToggleGroupControlOption,
25 } from "@wordpress/components";
26 import { __ } from "@wordpress/i18n";
27 import { prependHTTP } from "@wordpress/url";
28 import {
29 SpacingControl,
30 ColorControl,
31 BorderRadiusControl,
32 } from "@tableberg/components";
33 import { CellKey } from "../../attributes";
34 import { useTableStore } from "../../store";
35 import { buttonAttrDefaults, ButtonElementAttributes } from "./element";
36 import { DynamicDataPanel } from "../../components/DynamicDataPanel";
37 import { ElementBindings } from "../../dynamic-data/types";
38 import { ElementDeleteButton } from "../../components/ElementDeleteButton";
39 import { ElementOptionsBlockControls } from "../../components/ElementOptionsButton";
40
41 export function ButtonElementControls({
42 attributes,
43 bindings,
44 cellCoords,
45 elementIndex,
46 updateStyles: updateStylesProp,
47 updateAttrs: updateAttrsProp,
48 }: {
49 attributes: ButtonElementAttributes;
50 bindings?: ElementBindings;
51 cellCoords: CellKey;
52 elementIndex: number;
53 // Native block edits inject setAttributes-based updaters; store-backed
54 // element renderers use the table-store fallbacks.
55 updateStyles?: (
56 styles: Partial<ButtonElementAttributes["styles"]>
57 ) => void;
58 updateAttrs?: (attrs: Partial<ButtonElementAttributes>) => void;
59 }) {
60 const { styles, link: linkAttrs, id, align } = attributes;
61
62 const storeUpdateStyles = useTableStore(
63 state => state.updateSelectedElementStyles
64 );
65 const storeUpdateAttrs = useTableStore(
66 state => state.updateSelectedElementAttrs
67 );
68 const updateStyles = updateStylesProp ?? storeUpdateStyles;
69 const updateAttrs = updateAttrsProp ?? storeUpdateAttrs;
70
71 const [isEditingURL, setIsEditingURL] = useState(false);
72
73 const linkUrlIsBound = !!bindings?.["link.url"];
74 const textColorIsBound = !!bindings?.["styles.textColor"];
75 const backgroundColorIsBound = !!bindings?.["styles.backgroundColor"];
76 const idIsBound = !!bindings?.id;
77
78 const isURLSet = !!linkAttrs.url;
79 const opensInNewTab = linkAttrs.target === "_blank";
80
81 const linkValue = useMemo(
82 () => ({ url: linkAttrs.url, opensInNewTab }),
83 [linkAttrs.url, opensInNewTab]
84 );
85
86 const unlink = () => {
87 updateAttrs({
88 link: buttonAttrDefaults.link,
89 });
90 setIsEditingURL(false);
91 };
92
93 const validWidthValues = ["auto", "25%", "50%", "75%", "100%"];
94
95 return (
96 <>
97 <BlockControls group="block">
98 <AlignmentControl
99 value={styles.textAlign}
100 onChange={(textAlign: string) => {
101 if (
102 textAlign !== "left" &&
103 textAlign !== "center" &&
104 textAlign !== "right"
105 ) {
106 textAlign = buttonAttrDefaults.styles.textAlign;
107 }
108
109 updateStyles({
110 textAlign: textAlign,
111 });
112 }}
113 />
114 <ToolbarButton
115 icon={link}
116 title={
117 linkUrlIsBound
118 ? __("Link URL is dynamically bound", "tableberg")
119 : isURLSet
120 ? __("Unlink", "tableberg")
121 : __("Link", "tableberg")
122 }
123 onClick={
124 linkUrlIsBound
125 ? undefined
126 : isURLSet
127 ? unlink
128 : () => setIsEditingURL(true)
129 }
130 isActive={isURLSet || linkUrlIsBound}
131 disabled={linkUrlIsBound}
132 />
133 <ElementDeleteButton
134 cellCoords={cellCoords}
135 elementIndex={elementIndex}
136 />
137 {isEditingURL && !linkUrlIsBound && (
138 <Popover
139 placement="bottom"
140 onClose={() => setIsEditingURL(false)}
141 shift
142 >
143 <LinkControl
144 value={linkValue}
145 onChange={({
146 url: newURL = "",
147 opensInNewTab: newOpensInNewTab,
148 }: {
149 url?: string;
150 opensInNewTab?: boolean;
151 }) => {
152 updateAttrs({
153 link: {
154 ...linkAttrs,
155 url: prependHTTP(newURL),
156 target: newOpensInNewTab
157 ? "_blank"
158 : "_self",
159 },
160 });
161 }}
162 onRemove={unlink}
163 />
164 </Popover>
165 )}
166 </BlockControls>
167 <ElementOptionsBlockControls
168 cellCoords={cellCoords}
169 elementIndex={elementIndex}
170 />
171 <InspectorControls group="color">
172 <ColorControl
173 label={
174 textColorIsBound
175 ? __("Text (dynamic)", "tableberg")
176 : __("Text", "tableberg")
177 }
178 value={styles.textColor}
179 onChange={textColor => updateStyles({ textColor })}
180 onDeselect={() =>
181 updateStyles({
182 textColor: buttonAttrDefaults.styles.textColor,
183 })
184 }
185 />
186 <ColorControl
187 label={__("Hover Text", "tableberg")}
188 value={styles.textHoverColor}
189 onChange={textHoverColor =>
190 updateStyles({ textHoverColor })
191 }
192 onDeselect={() =>
193 updateStyles({
194 textHoverColor:
195 buttonAttrDefaults.styles.textHoverColor,
196 })
197 }
198 />
199 <ColorControl
200 label={
201 backgroundColorIsBound
202 ? __("Background (dynamic)", "tableberg")
203 : __("Background", "tableberg")
204 }
205 value={styles.backgroundColor}
206 onChange={backgroundColor =>
207 updateStyles({ backgroundColor })
208 }
209 onDeselect={() =>
210 updateStyles({
211 backgroundColor:
212 buttonAttrDefaults.styles.backgroundColor,
213 })
214 }
215 />
216 <ColorControl
217 label={__("Hover Background", "tableberg")}
218 value={styles.backgroundHoverColor}
219 onChange={backgroundHoverColor =>
220 updateStyles({ backgroundHoverColor })
221 }
222 onDeselect={() =>
223 updateStyles({
224 backgroundHoverColor:
225 buttonAttrDefaults.styles.backgroundHoverColor,
226 })
227 }
228 />
229 </InspectorControls>
230 <InspectorControls group="dimensions">
231 <SpacingControl
232 label={__("Padding", "tableberg")}
233 value={styles.padding}
234 onChange={padding => updateStyles({ padding })}
235 onDeselect={() =>
236 updateStyles({
237 padding: buttonAttrDefaults.styles.padding,
238 })
239 }
240 hasValue={() =>
241 !!styles.padding.top ||
242 !!styles.padding.right ||
243 !!styles.padding.bottom ||
244 !!styles.padding.left
245 }
246 />
247 <BorderRadiusControl
248 label={__("Border Radius", "tableberg")}
249 value={styles.borderRadius}
250 onChange={borderRadius => updateStyles({ borderRadius })}
251 onDeselect={() =>
252 updateStyles({
253 borderRadius:
254 buttonAttrDefaults.styles.borderRadius,
255 })
256 }
257 hasValue={() =>
258 !!styles.borderRadius.topLeft ||
259 !!styles.borderRadius.topRight ||
260 !!styles.borderRadius.bottomLeft ||
261 !!styles.borderRadius.bottomRight
262 }
263 />
264 </InspectorControls>
265 <InspectorControls>
266 <PanelBody title={__("Typography", "tableberg")}>
267 <BaseControl __nextHasNoMarginBottom>
268 <FontSizePicker
269 value={styles.fontSize}
270 onChange={fontSize => {
271 updateStyles({
272 fontSize:
273 fontSize ||
274 buttonAttrDefaults.styles.fontSize,
275 });
276 }}
277 />
278 </BaseControl>
279 </PanelBody>
280 </InspectorControls>
281 <InspectorControls group="advanced">
282 <TextControl
283 __nextHasNoMarginBottom
284 autoComplete="off"
285 label={
286 idIsBound
287 ? __("HTML ID (dynamic)", "tableberg")
288 : __("HTML ID", "tableberg")
289 }
290 help={
291 idIsBound
292 ? __("Overridden by dynamic data", "tableberg")
293 : ""
294 }
295 value={id}
296 onChange={id => updateAttrs({ id })}
297 />
298 </InspectorControls>
299 <InspectorControls>
300 <PanelBody title={__("Button Settings", "tableberg")}>
301 <ToggleGroupControl
302 label={__("Button Alignment", "tableberg")}
303 value={align}
304 onChange={value => {
305 if (
306 value !== "left" &&
307 value !== "center" &&
308 value !== "right"
309 ) {
310 value = buttonAttrDefaults.align;
311 }
312
313 updateAttrs({
314 align: value,
315 });
316 }}
317 isBlock
318 >
319 <ToggleGroupControlOptionIcon
320 value="left"
321 label={__("Left", "tableberg")}
322 icon={justifyLeft}
323 />
324 <ToggleGroupControlOptionIcon
325 value="center"
326 label={__("Center", "tableberg")}
327 icon={justifyCenter}
328 />
329 <ToggleGroupControlOptionIcon
330 value="right"
331 label={__("Right", "tableberg")}
332 icon={justifyRight}
333 />
334 </ToggleGroupControl>
335 <ToggleGroupControl
336 label={__("Width", "tableberg")}
337 value={styles.width}
338 onChange={width => {
339 if (!width || typeof width === "number") {
340 width = buttonAttrDefaults.styles.width;
341 }
342
343 if (!validWidthValues.includes(width)) {
344 width = buttonAttrDefaults.styles.width;
345 }
346
347 updateStyles({ width });
348 }}
349 isBlock
350 >
351 {validWidthValues.map(widthValue => {
352 return (
353 <ToggleGroupControlOption
354 key={widthValue}
355 value={widthValue}
356 label={__(widthValue, "tableberg")}
357 />
358 );
359 })}
360 </ToggleGroupControl>
361 </PanelBody>
362 </InspectorControls>
363 <InspectorControls>
364 <DynamicDataPanel elementType="button" bindings={bindings} />
365 </InspectorControls>
366 </>
367 );
368 }
369