PluginProbe
Smart Post – Post Grid, Post Carousel, Post Slider Gutenberg Blocks for Blog & News / 4.0.7
Smart Post – Post Grid, Post Carousel, Post Slider Gutenberg Blocks for Blog & News v4.0.7
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 2.3.5 2.3.6 2.4.0 2.4.1 2.4.10 2.4.11 2.4.12 2.4.13 2.4.14 2.4.15 2.4.16 2.4.17 2.4.18 2.4.19 2.4.2 2.4.20 2.4.21 All 88 releases
post-carousel / src / components / global-typography / typography.js

typography.js in Smart Post – Post Grid, Post Carousel, Post Slider Gutenberg Blocks for Blog & News 4.0.7, at src/components/global-typography/typography.js

632 lines 17.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import Select from "react-select";
2 import { __ } from "@wordpress/i18n";
3 import { Button, Flex, Popover, Tooltip } from "@wordpress/components";
4 import { Fragment, useEffect, useRef, useState } from "@wordpress/element";
5 import ComponentsTopSection from "../componentsTopControl/ComponentsTopSection.js";
6 import "../typography/editor.scss";
7 import SelectField from "../selectField/selectField.js";
8 import { fontWeightMap, getFontWeightList, textCaseOptions, textDecorationOptions } from "../typography/utility.js";
9 import InputControl from "../inputControl/inputControl.js";
10 import { useDeviceType } from "../../controls/controls.js";
11 import { BorderIcon } from "../../icons/icons.js";
12 import { useSelect } from "@wordpress/data";
13 import useGoogleFonts from "../../hooks/useGoogleFontApi.js";
14
15 const GlobalTypography = ({ attributes, typographyLabel = "Typography", typoItem, onChangeAttr, deleteAction }) => {
16 const fontFamilies = useSelect((select) => {
17 const settings = select("core/editor")?.getEditorSettings();
18 return settings?.__experimentalFeatures?.typography?.fontFamilies || [];
19 }, []);
20 const [systemFonts, setSystemFonts] = useState([]);
21 const [allFonts, setAllFonts] = useState([]);
22 const [fontLists, setFontLists] = useState([]);
23 const [fontInfo, setFontInfo] = useState(typoItem);
24 const { wordSpacing } = attributes;
25 const deviceType = useDeviceType();
26 const typographyBtnRef = useRef(null);
27
28 const [isVisible, setIsVisible] = useState(false);
29
30 const toggleVisible = () => {
31 setIsVisible((state) => !state);
32
33 if (isVisible) {
34 onChangeAttr(fontInfo);
35 }
36 };
37
38 const { googleFonts } = useGoogleFonts();
39
40 useEffect(() => {
41 if (allFonts.length === 0 && googleFonts.length > 0) {
42 let wpFonts = [];
43 if (fontFamilies) {
44 const customFonts = fontFamilies.custom || [];
45 const themeFonts = fontFamilies.theme || [];
46 const _systemFonts = [...customFonts, ...themeFonts];
47 wpFonts = _systemFonts?.map((f) => {
48 const variants = f?.fontFace?.map((v) => v.fontWeight);
49 return {
50 label: f.name,
51 value: f.fontFamily,
52 type: "system",
53 font: {
54 family: f.fontFamily,
55 variants:
56 variants?.length > 0
57 ? variants[0]?.split(" ")
58 : ["300", "400", "500", "600", "700", "800"],
59 },
60 };
61 });
62 }
63
64 const grouped = [
65 ...(wpFonts.length > 0 ? [{ label: "System Fonts", options: wpFonts }] : []),
66 {
67 label: "Google Fonts",
68 options: googleFonts.filter((font, i) => i < 50 && font),
69 },
70 ];
71 setSystemFonts(wpFonts);
72 setAllFonts([...wpFonts, ...googleFonts]);
73 setFontLists(grouped);
74 }
75 }, [googleFonts, fontFamilies]);
76
77 const fontSearch = (inputValue) => {
78 if (!inputValue) {
79 setFontLists([
80 ...(systemFonts.length > 0
81 ? [
82 {
83 label: "System Fonts",
84 options: systemFonts,
85 },
86 ]
87 : []),
88 {
89 label: "Google Fonts",
90 options: googleFonts.filter((font, i) => i < 50 && font),
91 },
92 ]);
93 return;
94 }
95
96 const searchedFonts = allFonts
97 .filter((font) => font.label.toLowerCase().includes(inputValue.toLowerCase()))
98 .slice(0, 30);
99
100 setFontLists([
101 {
102 label: "Search Result",
103 options: searchedFonts,
104 },
105 ]);
106 };
107
108 // default and active family options.
109 const defaultFamilyOption = {
110 label: "Default",
111 value: "",
112 font: { variants: ["regular"] },
113 };
114
115 const activeFontFamily =
116 fontInfo.typography.family === ""
117 ? defaultFamilyOption
118 : {
119 label:
120 allFonts?.find((font) => font.value === fontInfo.typography.family)?.label ||
121 fontInfo.typography.family,
122 value: fontInfo.typography?.family,
123 font: fontInfo.typography.font,
124 };
125
126 useEffect(() => {
127 const clickOutSite = (e) => {
128 const target = e.target.closest(".sp-smart-post-typography-fonts");
129
130 const buttonTarget = e.target.closest(`.sp-smart-post-typography-btn button.button-${fontInfo?.slug}`);
131 const familyTarget = e.target.closest(".css-1nmdiq5-menu");
132
133 if (!target && isVisible && !buttonTarget && !familyTarget) {
134 setIsVisible(false);
135
136 onChangeAttr(fontInfo);
137 }
138 };
139 window.addEventListener("click", clickOutSite);
140
141 return () => window.removeEventListener("click", clickOutSite);
142 });
143
144 const allFamilyList = [defaultFamilyOption, ...fontLists];
145
146 const isAvailableOnList = allFamilyList?.find((font) => font.value === activeFontFamily.value);
147
148 const fontFamilySelectOptions = isAvailableOnList
149 ? allFamilyList
150 : [defaultFamilyOption, activeFontFamily, ...fontLists];
151
152 // Set Font Family Function.
153 const selectFontFamily = (newValue) => {
154 const newData = {
155 ...fontInfo,
156 typography: {
157 ...fontInfo.typography,
158 family: newValue.value,
159 type: "system" === newValue.type ? "system" : "google",
160 font: newValue.font,
161 fontWeight: "400",
162 },
163 };
164
165 setFontInfo(newData);
166 };
167
168 // Set font weight and font style function.
169 const onChangeFontWeight = (fontWeight) => {
170 const arrayOfStyles = fontWeightMap[fontWeight]?.split(" ");
171 const style = fontWeightMap[fontWeight].includes("italic") ? "italic" : "normal";
172
173 let weight = arrayOfStyles[arrayOfStyles.length - 1];
174 weight = "italic" === style && "400" === weight ? "italic" : weight;
175
176 const newData = {
177 ...fontInfo,
178 typography: {
179 ...fontInfo.typography,
180 fontWeight: weight,
181 style: style,
182 },
183 };
184
185 setFontInfo(newData);
186 };
187
188 // Set font line height function.
189 const onChangeLineHeight = (newValue) => {
190 const newData = {
191 ...fontInfo,
192 lineHeight: {
193 ...fontInfo.lineHeight,
194 device: {
195 ...fontInfo.lineHeight.device,
196 [deviceType]: newValue,
197 },
198 },
199 };
200
201 setFontInfo(newData);
202 };
203
204 // Set letter spacing function.
205 const letterSpacing = (newValue) => {
206 const newData = {
207 ...fontInfo,
208 letterSpacing: {
209 ...fontInfo.letterSpacing,
210 device: {
211 ...fontInfo.letterSpacing.device,
212 [deviceType]: newValue,
213 },
214 },
215 };
216
217 setFontInfo(newData);
218 };
219
220 // Set word spacing function.
221 const wordSpacingFn = (newValue) => {
222 const newData = {
223 ...fontInfo,
224 wordSpacing: {
225 ...fontInfo.wordSpacing,
226 device: {
227 ...fontInfo.wordSpacing.device,
228 [deviceType]: newValue,
229 },
230 },
231 };
232
233 setFontInfo(newData);
234 };
235
236 // Set font size function.
237 const onChangeFontSize = (newValue) => {
238 const newData = {
239 ...fontInfo,
240 fontSize: {
241 ...fontInfo.fontSize,
242 device: {
243 ...fontInfo.fontSize.device,
244 [deviceType]: newValue,
245 },
246 },
247 };
248
249 setFontInfo(newData);
250 };
251
252 // Set unit function.
253 const unitChange = (newUnit, key) => {
254 const newData = {
255 ...fontInfo,
256 [key]: {
257 ...fontInfo[key],
258 unit: {
259 ...fontInfo[key].unit,
260 [newUnit.deviceType]: newUnit.unit,
261 },
262 },
263 };
264
265 setFontInfo(newData);
266 };
267
268 // Reset function.
269 // const onReset = ( defaultValue, key ) => {
270 // const newData = {
271 // ...fontInfo,
272 // [key]: {
273 // ...fontInfo[key],
274 // "unit": {
275 // ...fontInfo.fontSize.unit,
276 // "Desktop": defaultValue.unit,
277 // },
278 // "device": {
279 // ...fontInfo.fontSize.device,
280 // "Desktop": defaultValue.value,
281 // },
282 // },
283 // };
284
285 // setFontInfo( newData );
286 // };
287
288 // Set text style function.
289 const onChangeTextStyles = (key, value) => {
290 const newValue = fontInfo?.typography[key] === value ? "" : value;
291
292 const newData = {
293 ...fontInfo,
294 typography: { ...fontInfo.typography, [key]: newValue },
295 };
296
297 setFontInfo(newData);
298 };
299
300 // Title text change
301 const onChangeFontTitle = (e) => {
302 const newData = { ...fontInfo, title: e.target.value };
303
304 setFontInfo(newData);
305 };
306
307 // Update fontSize and lineHeight
308 const onChangeSizes = (newValue, index, key) => {
309 const newSizes = fontInfo?.sizes?.map((size, i) =>
310 i === index
311 ? {
312 ...size,
313 [key]: {
314 ...size[key],
315 device: {
316 ...size[key]?.device,
317 [deviceType]: newValue,
318 },
319 },
320 }
321 : size
322 );
323
324 const newData = { ...fontInfo, sizes: newSizes };
325
326 setFontInfo(newData);
327 };
328
329 const onChangeSizesUnit = (newValue, index, key) => {
330 const newSizes = fontInfo?.sizes?.map((size, i) =>
331 i === index
332 ? {
333 ...size,
334 [key]: {
335 ...size[key],
336 unit: {
337 ...size[key]?.unit,
338 [deviceType]: newValue?.unit,
339 },
340 },
341 }
342 : size
343 );
344
345 const newData = { ...fontInfo, sizes: newSizes };
346
347 setFontInfo(newData);
348 };
349
350 return (
351 <>
352 <div className="sp-smart-post-typography sp-smart-post-component-mb sp-smart-post-tab-panel">
353 <div
354 className={`sp-smart-post-typography-btn sp-smart-post-button ${isVisible && "active"}`}
355 ref={typographyBtnRef}
356 >
357 <p className="sp-smart-post-component-title">{typographyLabel}</p>
358 <div className="sp-smart-post-header-right">
359 <Button
360 className={`components-button sp-smart-post-border-icon-button active has-icon button-${
361 fontInfo?.slug
362 } ${isVisible ? "button-clicked" : ""}`}
363 aria-label={isVisible ? "open typography popup" : "close typography popup"}
364 onClick={() => toggleVisible(fontInfo?.slug)}
365 >
366 {<BorderIcon isActive={isVisible} />}
367 </Button>
368 </div>
369 </div>
370
371 {isVisible && (
372 <Popover shift={true} focusOnMount={false}>
373 <div className={`sp-smart-post-typography-fonts sp-smart-global-typography`}>
374 <div className="sp-smart-post-typography-header">
375 <h4>
376 {!["heading", "body", "button"].includes(fontInfo.slug) ? (
377 <>
378 <span>Name</span>
379 <input
380 name={fontInfo?.slug}
381 value={fontInfo.title}
382 onChange={onChangeFontTitle}
383 />
384 </>
385 ) : (
386 `${fontInfo.title} Typography`
387 )}
388 </h4>
389 {!["heading", "body", "button"].includes(fontInfo.slug) && (
390 <Button
391 className="sp-smart-typography-dots"
392 onClick={() => {
393 deleteAction(typoItem);
394 setIsVisible(false);
395 }}
396 >
397 <svg
398 width="20"
399 height="20"
400 viewBox="0 0 20 20"
401 fill="#000"
402 xmlns="http://www.w3.org/2000/svg"
403 >
404 <path
405 d="M12 4H15C15.6 4 16 4.4 16 5V6H3V5C3 4.4 3.5 4 4 4H7C7.2 2.9 8.3 2 9.5 2C10.7 2 11.8 2.9 12 4ZM8 4H11C10.8 3.4 10.1 3 9.5 3C8.9 3 8.2 3.4 8 4ZM4 7H15L14.1 17.1C14.1 17.6 13.6 18 13.1 18H5.9C5.4 18 5 17.6 4.9 17.1L4 7Z"
406 fill="#000"
407 />
408 </svg>
409 </Button>
410 )}
411 </div>
412 <div className="sp-smart-post-typography-fields">
413 <div className={`sp-smart-post-typography-family sp-smart-post-component-mb`}>
414 <div className="sp-smart-post-select-field">
415 <div className="sp-smart-post-header">
416 <span className="sp-smart-post-component-title">
417 {" "}
418 Font Family
419 </span>
420 </div>
421
422 <Select
423 options={fontFamilySelectOptions}
424 value={activeFontFamily}
425 placeholder={activeFontFamily.label}
426 onChange={(newValue) => selectFontFamily(newValue)}
427 onInputChange={(inputValue) => fontSearch(inputValue)}
428 />
429 </div>
430 </div>
431 <SelectField
432 label={__("Font Style", "post-carousel")}
433 attributes={fontInfo?.fontWeight}
434 items={getFontWeightList(activeFontFamily)}
435 onChange={(newStyle) => onChangeFontWeight(newStyle)}
436 __nextHasNoMarginBottom
437 />
438 </div>
439
440 {!fontInfo.sizes && (
441 <>
442 <div className="sp-smart-post-typography-word-spacing-latter-spacing-wrapper sp-d-flex sp-gap-8px">
443 <div className="sp-smart-post-typography-line-height-picker">
444 <ComponentsTopSection
445 label={__("Font Size", "post-carousel")}
446 onUnitChange={(newUnit) => unitChange(newUnit, "fontSize")}
447 attributes={fontInfo?.fontSize}
448 // setAttributes={ setAttributes }
449 units={["px", "%", "em"]}
450 />
451 <InputControl
452 attributes={fontInfo?.fontSize?.device?.[deviceType]}
453 type="number"
454 onChange={onChangeFontSize}
455 min={0}
456 />
457 </div>
458 <div className="sp-smart-post-typography-letter-spacing-picker">
459 <ComponentsTopSection
460 label={__("Line Height", "post-carousel")}
461 attributes={fontInfo?.lineHeight}
462 onUnitChange={(newUnit) => unitChange(newUnit, "lineHeight")}
463 />
464 <InputControl
465 attributes={fontInfo?.lineHeight?.device?.[deviceType]}
466 type="number"
467 onChange={onChangeLineHeight}
468 min={0}
469 step={0.1}
470 max={6}
471 />
472 </div>
473 </div>
474 </>
475 )}
476 <div className="sp-smart-post-typography-word-spacing-latter-spacing-wrapper sp-d-flex sp-gap-8px">
477 <div className="sp-smart-post-typography-line-height-picker">
478 <ComponentsTopSection
479 label={__("Letter Spacing", "post-carousel")}
480 onUnitChange={(newUnit) => unitChange(newUnit, "letterSpacing")}
481 attributes={fontInfo?.letterSpacing}
482 // setAttributes={ setAttributes }
483 units={["px", "em"]}
484 />
485 <InputControl
486 attributes={fontInfo?.letterSpacing?.device?.[deviceType]}
487 type="number"
488 onChange={(newValue) => letterSpacing(newValue)}
489 min={0}
490 />
491 </div>
492 {wordSpacing && (
493 <div className="sp-smart-post-typography-letter-spacing-picker">
494 <ComponentsTopSection
495 label={__("Word Spacing", "post-carousel")}
496 attributes={fontInfo?.wordSpacing}
497 onUnitChange={(newUnit) => unitChange(newUnit, "wordSpacing")}
498 units={["px", "em"]}
499 />
500 <InputControl
501 attributes={fontInfo?.wordSpacing?.device?.[deviceType]}
502 type="number"
503 onChange={(newValue) => wordSpacingFn(newValue)}
504 min={0}
505 />
506 </div>
507 )}
508 </div>
509 {/* <div className="sp-smart-post-typography-multiple-button-group sp-smart-post-component-mb">
510 <ComponentsTopSection
511 label={ __(
512 'Text Format',
513 'post-carousel-pro'
514 ) }
515 />
516 <div className="sp-smart-post-button-group-list">
517 { textStylesOptions?.map(
518 ( { label, key, value }, i ) => (
519 <button
520 key={ i }
521 className={ `components-button${
522 fontInfo?.typography[
523 key
524 ] === value
525 ? ' active'
526 : ''
527 }` }
528 onClick={ () =>
529 onChangeTextStyles(
530 key,
531 value
532 )
533 }
534 >
535 <span title={ value }>
536 { label }
537 </span>
538 </button>
539 )
540 ) }
541 </div>
542 </div> */}
543 <Flex align="center">
544 <div className="sp-smart-post-typography-multiple-button-group sp-smart-post-component-mb">
545 <ComponentsTopSection label={__("Decoration", "post-carousel")} />
546
547 <div className="sp-smart-post-button-group-list">
548 {textDecorationOptions?.map(({ label, key, value }, i) => (
549 <Tooltip placement="top" text={value} key={i}>
550 <button
551 className={`components-button${
552 fontInfo?.typography[key] === value ? " active" : ""
553 }`}
554 onClick={() => onChangeTextStyles(key, value)}
555 >
556 <span>{label}</span>
557 </button>
558 </Tooltip>
559 ))}
560 </div>
561 </div>
562 <div className="sp-smart-post-typography-multiple-button-group sp-smart-post-component-mb">
563 <ComponentsTopSection label={__("Case", "post-carousel")} />
564
565 <div className="sp-smart-post-button-group-list">
566 {textCaseOptions?.map(({ label, key, value }, i) => (
567 <Tooltip placement="top" text={value} key={i}>
568 <button
569 className={`components-button ${
570 fontInfo?.typography[key] === value ? " active" : ""
571 }`}
572 onClick={() => onChangeTextStyles(key, value)}
573 >
574 <span>{label}</span>
575 </button>
576 </Tooltip>
577 ))}
578 </div>
579 </div>
580 </Flex>
581 {fontInfo?.sizes?.map((size, i) => (
582 <Fragment key={i}>
583 <span className="sp-smart-global-typography-label">{`${fontInfo.title} ${
584 i + 1
585 }`}</span>
586
587 <div className="sp-smart-post-typography-word-spacing-latter-spacing-wrapper sp-d-flex sp-gap-8px">
588 <div className="sp-smart-post-typography-line-height-picker">
589 <ComponentsTopSection
590 label={__("Font Size", "post-carousel")}
591 onUnitChange={(newUnit) => onChangeSizesUnit(newUnit, i, "fontSize")}
592 attributes={size?.fontSize}
593 // setAttributes={ setAttributes }
594 units={["px", "%", "em"]}
595 />
596 <InputControl
597 attributes={size?.fontSize?.device?.[deviceType]}
598 type="number"
599 onChange={(newValue) => onChangeSizes(newValue, i, "fontSize")}
600 min={0}
601 />
602 </div>
603
604 <div className="sp-smart-post-typography-letter-spacing-picker">
605 <ComponentsTopSection
606 label={__("Line Height", "post-carousel")}
607 attributes={size?.lineHeight}
608 onUnitChange={(newUnit) => onChangeSizesUnit(newUnit, i, "lineHeight")}
609 // units={['px', '%', 'em']}
610 />
611 <InputControl
612 attributes={size?.lineHeight?.device?.[deviceType]}
613 type="number"
614 onChange={(newValue) => onChangeSizes(newValue, i, "lineHeight")}
615 min={0}
616 step={0.1}
617 max={6}
618 />
619 </div>
620 </div>
621 </Fragment>
622 ))}
623 </div>
624 </Popover>
625 )}
626 </div>
627 </>
628 );
629 };
630
631 export default GlobalTypography;
632