| 1 |
import { Modal, Button } from "@wordpress/components"; |
| 2 |
import { useState } from "@wordpress/element"; |
| 3 |
|
| 4 |
import "./editor.scss"; |
| 5 |
import Divider from "../divider/divider"; |
| 6 |
import useIconList from "./useIconList"; |
| 7 |
import { CloseIcon } from "../../prebuild-library/icons"; |
| 8 |
|
| 9 |
const IconsLibrary = ({ attributes, attributesKey, setAttributes, onChange = false, pro = false }) => { |
| 10 |
let iconList = useIconList(); |
| 11 |
const activeIcon = iconList[attributes]; |
| 12 |
|
| 13 |
const [styles, setStyle] = useState([]); |
| 14 |
const [isOpen, setOpen] = useState(false); |
| 15 |
const [iconName, setIconName] = useState(""); |
| 16 |
const [searchValue, setSearchValue] = useState(""); |
| 17 |
const [iconCat, setIconCat] = useState("all-icons"); |
| 18 |
|
| 19 |
const openModal = () => setOpen(true); |
| 20 |
const closeModal = () => setOpen(false); |
| 21 |
function handleRemoveIcon() { |
| 22 |
setAttributes({ |
| 23 |
[attributesKey]: "", |
| 24 |
}); |
| 25 |
setOpen(true); |
| 26 |
} |
| 27 |
|
| 28 |
function shortenLabel(text) { |
| 29 |
if (text.includes("-")) { |
| 30 |
return text.split("-")[0]; |
| 31 |
} |
| 32 |
const parts = text.trim().split(/\s+/); |
| 33 |
|
| 34 |
return parts.length > 1 ? parts[0] + " …" : parts[0]; |
| 35 |
} |
| 36 |
|
| 37 |
const stylesType = ["Solid", "Regular", "Light"]; |
| 38 |
// const catList = ["All Icons", "Accessibility", "Alert", "Animals", "Arrows", "Media", "Business", "Charity"]; |
| 39 |
const catList = ["All Icons", "Accessibility", "Alert", "Animals", "Arrows", "Media"]; |
| 40 |
|
| 41 |
const handleStyleChange = (e) => { |
| 42 |
const { value, checked } = e.target; |
| 43 |
|
| 44 |
setStyle( |
| 45 |
(prev) => (checked ? [...prev, value] : prev.filter((item) => item !== value)) // remove unselected |
| 46 |
); |
| 47 |
}; |
| 48 |
|
| 49 |
if (styles.length > 0) { |
| 50 |
iconList = Object.fromEntries( |
| 51 |
Object.entries(iconList)?.filter(([_, icon]) => icon?.style?.some((style) => styles.includes(style))) |
| 52 |
); |
| 53 |
} |
| 54 |
|
| 55 |
if ("all-icons" !== iconCat) { |
| 56 |
iconList = Object.fromEntries( |
| 57 |
Object.entries(iconList)?.filter(([_, icon]) => icon?.category?.some((cat) => iconCat === cat)) |
| 58 |
); |
| 59 |
} |
| 60 |
|
| 61 |
if ("" !== searchValue) { |
| 62 |
iconList = Object.fromEntries( |
| 63 |
Object.entries(iconList).filter(([_, icon]) => icon.label.toLowerCase().includes(searchValue.toLowerCase())) |
| 64 |
); |
| 65 |
} |
| 66 |
|
| 67 |
function handleIconChange() { |
| 68 |
if (onChange) { |
| 69 |
onChange(iconName); |
| 70 |
} else { |
| 71 |
setAttributes({ |
| 72 |
[attributesKey]: iconName, |
| 73 |
}); |
| 74 |
} |
| 75 |
closeModal(); |
| 76 |
} |
| 77 |
|
| 78 |
return ( |
| 79 |
<> |
| 80 |
<div className={`sp-icon-picker-selector-container${pro ? " sp-is-pro" : ""}`}> |
| 81 |
<Button variant="secondary" onClick={openModal}> |
| 82 |
{!activeIcon && ( |
| 83 |
<div className="sp-icon-picker-default-icon-container"> |
| 84 |
<svg |
| 85 |
xmlns="http://www.w3.org/2000/svg" |
| 86 |
viewBox="0 0 512 512" |
| 87 |
fill="none" |
| 88 |
width="28" |
| 89 |
height="28" |
| 90 |
className="sp-icon-picker-default-icon" |
| 91 |
> |
| 92 |
<path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm144 276c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92h-92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z" /> |
| 93 |
</svg> |
| 94 |
</div> |
| 95 |
)} |
| 96 |
|
| 97 |
{activeIcon && ( |
| 98 |
<div className="sp-icon-picker-selected-icon-container"> |
| 99 |
<span onClick={handleRemoveIcon} className="sp-icon-picker-remove-icon"> |
| 100 |
<svg |
| 101 |
xmlns="http://www.w3.org/2000/svg" |
| 102 |
viewBox="0 0 320 512" |
| 103 |
className="sp-icon-picker-remove-icon-svg" |
| 104 |
> |
| 105 |
<path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z" /> |
| 106 |
</svg> |
| 107 |
</span> |
| 108 |
|
| 109 |
<svg |
| 110 |
width={activeIcon?.width} |
| 111 |
height={activeIcon?.height} |
| 112 |
viewBox={activeIcon?.viewBox} |
| 113 |
className="sp-icon-picker-active-icon" |
| 114 |
> |
| 115 |
<path d={activeIcon?.path} /> |
| 116 |
</svg> |
| 117 |
<span className="sp-icon-picker-active-icon-label">{activeIcon?.label}</span> |
| 118 |
</div> |
| 119 |
)} |
| 120 |
</Button> |
| 121 |
</div> |
| 122 |
|
| 123 |
{isOpen && ( |
| 124 |
<Modal className="sp-icon-picker" onRequestClose={closeModal}> |
| 125 |
<Button className="sp-icon-picker-close-btn" onClick={closeModal}> |
| 126 |
<CloseIcon /> |
| 127 |
</Button> |
| 128 |
<div className="sp-icon-picker-body"> |
| 129 |
<div className="sp-icon-picker-sidebar"> |
| 130 |
<h2 className="sp-icon-picker-title">Icon Library</h2> |
| 131 |
<Divider /> |
| 132 |
<h4>Style</h4> |
| 133 |
<ul className="sp-icon-picker-cat-list sp-icon-picker-style"> |
| 134 |
{stylesType.map((type) => { |
| 135 |
const id = type.toLowerCase(); |
| 136 |
return ( |
| 137 |
<li key={id}> |
| 138 |
<input |
| 139 |
onClick={handleStyleChange} |
| 140 |
type="checkbox" |
| 141 |
value={type.toLowerCase()} |
| 142 |
id={id} |
| 143 |
/> |
| 144 |
<label htmlFor={id}>{type}</label> |
| 145 |
</li> |
| 146 |
); |
| 147 |
})} |
| 148 |
</ul> |
| 149 |
<Divider /> |
| 150 |
<h4>Categories</h4> |
| 151 |
<ul className="sp-icon-picker-cat-list"> |
| 152 |
{catList.map((cat) => { |
| 153 |
const id = cat.toLowerCase(); |
| 154 |
return ( |
| 155 |
<li |
| 156 |
className={ |
| 157 |
iconCat === cat.replaceAll(" ", "-").toLowerCase() ? "active" : "" |
| 158 |
} |
| 159 |
key={id} |
| 160 |
> |
| 161 |
<button |
| 162 |
onClick={(e) => setIconCat(e.target.value)} |
| 163 |
value={cat.replaceAll(" ", "-").toLowerCase()} |
| 164 |
type="button" |
| 165 |
> |
| 166 |
{cat} |
| 167 |
</button> |
| 168 |
</li> |
| 169 |
); |
| 170 |
})} |
| 171 |
</ul> |
| 172 |
<Divider /> |
| 173 |
</div> |
| 174 |
<div className="sp-icon-picker-content"> |
| 175 |
<div className="sp-icon-picker-search-bar"> |
| 176 |
<svg |
| 177 |
xmlns="http://www.w3.org/2000/svg" |
| 178 |
width="11" |
| 179 |
height="11" |
| 180 |
viewBox="0 0 11 11" |
| 181 |
fill="none" |
| 182 |
> |
| 183 |
<path |
| 184 |
fillRule="evenodd" |
| 185 |
clipRule="evenodd" |
| 186 |
d="M10.53 4.34813C10.53 6.74953 8.58323 8.69626 6.18183 8.69626C5.17704 8.69626 4.25184 8.35544 3.51556 7.78309L0.768648 10.53L0 9.76135L2.7469 7.01445C2.17454 6.27815 1.8337 5.35294 1.8337 4.34813C1.8337 1.94672 3.78042 0 6.18183 0C8.58323 0 10.53 1.94672 10.53 4.34813ZM9.44293 4.34813C9.44293 6.14918 7.98288 7.60923 6.18183 7.60923C4.38078 7.60923 2.92073 6.14918 2.92073 4.34813C2.92073 2.54708 4.38078 1.08703 6.18183 1.08703C7.98288 1.08703 9.44293 2.54708 9.44293 4.34813Z" |
| 187 |
fill="#757575" |
| 188 |
/> |
| 189 |
</svg> |
| 190 |
<input |
| 191 |
type="text" |
| 192 |
value={searchValue} |
| 193 |
onChange={(e) => setSearchValue(e.target.value)} |
| 194 |
className="sp-icon-picker-search-input" |
| 195 |
placeholder="Search icons..." |
| 196 |
/> |
| 197 |
</div> |
| 198 |
<div className="sp-icon-picker-icons"> |
| 199 |
<ul> |
| 200 |
{Object.keys(iconList)?.map((key) => ( |
| 201 |
<li key={key}> |
| 202 |
<button |
| 203 |
className={key === iconName ? "active" : ""} |
| 204 |
onClick={() => setIconName(key)} |
| 205 |
title={iconList[key]?.label} |
| 206 |
> |
| 207 |
<svg |
| 208 |
width={iconList[key]?.width} |
| 209 |
height={iconList[key]?.height} |
| 210 |
viewBox={iconList[key]?.viewBox} |
| 211 |
> |
| 212 |
<path d={iconList[key]?.path} /> |
| 213 |
</svg> |
| 214 |
<span>{shortenLabel(iconList[key]?.label)}</span> |
| 215 |
</button> |
| 216 |
</li> |
| 217 |
))} |
| 218 |
</ul> |
| 219 |
</div> |
| 220 |
<Button className="sp-icon-picker-insert-btn" onClick={handleIconChange}> |
| 221 |
Insert Icon |
| 222 |
</Button> |
| 223 |
</div> |
| 224 |
</div> |
| 225 |
</Modal> |
| 226 |
)} |
| 227 |
</> |
| 228 |
); |
| 229 |
}; |
| 230 |
|
| 231 |
export default IconsLibrary; |
| 232 |
|