PluginProbe
Tableberg – Simple Gutenberg Table Block / 1.2.0
Tableberg – Simple Gutenberg Table Block v1.2.0
1.2.0 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 All 43 releases
tableberg / src / blocks / button / controls.tsx

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

388 lines 14.9 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={__("Style", "tableberg")}
303 value={styles.variant ?? "fill"}
304 onChange={value => {
305 updateStyles({
306 variant: value === "outline" ? "outline" : "fill",
307 });
308 }}
309 isBlock
310 >
311 <ToggleGroupControlOption
312 value="fill"
313 label={__("Fill", "tableberg")}
314 />
315 <ToggleGroupControlOption
316 value="outline"
317 label={__("Outline", "tableberg")}
318 />
319 </ToggleGroupControl>
320 <ToggleGroupControl
321 label={__("Button Alignment", "tableberg")}
322 value={align}
323 onChange={value => {
324 if (
325 value !== "left" &&
326 value !== "center" &&
327 value !== "right"
328 ) {
329 value = buttonAttrDefaults.align;
330 }
331
332 updateAttrs({
333 align: value,
334 });
335 }}
336 isBlock
337 >
338 <ToggleGroupControlOptionIcon
339 value="left"
340 label={__("Left", "tableberg")}
341 icon={justifyLeft}
342 />
343 <ToggleGroupControlOptionIcon
344 value="center"
345 label={__("Center", "tableberg")}
346 icon={justifyCenter}
347 />
348 <ToggleGroupControlOptionIcon
349 value="right"
350 label={__("Right", "tableberg")}
351 icon={justifyRight}
352 />
353 </ToggleGroupControl>
354 <ToggleGroupControl
355 label={__("Width", "tableberg")}
356 value={styles.width}
357 onChange={width => {
358 if (!width || typeof width === "number") {
359 width = buttonAttrDefaults.styles.width;
360 }
361
362 if (!validWidthValues.includes(width)) {
363 width = buttonAttrDefaults.styles.width;
364 }
365
366 updateStyles({ width });
367 }}
368 isBlock
369 >
370 {validWidthValues.map(widthValue => {
371 return (
372 <ToggleGroupControlOption
373 key={widthValue}
374 value={widthValue}
375 label={__(widthValue, "tableberg")}
376 />
377 );
378 })}
379 </ToggleGroupControl>
380 </PanelBody>
381 </InspectorControls>
382 <InspectorControls>
383 <DynamicDataPanel elementType="button" bindings={bindings} />
384 </InspectorControls>
385 </>
386 );
387 }
388