diff --git a/packages/admin-ui/package.json b/packages/admin-ui/package.json index d1acc75333d..4f4fd93c2ce 100644 --- a/packages/admin-ui/package.json +++ b/packages/admin-ui/package.json @@ -55,7 +55,7 @@ "@storybook/theming": "7.6.20", "@svgr/webpack": "^6.1.1", "@types/react": "18.2.79", - "@types/react-virtualized": "^9", + "@types/react-virtualized": "^9.22.0", "@webiny/cli": "0.0.0", "@webiny/project-utils": "0.0.0", "chalk": "^4.1.2", diff --git a/packages/admin-ui/src/IconPicker/IconPicker.stories.tsx b/packages/admin-ui/src/IconPicker/IconPicker.stories.tsx index 39679d6a106..233d2e3aab2 100644 --- a/packages/admin-ui/src/IconPicker/IconPicker.stories.tsx +++ b/packages/admin-ui/src/IconPicker/IconPicker.stories.tsx @@ -1,10 +1,9 @@ import React, { useState } from "react"; import type { Meta, StoryObj } from "@storybook/react"; -import { IconPicker } from "~/IconPicker"; +import { IconDto, IconPicker } from "~/IconPicker"; import { IconName, library } from "@fortawesome/fontawesome-svg-core"; import { IconPrefix } from "@fortawesome/fontawesome-common-types"; import { fas } from "@fortawesome/free-solid-svg-icons"; -import { IconDto } from "~/IconPicker/primitives/domains"; const meta: Meta = { title: "Components/Form/IconPicker", diff --git a/packages/admin-ui/src/IconPicker/IconPicker.tsx b/packages/admin-ui/src/IconPicker/IconPicker.tsx index 6d015e1aca3..21e32d5179b 100644 --- a/packages/admin-ui/src/IconPicker/IconPicker.tsx +++ b/packages/admin-ui/src/IconPicker/IconPicker.tsx @@ -35,4 +35,4 @@ const DecoratableIconPicker = ({ }; const IconPicker = makeDecoratable("IconPicker", DecoratableIconPicker); -export { IconPicker }; +export { IconPicker, type IconPickerProps }; diff --git a/packages/admin-ui/src/IconPicker/primitives/domains/Icon.tsx b/packages/admin-ui/src/IconPicker/domains/Icon.tsx similarity index 96% rename from packages/admin-ui/src/IconPicker/primitives/domains/Icon.tsx rename to packages/admin-ui/src/IconPicker/domains/Icon.tsx index ebbde648785..86d24642789 100644 --- a/packages/admin-ui/src/IconPicker/primitives/domains/Icon.tsx +++ b/packages/admin-ui/src/IconPicker/domains/Icon.tsx @@ -20,7 +20,7 @@ export class Icon { if (typeof value === "string" && value.includes("/")) { const values = value.split("/"); return new Icon({ - prefix: values[1], + prefix: values[0], name: values[1] }); } else { diff --git a/packages/admin-ui/src/IconPicker/primitives/domains/IconDto.tsx b/packages/admin-ui/src/IconPicker/domains/IconDto.tsx similarity index 100% rename from packages/admin-ui/src/IconPicker/primitives/domains/IconDto.tsx rename to packages/admin-ui/src/IconPicker/domains/IconDto.tsx diff --git a/packages/admin-ui/src/IconPicker/primitives/domains/IconFormattedFontAwesome.ts b/packages/admin-ui/src/IconPicker/domains/IconFormattedFontAwesome.ts similarity index 100% rename from packages/admin-ui/src/IconPicker/primitives/domains/IconFormattedFontAwesome.ts rename to packages/admin-ui/src/IconPicker/domains/IconFormattedFontAwesome.ts diff --git a/packages/admin-ui/src/IconPicker/primitives/domains/IconFormatter.tsx b/packages/admin-ui/src/IconPicker/domains/IconFormatter.tsx similarity index 100% rename from packages/admin-ui/src/IconPicker/primitives/domains/IconFormatter.tsx rename to packages/admin-ui/src/IconPicker/domains/IconFormatter.tsx diff --git a/packages/admin-ui/src/IconPicker/primitives/domains/ListCache.ts b/packages/admin-ui/src/IconPicker/domains/ListCache.ts similarity index 100% rename from packages/admin-ui/src/IconPicker/primitives/domains/ListCache.ts rename to packages/admin-ui/src/IconPicker/domains/ListCache.ts diff --git a/packages/admin-ui/src/IconPicker/primitives/domains/index.ts b/packages/admin-ui/src/IconPicker/domains/index.ts similarity index 100% rename from packages/admin-ui/src/IconPicker/primitives/domains/index.ts rename to packages/admin-ui/src/IconPicker/domains/index.ts diff --git a/packages/admin-ui/src/IconPicker/index.ts b/packages/admin-ui/src/IconPicker/index.ts index 219446fddbe..feb6e47c09f 100644 --- a/packages/admin-ui/src/IconPicker/index.ts +++ b/packages/admin-ui/src/IconPicker/index.ts @@ -1 +1,2 @@ export * from "./IconPicker"; +export { IconDto } from "./domains"; diff --git a/packages/admin-ui/src/IconPicker/primitives/IconPickerPrimitive.stories.tsx b/packages/admin-ui/src/IconPicker/primitives/IconPickerPrimitive.stories.tsx index b3f395c3f56..29b6f610246 100644 --- a/packages/admin-ui/src/IconPicker/primitives/IconPickerPrimitive.stories.tsx +++ b/packages/admin-ui/src/IconPicker/primitives/IconPickerPrimitive.stories.tsx @@ -1,10 +1,10 @@ import React, { useState } from "react"; import type { Meta, StoryObj } from "@storybook/react"; import { IconPickerPrimitive } from "./IconPickerPrimitive"; +import { IconDto } from "~/IconPicker"; import { IconName, library } from "@fortawesome/fontawesome-svg-core"; import { IconPrefix } from "@fortawesome/fontawesome-common-types"; import { fas } from "@fortawesome/free-solid-svg-icons"; -import { IconDto } from "~/IconPicker/primitives/domains"; const meta: Meta = { title: "Components/Form Primitives/IconPicker", diff --git a/packages/admin-ui/src/IconPicker/primitives/IconPickerPrimitive.tsx b/packages/admin-ui/src/IconPicker/primitives/IconPickerPrimitive.tsx index e6174bb401c..80e62cc41e0 100644 --- a/packages/admin-ui/src/IconPicker/primitives/IconPickerPrimitive.tsx +++ b/packages/admin-ui/src/IconPicker/primitives/IconPickerPrimitive.tsx @@ -3,14 +3,14 @@ import { inputVariants } from "~/Input"; import { Popover } from "~/Popover"; import { cn, cva, type VariantProps } from "~/utils"; import { IconPickerGrid, IconPickerInput, IconPickerTrigger } from "./components"; -import { IconDto } from "./domains"; +import { IconDto } from "../domains"; import { useIconPicker } from "./useIconPicker"; const iconPickerVariants = cva("wby-cursor-pointer wby-text-neutral-strong", { variants: { size: { md: "wby-w-[64px]", - lg: "wby-w-[68px]", + lg: "wby-w-[64px]", xl: "wby-w-[76px]" }, disabled: { diff --git a/packages/admin-ui/src/IconPicker/primitives/components/IconPickerGrid.tsx b/packages/admin-ui/src/IconPicker/primitives/components/IconPickerGrid.tsx index ff4f4af5b1e..cab358d182e 100644 --- a/packages/admin-ui/src/IconPicker/primitives/components/IconPickerGrid.tsx +++ b/packages/admin-ui/src/IconPicker/primitives/components/IconPickerGrid.tsx @@ -2,7 +2,7 @@ import React, { useCallback } from "react"; import { Grid, GridCellProps } from "react-virtualized"; import { Text } from "~/Text"; import { cn } from "~/utils"; -import { IconFormattedFontAwesome, IconFormatter } from "../domains"; +import { IconFormattedFontAwesome, IconFormatter } from "../../domains"; import { IconPickerIcon } from "./IconPickerIcon"; const COLUMN_COUNT = 5; diff --git a/packages/admin-ui/src/IconPicker/primitives/components/IconPickerTrigger.tsx b/packages/admin-ui/src/IconPicker/primitives/components/IconPickerTrigger.tsx index fbe346c7e21..7fd63ce3635 100644 --- a/packages/admin-ui/src/IconPicker/primitives/components/IconPickerTrigger.tsx +++ b/packages/admin-ui/src/IconPicker/primitives/components/IconPickerTrigger.tsx @@ -4,7 +4,7 @@ import { Icon as IconComponent } from "~/Icon"; import { inputVariants } from "~/Input"; import type { VariantProps } from "~/utils"; import { IconPickerIcon } from "./IconPickerIcon"; -import { Icon, IconFormatter } from "../domains"; +import { Icon, IconFormatter } from "../../domains"; interface IconPickerTriggerProps { value?: string; @@ -17,13 +17,11 @@ const IconPickerTrigger = ({ value, size }: IconPickerTriggerProps) => { return IconFormatter.formatFontAwesome(icon); }, [value]); - const iconSize = useMemo(() => (size === "lg" || size === "xl" ? "lg" : "md"), [size]); - return (
} label={`Selected icon`} /> diff --git a/packages/admin-ui/src/IconPicker/primitives/presenters/IconPickerPresenter.ts b/packages/admin-ui/src/IconPicker/primitives/presenters/IconPickerPresenter.ts index 101db1292ae..cddf1377d31 100644 --- a/packages/admin-ui/src/IconPicker/primitives/presenters/IconPickerPresenter.ts +++ b/packages/admin-ui/src/IconPicker/primitives/presenters/IconPickerPresenter.ts @@ -1,5 +1,5 @@ import { makeAutoObservable } from "mobx"; -import { Icon, IconDto, IconFormattedFontAwesome, IconFormatter, ListCache } from "../domains"; +import { Icon, IconDto, IconFormattedFontAwesome, IconFormatter, ListCache } from "../../domains"; interface IconPickerParams { icons: IconDto[]; diff --git a/packages/app-headless-cms-common/package.json b/packages/app-headless-cms-common/package.json index b6f91436828..bcbc3bb1aa0 100644 --- a/packages/app-headless-cms-common/package.json +++ b/packages/app-headless-cms-common/package.json @@ -27,6 +27,7 @@ }, "devDependencies": { "@emotion/babel-plugin": "^11.11.0", + "@webiny/admin-ui": "0.0.0", "@webiny/cli": "0.0.0", "@webiny/project-utils": "0.0.0", "babel-plugin-module-resolver": "^5.0.2", diff --git a/packages/app-headless-cms-common/src/types/index.ts b/packages/app-headless-cms-common/src/types/index.ts index efbacd825aa..5dbb2a48539 100644 --- a/packages/app-headless-cms-common/src/types/index.ts +++ b/packages/app-headless-cms-common/src/types/index.ts @@ -17,6 +17,7 @@ import { import { CmsModel, CmsModelField } from "./model"; import { CmsIdentity } from "~/types/shared"; import type { SourceType } from "dnd-core"; +import { IconDto } from "@webiny/admin-ui"; export type DragObjectWithType = { type: SourceType; @@ -472,7 +473,7 @@ export interface CmsIcon { export interface CmsIconsPlugin extends Plugin { type: "cms-icons"; - getIcons(): CmsIcon[]; + getIcons(): IconDto[]; } /** diff --git a/packages/app-headless-cms-common/tsconfig.build.json b/packages/app-headless-cms-common/tsconfig.build.json index 8c83022e3c4..0c1a87dca95 100644 --- a/packages/app-headless-cms-common/tsconfig.build.json +++ b/packages/app-headless-cms-common/tsconfig.build.json @@ -2,6 +2,7 @@ "extends": "../../tsconfig.build.json", "include": ["src"], "references": [ + { "path": "../admin-ui/tsconfig.build.json" }, { "path": "../app-security/tsconfig.build.json" }, { "path": "../form/tsconfig.build.json" }, { "path": "../plugins/tsconfig.build.json" }, diff --git a/packages/app-headless-cms-common/tsconfig.json b/packages/app-headless-cms-common/tsconfig.json index a8462cfbdf5..e344f231574 100644 --- a/packages/app-headless-cms-common/tsconfig.json +++ b/packages/app-headless-cms-common/tsconfig.json @@ -2,6 +2,7 @@ "extends": "../../tsconfig.json", "include": ["src", "__tests__"], "references": [ + { "path": "../admin-ui" }, { "path": "../app-security" }, { "path": "../form" }, { "path": "../plugins" }, @@ -14,6 +15,8 @@ "paths": { "~/*": ["./src/*"], "~tests/*": ["./__tests__/*"], + "@webiny/admin-ui/*": ["../admin-ui/src/*"], + "@webiny/admin-ui": ["../admin-ui/src"], "@webiny/app-security/*": ["../app-security/src/*"], "@webiny/app-security": ["../app-security/src"], "@webiny/form/*": ["../form/src/*"], diff --git a/packages/app-headless-cms/package.json b/packages/app-headless-cms/package.json index b546ddceabd..0d483e19d47 100644 --- a/packages/app-headless-cms/package.json +++ b/packages/app-headless-cms/package.json @@ -27,6 +27,7 @@ "@material-design-icons/svg": "^0.14.13", "@svgr/webpack": "^6.1.1", "@types/react": "18.2.79", + "@webiny/admin-ui": "0.0.0", "@webiny/app": "0.0.0", "@webiny/app-aco": "0.0.0", "@webiny/app-admin": "0.0.0", @@ -74,7 +75,6 @@ "react-dom": "18.2.0", "react-helmet": "^6.1.0", "react-hotkeyz": "^1.0.4", - "react-virtualized": "^9.22.5", "use-deep-compare-effect": "^1.8.1" }, "devDependencies": { diff --git a/packages/app-headless-cms/src/admin/components/IconPicker.tsx b/packages/app-headless-cms/src/admin/components/IconPicker.tsx index 6dc980f6ee9..dc684fff9ff 100644 --- a/packages/app-headless-cms/src/admin/components/IconPicker.tsx +++ b/packages/app-headless-cms/src/admin/components/IconPicker.tsx @@ -1,257 +1,15 @@ -import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { css } from "emotion"; -import { css as reactCss, Global } from "@emotion/react"; +import React, { useMemo } from "react"; +import { IconDto, IconPicker as AdminIconPicker, IconPickerProps } from "@webiny/admin-ui"; import { plugins } from "@webiny/plugins"; -import { Typography } from "@webiny/ui/Typography"; -import { Grid } from "react-virtualized"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { DelayedOnChange, OnChangeCallable } from "@webiny/ui/DelayedOnChange"; -import { Menu, RenderableMenuChildren } from "@webiny/ui/Menu"; -import { Input } from "@webiny/ui/Input"; -import { CmsIcon, CmsIconsPlugin } from "~/types"; -import { FormComponentProps } from "@webiny/ui/types"; -import { FormElementMessage } from "@webiny/ui/FormElementMessage"; -import { GridCellProps } from "react-virtualized/dist/es/Grid"; +import { CmsIconsPlugin } from "~/types"; -/** - * Controls the helper text below the checkbox. - * @type {string} - */ -const iconPickerLabel = css({ marginBottom: 5, marginLeft: 2 }); - -const globalStyles = reactCss` - #rmwcPortal > .mdc-menu-surface { - z-index: 1000; - } -`; - -const MenuWrapper = css` - color: var(--mdc-theme-text-secondary-on-background); - background-color: var(--mdc-theme-on-background); - border-bottom: 1px solid var(--mdc-theme-text-secondary-on-background, rgba(0, 0, 0, 0.54)); - padding: 16px 8px; - cursor: pointer; - :hover { - border-bottom: 1px solid rgba(0, 0, 0, 1); - } -`; - -const NoResultWrapper = css({ - width: 640, - color: "var(--mdc-theme-text-secondary-on-background)", - padding: "16px 12px" -}); - -const COLUMN_COUNT = 6; - -const gridItem = css({ - display: "flex", - flexDirection: "column", - justifyContent: "flex-start", - boxSizing: "border-box", - paddingTop: 15, - alignItems: "center", - textAlign: "center", - cursor: "pointer", - transform: "translateZ(0)", - borderRadius: 2, - color: "var(--mdc-theme-text-secondary-on-background)", - transition: "all 0.5s cubic-bezier(0.165, 0.84, 0.44, 1)", - "&::after": { - boxShadow: "0 0.25rem 0.125rem 0 rgba(0,0,0,0.05)", - transition: "opacity 0.5s cubic-bezier(0.165, 0.84, 0.44, 1)", - content: '""', - position: "absolute", - top: 0, - left: 0, - width: "100%", - height: "100%", - zIndex: -1, - opacity: 0 - }, - "&:hover": { - backgroundColor: "var(--mdc-theme-background)", - color: "var(--mdc-theme-text-primary-on-background)", - "&::after": { - opacity: 1 - } - }, - ">svg": { - width: 42, - marginBottom: 5 - } -}); - -const grid = css({ - padding: 20 -}); - -const pickIcon = css({ - width: 50, - textAlign: "center", - cursor: "pointer" -}); - -const searchInput = css({ - input: { - padding: "20px 12px 20px" - } -}); - -export interface IconPickerProps extends FormComponentProps { - label?: React.ReactNode; - description?: React.ReactNode; -} - -interface RenderCellParams { - closeMenu: () => void; -} - -export const IconPicker = ({ - value, - onChange, - label, - description, - validation -}: IconPickerProps) => { - const [filter, setFilter] = useState(""); - const [mustRenderGrid, setMustRenderGrid] = useState(false); - const inputRef = useRef(null); - - useEffect(() => { - setTimeout(() => { - if (mustRenderGrid && inputRef.current) { - inputRef.current.focus(); - } - }, 50); - }, [mustRenderGrid]); - - const onFilterChange = useCallback( - (value, cb) => { - setFilter(value); - if (cb) { - cb(value); - } - }, - [filter] - ); - - const allIcons: CmsIcon[] = useMemo(() => { +export const IconPicker = (props: Omit) => { + const icons: IconDto[] = useMemo(() => { const iconPlugins = plugins.byType("cms-icons"); - return iconPlugins.reduce((icons: Array, pl) => { + return iconPlugins.reduce((icons: Array, pl) => { return icons.concat(pl.getIcons()); }, []); }, []); - const icons = useMemo(() => { - return filter ? allIcons.filter(ic => ic.name.includes(filter)) : allIcons; - }, [filter]); - - const renderCell = useCallback( - ({ closeMenu }: RenderCellParams) => { - return function renderCell({ - columnIndex, - key, - rowIndex, - style - }: GridCellProps): React.ReactNode { - const item = icons[rowIndex * COLUMN_COUNT + columnIndex]; - if (!item) { - return null; - } - - return ( -
{ - if (onChange) { - onChange(item.id.join("/")); - } - closeMenu(); - }} - > - - {item.name} -
- ); - }; - }, - [icons] - ); - - const renderGrid = useCallback( - ({ closeMenu }) => { - return ( - <> - - - {({ value, onChange }) => ( - - )} - - {icons.length === 0 ? ( -
- No results found. -
- ) : ( - - )} - - ); - }, - [icons] - ); - - const fontAwesomeIconValue: any = - typeof value === "string" && value.includes("/") ? value.split("/") : ["fas", "star"]; - - const { isValid: validationIsValid, message: validationMessage } = validation || {}; - - return ( - <> - {label && ( -
- {label} -
- )} - - setMustRenderGrid(true)} - onClose={() => setMustRenderGrid(false)} - renderToPortal={true} - render={mustRenderGrid ? renderGrid : () => null} - handle={ -
-
- -
-
- } - /> - - {validationIsValid === false && ( - {validationMessage} - )} - {validationIsValid !== false && description && ( - {description} - )} - - ); + return ; }; diff --git a/packages/app-headless-cms/src/admin/plugins/icons.tsx b/packages/app-headless-cms/src/admin/plugins/icons.tsx index bde8b9d159c..6da8ad6bd74 100644 --- a/packages/app-headless-cms/src/admin/plugins/icons.tsx +++ b/packages/app-headless-cms/src/admin/plugins/icons.tsx @@ -1,20 +1,12 @@ -import React from "react"; import { IconName, library } from "@fortawesome/fontawesome-svg-core"; import { IconPrefix } from "@fortawesome/fontawesome-common-types"; import { fab } from "@fortawesome/free-brands-svg-icons"; import { fas } from "@fortawesome/free-solid-svg-icons"; import { far } from "@fortawesome/free-regular-svg-icons"; -import { CmsIcon, CmsIconsPlugin } from "~/types"; +import { IconDto } from "@webiny/admin-ui"; +import { CmsIconsPlugin } from "~/types"; -const createSvg = (icon: string[]): React.ReactElement => { - return ( - - - - ); -}; - -const icons: CmsIcon[] = []; +const icons: IconDto[] = []; interface Icons { definitions: Record>; @@ -36,9 +28,8 @@ const plugin: CmsIconsPlugin = { // @ts-expect-error Object.keys(defs).forEach((icon: IconName) => { icons.push({ - id: [pack, icon], - name: icon, - svg: createSvg(defs[icon]) + prefix: pack, + name: icon }); }); }); diff --git a/packages/app-headless-cms/tsconfig.build.json b/packages/app-headless-cms/tsconfig.build.json index 15585cfe08c..04e493223bf 100644 --- a/packages/app-headless-cms/tsconfig.build.json +++ b/packages/app-headless-cms/tsconfig.build.json @@ -2,6 +2,7 @@ "extends": "../../tsconfig.build.json", "include": ["src"], "references": [ + { "path": "../admin-ui/tsconfig.build.json" }, { "path": "../app/tsconfig.build.json" }, { "path": "../app-aco/tsconfig.build.json" }, { "path": "../app-admin/tsconfig.build.json" }, diff --git a/packages/app-headless-cms/tsconfig.json b/packages/app-headless-cms/tsconfig.json index f68ff7be9c7..b61db93dd15 100644 --- a/packages/app-headless-cms/tsconfig.json +++ b/packages/app-headless-cms/tsconfig.json @@ -2,6 +2,7 @@ "extends": "../../tsconfig.json", "include": ["src", "__tests__"], "references": [ + { "path": "../admin-ui" }, { "path": "../app" }, { "path": "../app-aco" }, { "path": "../app-admin" }, @@ -34,6 +35,8 @@ "paths": { "~/*": ["./src/*"], "~tests/*": ["./__tests__/*"], + "@webiny/admin-ui/*": ["../admin-ui/src/*"], + "@webiny/admin-ui": ["../admin-ui/src"], "@webiny/app/*": ["../app/src/*"], "@webiny/app": ["../app/src"], "@webiny/app-aco/*": ["../app-aco/src/*"], diff --git a/packages/app-page-builder/package.json b/packages/app-page-builder/package.json index c3d6bef6135..b9050a9e315 100644 --- a/packages/app-page-builder/package.json +++ b/packages/app-page-builder/package.json @@ -78,7 +78,6 @@ "react-images": "^0.5.19", "react-in-viewport": "^1.0.0-alpha.30", "react-sortable": "^2.0.0", - "react-virtualized": "^9.22.5", "recoil": "^0.7.7", "slugify": "^1.6.6", "store": "^2.0.12", @@ -92,7 +91,6 @@ "@types/pako": "^2.0.3", "@types/platform": "^1.3.4", "@types/react-images": "^0.5.3", - "@types/react-virtualized": "^9.21.16", "@types/resize-observer-browser": "^0.1.4", "@types/store": "^2.0.2", "@webiny/cli": "0.0.0", diff --git a/packages/app-page-builder/src/admin/plugins/icons/index.tsx b/packages/app-page-builder/src/admin/plugins/icons/index.tsx index b462304293e..7237427d702 100644 --- a/packages/app-page-builder/src/admin/plugins/icons/index.tsx +++ b/packages/app-page-builder/src/admin/plugins/icons/index.tsx @@ -1,20 +1,12 @@ -import React from "react"; import { IconName, library } from "@fortawesome/fontawesome-svg-core"; import { fab } from "@fortawesome/free-brands-svg-icons"; import { fas } from "@fortawesome/free-solid-svg-icons"; import { far } from "@fortawesome/free-regular-svg-icons"; -import { PbIcon, PbIconsPlugin } from "~/types"; import { IconPrefix } from "@fortawesome/fontawesome-common-types"; +import { IconDto } from "@webiny/admin-ui"; +import { PbIconsPlugin } from "~/types"; -const createSvg = (icon: string[]): React.ReactElement => { - return ( - - - - ); -}; - -const icons: PbIcon[] = []; +const icons: IconDto[] = []; interface Icons { definitions: Record>; @@ -39,9 +31,8 @@ const plugin: PbIconsPlugin = { // @ts-expect-error Object.keys(defs).forEach((icon: IconName) => { icons.push({ - id: [pack, icon], - name: icon, - svg: createSvg(defs[icon]) + prefix: pack, + name: icon }); }); }); diff --git a/packages/app-page-builder/src/admin/views/BlockCategories/IconPicker.tsx b/packages/app-page-builder/src/admin/views/BlockCategories/IconPicker.tsx index e82ae797648..08c8c09641b 100644 --- a/packages/app-page-builder/src/admin/views/BlockCategories/IconPicker.tsx +++ b/packages/app-page-builder/src/admin/views/BlockCategories/IconPicker.tsx @@ -1,240 +1,17 @@ -// TODO: find a better way to share IconPicker with icons across apps. -import React, { useState, useCallback, useMemo, useEffect, useRef } from "react"; -import { css } from "emotion"; +import React, { useMemo } from "react"; +import { IconDto, IconPicker as AdminIconPicker, IconPickerProps } from "@webiny/admin-ui"; import { plugins } from "@webiny/plugins"; -import { Typography } from "@webiny/ui/Typography"; -import { Grid } from "react-virtualized"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { DelayedOnChange } from "@webiny/ui/DelayedOnChange"; -import { Menu, MenuChildrenFunctionProps } from "@webiny/ui/Menu"; -import { Input } from "@webiny/ui/Input"; -import { PbIcon, PbIconsPlugin } from "~/types"; -import { FormComponentProps } from "@webiny/ui/types"; -import { FormElementMessage } from "@webiny/ui/FormElementMessage"; -import { GridCellProps } from "react-virtualized/dist/es/Grid"; +import { PbIconsPlugin } from "~/types"; -/** - * Controls the helper text below the checkbox. - * @type {string} - */ -const iconPickerLabel = css({ marginBottom: 5, marginLeft: 2 }); - -const MenuWrapper = css` - color: var(--mdc-theme-text-secondary-on-background); - background-color: var(--mdc-theme-on-background); - border-bottom: 1px solid var(--mdc-theme-text-secondary-on-background, rgba(0, 0, 0, 0.54)); - padding: 16px 8px; - cursor: pointer; - :hover { - border-bottom: 1px solid rgba(0, 0, 0, 1); - } -`; - -const NoResultWrapper = css({ - width: 640, - color: "var(--mdc-theme-text-secondary-on-background)", - padding: "16px 12px" -}); - -const COLUMN_COUNT = 6; - -const gridItem = css({ - display: "flex", - flexDirection: "column", - justifyContent: "flex-start", - boxSizing: "border-box", - paddingTop: 15, - alignItems: "center", - textAlign: "center", - cursor: "pointer", - transform: "translateZ(0)", - borderRadius: 2, - color: "var(--mdc-theme-text-secondary-on-background)", - transition: "all 0.5s cubic-bezier(0.165, 0.84, 0.44, 1)", - "&::after": { - boxShadow: "0 0.25rem 0.125rem 0 rgba(0,0,0,0.05)", - transition: "opacity 0.5s cubic-bezier(0.165, 0.84, 0.44, 1)", - content: '""', - position: "absolute", - top: 0, - left: 0, - width: "100%", - height: "100%", - zIndex: -1, - opacity: 0 - }, - "&:hover": { - backgroundColor: "var(--mdc-theme-background)", - color: "var(--mdc-theme-text-primary-on-background)", - "&::after": { - opacity: 1 - } - }, - ">svg": { - width: 42, - marginBottom: 5 - } -}); - -const grid = css({ - padding: 20 -}); - -const pickIcon = css({ - width: 50, - textAlign: "center", - cursor: "pointer" -}); - -const searchInput = css({ - input: { - padding: "20px 12px 20px" - } -}); - -interface IconPickerProps extends FormComponentProps { - label?: React.ReactNode; - description?: React.ReactNode; -} -const IconPicker = ({ value, onChange, label, description, validation }: IconPickerProps) => { - const [filter, setFilter] = useState(""); - const [mustRenderGrid, setMustRenderGrid] = useState(false); - const inputRef = useRef(null); - - useEffect(() => { - setTimeout(() => { - if (mustRenderGrid && inputRef.current) { - inputRef.current.focus(); - } - }, 50); - }, [mustRenderGrid]); - - const onFilterChange = useCallback( - (value: string) => { - setFilter(value); - }, - [filter] - ); - - const allIcons: PbIcon[] = useMemo(() => { +const IconPicker = (props: Omit) => { + const icons: IconDto[] = useMemo(() => { const iconPlugins = plugins.byType("pb-icons"); - return iconPlugins.reduce((icons: Array, pl) => { + return iconPlugins.reduce((icons: Array, pl) => { return icons.concat(pl.getIcons()); }, []); }, []); - const icons = useMemo(() => { - return filter ? allIcons.filter(ic => ic.name.includes(filter)) : allIcons; - }, [filter]); - - const renderCell = useCallback( - ({ closeMenu }: MenuChildrenFunctionProps) => { - return function renderCell({ - columnIndex, - key, - rowIndex, - style - }: GridCellProps): React.ReactNode { - const item = icons[rowIndex * COLUMN_COUNT + columnIndex]; - if (!item) { - return null; - } - - return ( -
{ - if (onChange) { - onChange(item.id.join("/")); - } - closeMenu(); - }} - > - - {item.name} -
- ); - }; - }, - [mustRenderGrid, icons] - ); - - const renderGrid = useCallback( - ({ closeMenu }: MenuChildrenFunctionProps) => { - if (!mustRenderGrid) { - return; - } - - return ( - <> - - {({ value, onChange }) => ( - - )} - - {icons.length === 0 ? ( -
- No results found. -
- ) : ( - - )} - - ); - }, - [mustRenderGrid, icons] - ); - - const fontAwesomeIconValue: any = - typeof value === "string" && value.includes("/") ? value.split("/") : ["fas", "star"]; - - const { isValid: validationIsValid, message: validationMessage } = validation || {}; - - return ( - <> - {label && ( -
- {label} -
- )} - setMustRenderGrid(true)} - onClose={() => setMustRenderGrid(false)} - handle={ -
-
- -
-
- } - render={renderGrid} - /> - - {validationIsValid === false && ( - {validationMessage} - )} - {validationIsValid !== false && description && ( - {description} - )} - - ); + return ; }; export default IconPicker; diff --git a/packages/app-page-builder/src/types.ts b/packages/app-page-builder/src/types.ts index 8d25240008b..7e0831d6e94 100644 --- a/packages/app-page-builder/src/types.ts +++ b/packages/app-page-builder/src/types.ts @@ -4,7 +4,6 @@ import { BaseEventAction, EventAction } from "./editor/recoil/eventActions"; import { PbState } from "./editor/recoil/modules/types"; import { GenericRecord, Plugin } from "@webiny/app/types"; import { BindComponent } from "@webiny/form"; -import { IconName, IconPrefix } from "@fortawesome/fontawesome-svg-core"; import { Icon } from "@webiny/app-admin/components/IconPicker/types"; import { FormAPI, FormOnSubmit, FormSetValue, GenericFormData } from "@webiny/form/types"; import { CoreOptions } from "medium-editor"; @@ -15,6 +14,7 @@ import { Theme } from "@webiny/app-theme/types"; import { Renderer } from "@webiny/app-page-builder-elements/types"; import { FolderTableItem, RecordTableItem, SearchRecordItem } from "@webiny/app-aco/table.types"; import type { SourceType } from "dnd-core"; +import { IconDto } from "@webiny/admin-ui"; export type DragObjectWithType = { type: SourceType; @@ -622,24 +622,9 @@ export interface PbEditorPageQueryFieldsPlugin extends Plugin { fields: string; } -export type PbIcon = { - /** - * [ pack, icon ], ex: ["fab", "cog"] - */ - id: [IconPrefix, IconName]; - /** - * Icon name - */ - name: string; - /** - * SVG element - */ - svg: ReactElement; -}; - export type PbIconsPlugin = Plugin & { type: "pb-icons"; - getIcons(): PbIcon[]; + getIcons(): IconDto[]; }; export type PbEditorToolbarTopPlugin = Plugin & { diff --git a/packages/ui/src/DelayedOnChange/DelayedOnChange.ts b/packages/ui/src/DelayedOnChange/DelayedOnChange.ts index 0aab0847c9a..b897d253126 100644 --- a/packages/ui/src/DelayedOnChange/DelayedOnChange.ts +++ b/packages/ui/src/DelayedOnChange/DelayedOnChange.ts @@ -1,8 +1,8 @@ import { - ApplyValueCb, + type ApplyValueCb, DelayedOnChange, - DelayedOnChangeProps, - OnChangeCallable + type DelayedOnChangeProps, + type OnChangeCallable } from "@webiny/admin-ui/DelayedOnChange"; export { diff --git a/yarn.lock b/yarn.lock index f7e19502ae8..60c296d0b87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14000,7 +14000,7 @@ __metadata: languageName: node linkType: hard -"@types/react-virtualized@npm:^9": +"@types/react-virtualized@npm:^9.22.0": version: 9.22.0 resolution: "@types/react-virtualized@npm:9.22.0" dependencies: @@ -14010,16 +14010,6 @@ __metadata: languageName: node linkType: hard -"@types/react-virtualized@npm:^9.21.16": - version: 9.21.21 - resolution: "@types/react-virtualized@npm:9.21.21" - dependencies: - "@types/prop-types": "npm:*" - "@types/react": "npm:^17" - checksum: 10/549ada449c05347035520297b7d6f145ebd298d0c0dd304848c6c575f2291c33b4429b29a05123fb7a8767e2e43167c3433234a49209d08f0fe6aef4e6b013cd - languageName: node - linkType: hard - "@types/react@npm:18.2.79": version: 18.2.79 resolution: "@types/react@npm:18.2.79" @@ -15026,7 +15016,7 @@ __metadata: "@svgr/webpack": "npm:^6.1.1" "@tanstack/react-table": "npm:^8.20.6" "@types/react": "npm:18.2.79" - "@types/react-virtualized": "npm:^9" + "@types/react-virtualized": "npm:^9.22.0" "@webiny/cli": "npm:0.0.0" "@webiny/project-utils": "npm:0.0.0" "@webiny/react-composition": "npm:0.0.0" @@ -17141,6 +17131,7 @@ __metadata: "@emotion/babel-plugin": "npm:^11.11.0" "@fortawesome/fontawesome-svg-core": "npm:^1.3.0" "@types/react": "npm:18.2.79" + "@webiny/admin-ui": "npm:0.0.0" "@webiny/app-security": "npm:0.0.0" "@webiny/cli": "npm:0.0.0" "@webiny/form": "npm:0.0.0" @@ -17177,6 +17168,7 @@ __metadata: "@material-design-icons/svg": "npm:^0.14.13" "@svgr/webpack": "npm:^6.1.1" "@types/react": "npm:18.2.79" + "@webiny/admin-ui": "npm:0.0.0" "@webiny/app": "npm:0.0.0" "@webiny/app-aco": "npm:0.0.0" "@webiny/app-admin": "npm:0.0.0" @@ -17227,7 +17219,6 @@ __metadata: react-dom: "npm:18.2.0" react-helmet: "npm:^6.1.0" react-hotkeyz: "npm:^1.0.4" - react-virtualized: "npm:^9.22.5" rimraf: "npm:^6.0.1" typescript: "npm:5.3.3" use-deep-compare-effect: "npm:^1.8.1" @@ -17388,7 +17379,6 @@ __metadata: "@types/platform": "npm:^1.3.4" "@types/react": "npm:18.2.79" "@types/react-images": "npm:^0.5.3" - "@types/react-virtualized": "npm:^9.21.16" "@types/resize-observer-browser": "npm:^0.1.4" "@types/store": "npm:^2.0.2" "@webiny/admin-ui": "npm:0.0.0" @@ -17448,7 +17438,6 @@ __metadata: react-images: "npm:^0.5.19" react-in-viewport: "npm:^1.0.0-alpha.30" react-sortable: "npm:^2.0.0" - react-virtualized: "npm:^9.22.5" recoil: "npm:^0.7.7" rimraf: "npm:^6.0.1" slugify: "npm:^1.6.6"