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 / elements / icon / index.tsx

index.tsx in Tableberg – Simple Gutenberg Table Block 1.1.5, at src/elements/icon/index.tsx

255 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { useRef } from "react";
2 import { __ } from "@wordpress/i18n";
3 import classNames from "classnames";
4 import { mergeAttrsWithDefaultsAndApplyBindings } from "@tableberg/shared/utils/merge-attrs-with-defaults-and-apply-bindings";
5
6 import { useTableStore } from "../../store";
7 import { useClickOutside } from "../../hooks/useClickOutside";
8 import { ElementRendererProps } from "../index";
9 import { IconElementControls } from "./controls";
10 import { BindableAttribute, ElementBindings } from "../../dynamic-data/types";
11 import { useDynamicDataBindings } from "../../dynamic-data/hooks/useDynamicData";
12
13 export interface IconElementAttributes {
14 icon: {
15 iconName: string;
16 svg?: {
17 viewBox: string;
18 path: string;
19 };
20 url?: string;
21 };
22 size: string;
23 behavior: "paragraph" | "char";
24 link: {
25 url: string;
26 target: "_blank" | "_self";
27 };
28 styles: {
29 align: "left" | "center" | "right";
30 rotation: number;
31 color: string;
32 colorHover: string;
33 background: string;
34 backgroundHover: string;
35 padding: {
36 top: string;
37 right: string;
38 bottom: string;
39 left: string;
40 };
41 border: {
42 top: string;
43 right: string;
44 bottom: string;
45 left: string;
46 };
47 borderRadius: {
48 topLeft: string;
49 topRight: string;
50 bottomRight: string;
51 bottomLeft: string;
52 };
53 };
54 }
55
56 export const iconAttrDefaults: IconElementAttributes = {
57 icon: {
58 iconName: "check",
59 svg: {
60 viewBox: "0 0 512 512",
61 path: "M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z",
62 },
63 },
64 size: "40px",
65 behavior: "paragraph",
66 link: {
67 url: "",
68 target: "_self",
69 },
70 styles: {
71 align: "left",
72 rotation: 0,
73 color: "",
74 colorHover: "",
75 background: "",
76 backgroundHover: "",
77 padding: {
78 top: "var(--wp--preset--spacing--20)",
79 right: "var(--wp--preset--spacing--20)",
80 bottom: "var(--wp--preset--spacing--20)",
81 left: "var(--wp--preset--spacing--20)",
82 },
83 border: {
84 top: "",
85 right: "",
86 bottom: "",
87 left: "",
88 },
89 borderRadius: {
90 topLeft: "",
91 topRight: "",
92 bottomLeft: "",
93 bottomRight: "",
94 },
95 },
96 };
97
98 export interface IconElementType {
99 name: "icon";
100 attributes: IconElementAttributes;
101 bindings?: ElementBindings;
102 }
103
104 export function IconElement({
105 attributes,
106 bindings,
107 cellCoords,
108 elementIndex,
109 }: ElementRendererProps<IconElementAttributes>) {
110 const wrapperRef = useRef<HTMLDivElement>(null);
111
112 const sortPreviewMode = useTableStore(state => state.sortPreviewMode);
113 const isElementSelected = useTableStore(state => state.isElementSelected);
114 const setSelectedElement = useTableStore(state => state.setSelectedElement);
115 const clearSelectedElement = useTableStore(
116 state => state.clearSelectedElement
117 );
118
119 const isSelected = isElementSelected(cellCoords, elementIndex);
120
121 useClickOutside({
122 ref: wrapperRef,
123 onClickOutside: () => {
124 if (isSelected) {
125 clearSelectedElement();
126 }
127 },
128 });
129
130 const { values: previewValues } = useDynamicDataBindings(bindings);
131
132 const mergedAttrs = mergeAttrsWithDefaultsAndApplyBindings(
133 attributes,
134 iconAttrDefaults,
135 bindings,
136 previewValues,
137 __("(No data)", "tableberg")
138 );
139
140 const { icon, size, behavior, link, styles } = mergedAttrs;
141
142 const wrapperClassName = classNames("tableberg-icon", {
143 "tableberg-icon-as-char": behavior === "char",
144 });
145
146 const wrapperStyle: Record<string, string | undefined> = {
147 "background": styles.background || undefined,
148 "transform": styles.rotation
149 ? `rotate(${styles.rotation}deg)`
150 : undefined,
151 "paddingTop": styles.padding.top,
152 "paddingRight": styles.padding.right,
153 "paddingBottom": styles.padding.bottom,
154 "paddingLeft": styles.padding.left,
155 "borderTop": styles.border.top,
156 "borderRight": styles.border.right,
157 "borderBottom": styles.border.bottom,
158 "borderLeft": styles.border.left,
159 "borderTopLeftRadius": styles.borderRadius.topLeft,
160 "borderTopRightRadius": styles.borderRadius.topRight,
161 "borderBottomRightRadius": styles.borderRadius.bottomRight,
162 "borderBottomLeftRadius": styles.borderRadius.bottomLeft,
163 "--tableberg-icon-color-hover":
164 styles.colorHover || styles.color || undefined,
165 "--tableberg-icon-bg-hover":
166 styles.backgroundHover || styles.background || undefined,
167 };
168
169 let iconContent: JSX.Element | null = null;
170
171 if (icon.svg) {
172 iconContent = (
173 <svg
174 viewBox={icon.svg.viewBox}
175 xmlns="http://www.w3.org/2000/svg"
176 height={size}
177 width={size}
178 style={{ fill: styles.color || undefined }}
179 >
180 <path d={icon.svg.path} />
181 </svg>
182 );
183 }
184
185 if (icon.url) {
186 iconContent = (
187 <img
188 src={icon.url}
189 alt=""
190 style={{
191 height: size,
192 width: size,
193 }}
194 />
195 );
196 }
197
198 const handleClick = () => {
199 if (!sortPreviewMode) {
200 setSelectedElement(cellCoords, elementIndex);
201 }
202 };
203
204 return (
205 <>
206 {isSelected && (
207 <IconElementControls
208 attributes={mergedAttrs}
209 bindings={bindings}
210 cellCoords={cellCoords}
211 elementIndex={elementIndex}
212 />
213 )}
214 <div
215 ref={wrapperRef}
216 className={wrapperClassName}
217 style={wrapperStyle}
218 onClick={handleClick}
219 >
220 {link.url ? (
221 <a
222 href={link.url}
223 target={link.target}
224 rel={
225 link.target === "_blank"
226 ? "noopener noreferrer"
227 : undefined
228 }
229 onClick={e => e.preventDefault()}
230 >
231 {iconContent}
232 </a>
233 ) : (
234 iconContent
235 )}
236 </div>
237 </>
238 );
239 }
240
241 export const iconBindableAttributes: BindableAttribute[] = [
242 {
243 path: "link.url",
244 label: __("Link URL", "tableberg"),
245 },
246 {
247 path: "styles.color",
248 label: __("Icon Color", "tableberg"),
249 },
250 {
251 path: "styles.background",
252 label: __("Background Color", "tableberg"),
253 },
254 ];
255