UNPKG

strapi-plugin-icons-field

Version:

A customizable plugin for Strapi to integrate an icon field into your content types.

270 lines (269 loc) 12.6 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const jsxRuntime = require("react/jsx-runtime"); const React = require("react"); const designSystem = require("@strapi/design-system"); const admin = require("@strapi/strapi/admin"); const index = require("./index-CoVMQhd4.js"); const parse = require("html-react-parser"); const styled = require("styled-components"); const icons = require("@strapi/icons"); const reactIntl = require("react-intl"); const _interopDefault = (e) => e && e.__esModule ? e : { default: e }; const React__default = /* @__PURE__ */ _interopDefault(React); const parse__default = /* @__PURE__ */ _interopDefault(parse); const styled__default = /* @__PURE__ */ _interopDefault(styled); function Icon({ icon, ...props }) { const parsedElement = icon && parse__default.default(icon.trim()); if (parsedElement && React__default.default.isValidElement(parsedElement)) { return React__default.default.cloneElement(parsedElement, props); } return null; } const ThemeableIcon = styled__default.default.span` display: contents; & > svg, & > svg *[fill]:not([fill='none']) { fill: ${(p) => p.$color}; } & > svg *[stroke]:not([stroke='none']) { stroke: ${(p) => p.$color}; } `; const IconSelect = (props) => { const theme = styled.useTheme(); const intl = reactIntl.useIntl(); const { label, hint, attribute, disabled, error, name, onChange, placeholder, required, value } = props; const [icons$1, setIcons] = React.useState([]); const [isModalOpen, setIsModalOpen] = React.useState(false); const [searchQuery, setSearchQuery] = React.useState(""); const { get } = admin.useFetchClient(); const toggleModal = () => setIsModalOpen((prev) => !prev); React.useEffect(() => { const fetchIcons = async () => { try { let url = `/${index.PLUGIN_ID}/icons`; if (attribute?.options?.selection) { if (Array.isArray(attribute.options.selection)) { url += `?selection=${encodeURIComponent(attribute.options.selection.join(","))}`; } else { url += `?selection=${encodeURIComponent(attribute.options.selection)}`; } } const { data } = await get(url); setIcons(data || []); } catch (error2) { console.error("Error fetching icons:", error2); } }; fetchIcons(); }, [attribute?.options?.selection]); const outputFormat = attribute?.options?.outputFormat || "svg"; const handleChange = (icon) => { const storedValue = outputFormat === "name" ? icon.name : icon.svg; onChange({ target: { name, value: storedValue, type: attribute.type } }); }; const allIcons = React.useMemo(() => icons$1.flatMap((group) => group.icons), [icons$1]); const selectedIconData = React.useMemo(() => { if (!value) return void 0; if (outputFormat === "name") { return allIcons.find((icon) => icon.name === value); } return allIcons.find((icon) => icon.svg === value); }, [value, allIcons, outputFormat]); const filteredIcons = React.useMemo(() => { if (!searchQuery.trim()) return icons$1; const query = searchQuery.toLowerCase(); return icons$1.map((group) => ({ ...group, icons: group.icons.filter((icon) => icon.name.toLowerCase().includes(query)) })).filter((group) => group.icons.length > 0); }, [icons$1, searchQuery]); const handleUnselectedIcon = (e) => { e.stopPropagation(); onChange({ target: { name, value: "", type: attribute.type } }); }; return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { error, hint, required, children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: label }), /* @__PURE__ */ jsxRuntime.jsxs( designSystem.Modal.Root, { labelledBy: "icon-select-modal-title", open: isModalOpen, onOpenChange: setIsModalOpen, children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsxs( designSystem.Box, { display: "flex", style: { alignItems: "center", gap: "12px", position: "relative", width: "100%" }, children: [ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "relative", flex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx( designSystem.Button, { variant: "tertiary", disabled, style: { gap: "8px", height: "42px", width: "100%", display: "flex", alignItems: "center", justifyContent: "space-between" }, children: /* @__PURE__ */ jsxRuntime.jsxs( "div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [ selectedIconData ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ /* @__PURE__ */ jsxRuntime.jsx(ThemeableIcon, { $color: theme.colors?.neutral800 || "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: selectedIconData.svg, style: { height: "24px", display: "block" } }) }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", children: selectedIconData.name }) ] }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { style: { fontWeight: "400" }, children: placeholder ?? intl.formatMessage({ id: "icons-field.select", defaultMessage: "Select an icon" }) }), /* @__PURE__ */ jsxRuntime.jsx( icons.CaretDown, { color: theme.colors?.neutral500, style: { position: "absolute", right: "16px", height: "16px", width: "16px" } } ) ] } ) } ) }), selectedIconData && /* @__PURE__ */ jsxRuntime.jsx( "button", { type: "button", onClick: handleUnselectedIcon, style: { position: "absolute", right: "44px", height: "16px", width: "16px", cursor: "pointer", zIndex: 3 }, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Cross, { color: theme.colors?.neutral500, style: { height: "100%", width: "100%" } }) } ) ] } ) }), /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", as: "h2", id: "title", children: intl.formatMessage({ id: "icons-field.modal.title", defaultMessage: "Select an icon" }) }) }), /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx( designSystem.Searchbar, { name: "icon-search", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onClear: () => setSearchQuery(""), clearLabel: intl.formatMessage({ id: "icons-field.modal.search.clear", defaultMessage: "Clear search" }), placeholder: intl.formatMessage({ id: "icons-field.modal.search.placeholder", defaultMessage: "Search icons..." }), children: intl.formatMessage({ id: "icons-field.modal.search.placeholder", defaultMessage: "Search icons..." }) } ) }), filteredIcons.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral500", children: intl.formatMessage({ id: "icons-field.modal.search.empty", defaultMessage: "No icons found." }) }), filteredIcons.map((group) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { marginBottom: 6, children: [ /* @__PURE__ */ jsxRuntime.jsx( designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", as: "h3", id: "title", marginBottom: 2, children: group.folder } ), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { display: "flex", marginTop: 2, style: { flexWrap: "wrap", gap: 6 }, children: group.icons.map((icon) => { const isSelected = outputFormat === "name" ? value === icon.name : value === icon.svg; return /* @__PURE__ */ jsxRuntime.jsxs( designSystem.Box, { as: "button", type: "button", "aria-label": icon.name, onClick: () => { handleChange(icon); toggleModal(); }, style: { alignItems: "center", aspectRatio: "1/1", background: isSelected ? theme.colors?.primary100 : theme.colors?.neutral100, border: isSelected ? `2px solid ${theme.colors?.primary600}` : `1px solid ${theme.colors?.neutral200}`, borderRadius: "4px", cursor: "pointer", display: "flex", flexDirection: "column", gap: "2px", height: "100%", justifyContent: "center", padding: "12px", width: "85px" }, children: [ /* @__PURE__ */ jsxRuntime.jsx(ThemeableIcon, { $color: theme.colors?.neutral800 || "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx( Icon, { icon: icon.svg, style: { aspectRatio: "1/1", height: "100%", maxWidth: "25px", width: "100%" } } ) }), attribute?.options?.showIconLabel && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", style: { marginTop: 8 }, children: icon.name }) ] }, icon.name ); }) }) ] }, group.folder)) ] }), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Footer, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Close, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: intl.formatMessage({ id: "icons-field.modal.close", defaultMessage: "Close window" }) }) }) }) ] }) ] } ), /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {}) ] }); }; exports.default = IconSelect; //# sourceMappingURL=IconSelect-C3tI7nD-.js.map