From 7da628e4ae19a390dcaf1c84d731eba2d48a30fc Mon Sep 17 00:00:00 2001 From: sagar davara Date: Wed, 22 Jan 2025 22:36:00 +0530 Subject: [PATCH 1/8] fix: modularize icons --- .changeset/rich-avocados-type.md | 7 +++ apps/kitchen-sink/package.json | 1 + apps/kitchen-sink/src/App.tsx | 9 +++ packages/framework/src/shared/dto.ts | 12 +++- packages/runtime/package.json | 1 - packages/runtime/src/EnsembleApp.tsx | 22 ++++++- .../src/__tests__/EnsembleApp.test.tsx | 30 +++++++++- packages/runtime/src/registry.tsx | 28 ++++++++- packages/runtime/src/runtime/menu.tsx | 58 ++++++------------- packages/runtime/src/runtime/modal/index.tsx | 12 ++-- packages/runtime/src/shared/icons.tsx | 20 ------- packages/runtime/src/shared/styles.ts | 13 +++-- .../runtime/src/widgets/Avatar/Avatar.tsx | 34 ++++++----- pnpm-lock.yaml | 38 +++++++----- 14 files changed, 177 insertions(+), 108 deletions(-) create mode 100644 .changeset/rich-avocados-type.md delete mode 100644 packages/runtime/src/shared/icons.tsx diff --git a/.changeset/rich-avocados-type.md b/.changeset/rich-avocados-type.md new file mode 100644 index 000000000..dbd5517c8 --- /dev/null +++ b/.changeset/rich-avocados-type.md @@ -0,0 +1,7 @@ +--- +"@ensembleui/react-framework": patch +"@ensembleui/react-kitchen-sink": patch +"@ensembleui/react-runtime": patch +--- + +reduce runtime bundle size by modularize icons diff --git a/apps/kitchen-sink/package.json b/apps/kitchen-sink/package.json index e696f4cc0..b5a187bc6 100644 --- a/apps/kitchen-sink/package.json +++ b/apps/kitchen-sink/package.json @@ -5,6 +5,7 @@ "dependencies": { "@ensembleui/react-framework": "workspace:*", "@ensembleui/react-runtime": "workspace:*", + "@mui/icons-material": "^6.4.1", "react": "^18.2.0", "react-dom": "^18.2.0", "web-vitals": "^2.1.4" diff --git a/apps/kitchen-sink/src/App.tsx b/apps/kitchen-sink/src/App.tsx index 16345b2cb..c2b515c98 100644 --- a/apps/kitchen-sink/src/App.tsx +++ b/apps/kitchen-sink/src/App.tsx @@ -1,6 +1,8 @@ import type { ApplicationDTO } from "@ensembleui/react-framework"; import { EnsembleApp } from "@ensembleui/react-runtime"; +import * as Icons from "@mui/icons-material"; // Screens +import React from "react"; import MenuYAML from "./ensemble/screens/menu.yaml"; import HomeYAML from "./ensemble/screens/home.yaml"; import WidgetsYAML from "./ensemble/screens/widgets.yaml"; @@ -142,6 +144,13 @@ const testApp: ApplicationDTO = { content: String(TestActionsYAML), }, ], + icons: { + mui: { icons: Icons as { [key: string]: React.ComponentType } }, + custom: { + prefix: "Mui", + icons: Icons as { [key: string]: React.ComponentType }, + }, + }, config: EnsembleConfig, }; diff --git a/packages/framework/src/shared/dto.ts b/packages/framework/src/shared/dto.ts index 1098777b5..d93b17674 100644 --- a/packages/framework/src/shared/dto.ts +++ b/packages/framework/src/shared/dto.ts @@ -23,7 +23,7 @@ export interface ApplicationDTO extends Omit { readonly languages?: LanguageDTO[]; readonly config?: string | EnsembleConfigYAML; readonly fonts?: FontDTO[]; - + readonly icons: IconDTO; readonly description?: string; readonly isPublic?: boolean; readonly isAutoGenerated?: boolean; @@ -63,3 +63,13 @@ export interface FontDTO { readonly fontWeight: string; readonly fontStyle: string; } + +export interface IconSet { + readonly prefix?: string; + readonly icons?: { [key: string]: unknown }; +} + +export interface IconDTO { + readonly mui: IconSet; + readonly custom?: IconSet; +} diff --git a/packages/runtime/package.json b/packages/runtime/package.json index ef0666ca9..b1ce9999b 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -27,7 +27,6 @@ "@emotion/styled": "^11.11.0", "@ensembleui/react-framework": "workspace:*", "@lottiefiles/react-lottie-player": "^3.5.3", - "@mui/icons-material": "^5.14.9", "@mui/material": "^5.14.9", "@mui/x-date-pickers": "^6.18.3", "@react-oauth/google": "^0.12.1", diff --git a/packages/runtime/src/EnsembleApp.tsx b/packages/runtime/src/EnsembleApp.tsx index b31edcffb..1ec39351e 100644 --- a/packages/runtime/src/EnsembleApp.tsx +++ b/packages/runtime/src/EnsembleApp.tsx @@ -1,8 +1,9 @@ -import { useEffect, useMemo, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import type { ApplicationDTO, EnsembleAppModel, ApplicationLoader, + IconSet, } from "@ensembleui/react-framework"; import { ApplicationContextProvider, @@ -19,7 +20,7 @@ import { EnsembleScreen } from "./runtime/screen"; import { ErrorPage } from "./runtime/error"; // Register built in widgets; import "./widgets"; -import { WidgetRegistry } from "./registry"; +import { IconRegistry, WidgetRegistry } from "./registry"; import { createCustomWidget } from "./runtime/customWidget"; import { ModalWrapper } from "./runtime/modal"; @@ -49,6 +50,16 @@ export const EnsembleApp: React.FC = ({ return; } + const registerIcons = (iconSet?: IconSet): void => { + const { prefix = "", icons = {} } = (iconSet || {}) as { + prefix?: string; + icons?: { [key: string]: React.ComponentType }; + }; + Object.entries(icons).forEach(([name, icon]) => { + IconRegistry.register(`${prefix}${name}`, icon); + }); + }; + const parseApp = (appDto: ApplicationDTO): void => { const parsedApp = EnsembleParser.parseApplication(appDto); parsedApp.customWidgets.forEach((customWidget) => { @@ -58,6 +69,13 @@ export const EnsembleApp: React.FC = ({ ); }); + if (!appDto.icons?.mui) { + throw new Error("An mui icons must be provided"); + } + + registerIcons(appDto.icons.mui); + registerIcons(appDto.icons?.custom); + setApp(parsedApp); }; diff --git a/packages/runtime/src/__tests__/EnsembleApp.test.tsx b/packages/runtime/src/__tests__/EnsembleApp.test.tsx index 05ca521f6..41f081883 100644 --- a/packages/runtime/src/__tests__/EnsembleApp.test.tsx +++ b/packages/runtime/src/__tests__/EnsembleApp.test.tsx @@ -57,7 +57,12 @@ test("Renders error page", () => { themes: {}, }); try { - render(); + render( + , + ); } catch (e) { // no-op } @@ -98,6 +103,7 @@ test("Renders view widget of home screen", () => { application={ { screens: [{ content: "" }], + icons: { mui: {} }, } as ApplicationDTO } />, @@ -143,6 +149,7 @@ test("Bind data from other widgets", async () => { application={ { screens: [{ content: "" }], + icons: { mui: {} }, } as ApplicationDTO } />, @@ -192,6 +199,7 @@ test("Updates values through Ensemble state", async () => { application={ { screens: [{ content: "" }], + icons: { mui: {} }, } as ApplicationDTO } />, @@ -206,3 +214,23 @@ test("Updates values through Ensemble state", async () => { const updatedText = await screen.findByText("Spiderman"); expect(updatedText).not.toBeNull(); }); + +test("Renders mui icon error", () => { + const logSpy = jest.spyOn(console, "error").mockImplementation(jest.fn()); + + parseApplicationMock.mockReturnValue({ + home: {}, + screens: [], + customWidgets: [], + themes: {}, + }); + try { + render(); + } catch (e) { + // no-op + } + + expect(logSpy.mock.calls.toString()).toContain( + "An mui icons must be provided", + ); +}); diff --git a/packages/runtime/src/registry.tsx b/packages/runtime/src/registry.tsx index 617a6806f..a9a23352f 100644 --- a/packages/runtime/src/registry.tsx +++ b/packages/runtime/src/registry.tsx @@ -1,11 +1,14 @@ import { Alert } from "antd"; import type { ReactElement } from "react"; -export type WidgetComponent = React.FC; +export type WidgetComponent = React.ComponentType; // eslint-disable-next-line @typescript-eslint/no-explicit-any const registry: { [key: string]: WidgetComponent | undefined } = {}; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const iconRegistry: { [key: string]: WidgetComponent | undefined } = {}; + export const WidgetRegistry = { register: (name: string, component: WidgetComponent): void => { registry[name] = component; @@ -25,6 +28,29 @@ export const WidgetRegistry = { }, }; +export const IconRegistry = { + register: (name: string, component: WidgetComponent): void => { + iconRegistry[name] = component; + }, + find: (name: string): WidgetComponent | ReactElement => { + const Icon = iconRegistry[name]; + if (!Icon) { + return UnknownIcon; + } + return Icon; + }, + findOrNull: (name: string): WidgetComponent | null => { + return iconRegistry[name] || null; + }, + unregister: (name: string): void => { + delete iconRegistry[name]; + }, +}; + const UnknownWidget: React.FC<{ missingName: string }> = ({ missingName }) => { return ; }; + +const UnknownIcon: React.FC<{ name: string }> = ({ name }) => { + return ; +}; diff --git a/packages/runtime/src/runtime/menu.tsx b/packages/runtime/src/runtime/menu.tsx index d3348cb11..c4122b173 100644 --- a/packages/runtime/src/runtime/menu.tsx +++ b/packages/runtime/src/runtime/menu.tsx @@ -1,4 +1,4 @@ -import type { PropsWithChildren, ReactNode } from "react"; +import type { PropsWithChildren } from "react"; import React, { useState, useEffect, useCallback, useMemo } from "react"; import { Menu as AntMenu, @@ -6,7 +6,6 @@ import { Drawer as AntDrawer, ConfigProvider, } from "antd"; -import * as MuiIcons from "@mui/icons-material"; import { unwrapWidget, useRegisterBindings, @@ -15,8 +14,9 @@ import { EnsembleMenuModelType, } from "@ensembleui/react-framework"; import { Outlet, Link, useLocation } from "react-router-dom"; -import { cloneDeep, omit } from "lodash-es"; +import { cloneDeep, isString, omit } from "lodash-es"; import { getColor } from "../shared/styles"; +import type { IconProps } from "../shared/types"; import { EnsembleRuntime } from "./runtime"; // eslint-disable-next-line import/no-cycle import { useEnsembleAction } from "./hooks"; @@ -48,8 +48,8 @@ export interface EnsembleMenuContext { interface MenuItemProps { id?: string; testId?: string; - icon?: string | { [key: string]: unknown }; - activeIcon?: string | { [key: string]: unknown }; + icon?: string | IconProps; + activeIcon?: string | IconProps; iconLibrary?: "default" | "fontAwesome"; label?: string; url?: string; @@ -98,29 +98,6 @@ interface DrawerMenuStyles extends MenuStyles { position?: "left" | "right" | "top" | "bottom"; } -const renderMuiIcon = ( - iconName?: string, - width = "15px", - height = "15px", -): ReactNode => { - if (!iconName) { - return null; - } - - const MuiIconComponent = MuiIcons[iconName as keyof typeof MuiIcons]; - if (MuiIconComponent) { - return ( - - ); - } - return null; -}; - const CustomLink: React.FC = ({ item, children, @@ -358,27 +335,26 @@ const MenuItems: React.FC<{ setSelectedItem, isCollapsed = false, }) => { - const getIcon = useCallback( + const getCustomIcon = useCallback( (item: MenuItemProps) => { const key = selectedItem === item.page ? "activeIcon" : "icon"; - const icon = + const iconProps = selectedItem === item.page && item.activeIcon ? item.activeIcon : item.icon; - if (!icon) { + if (!iconProps) { return null; } - if (typeof icon === "string") { - return renderMuiIcon(icon, styles.iconWidth, styles.iconHeight); - } - return EnsembleRuntime.render([ - { - ...unwrapWidget({ Icon: icon }), - key, - }, - ]); + const icon = isString(iconProps) + ? { + name: iconProps, + styles: { width: styles.iconWidth, height: styles.iconHeight }, + } + : iconProps; + + return EnsembleRuntime.render([{ ...unwrapWidget({ Icon: icon }), key }]); }, [styles.iconHeight, styles.iconWidth, selectedItem], ); @@ -425,7 +401,7 @@ const MenuItems: React.FC<{ {items.map((item, itemIndex) => ( { if (!item.openNewTab && item.page) { diff --git a/packages/runtime/src/runtime/modal/index.tsx b/packages/runtime/src/runtime/modal/index.tsx index 4f88c00a2..ce8dd7579 100644 --- a/packages/runtime/src/runtime/modal/index.tsx +++ b/packages/runtime/src/runtime/modal/index.tsx @@ -11,9 +11,11 @@ import { useState, } from "react"; import { createPortal } from "react-dom"; -import OpenInFullIcon from "@mui/icons-material/OpenInFull"; -import CloseFullscreenIcon from "@mui/icons-material/CloseFullscreen"; -import { CloseOutlined } from "@ant-design/icons"; +import { + CloseOutlined, + FullscreenOutlined, + FullscreenExitOutlined, +} from "@ant-design/icons"; import { generateRandomString, useEvaluate } from "@ensembleui/react-framework"; import { isString, omit, pick } from "lodash-es"; import { useNavigate } from "react-router-dom"; @@ -253,7 +255,7 @@ export const ModalWrapper: React.FC = ({ children }) => { const getFullScreenIcon = (index: number): React.ReactNode => isFullScreen[index] ? ( - setIsFullScreen((oldIsFullScreen) => { const newIsFullScreen = [...oldIsFullScreen]; @@ -264,7 +266,7 @@ export const ModalWrapper: React.FC = ({ children }) => { style={iconStyles} /> ) : ( - setIsFullScreen((oldIsFullScreen) => { const newIsFullScreen = [...oldIsFullScreen]; diff --git a/packages/runtime/src/shared/icons.tsx b/packages/runtime/src/shared/icons.tsx deleted file mode 100644 index 9c9ae170f..000000000 --- a/packages/runtime/src/shared/icons.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import * as MuiIcons from "@mui/icons-material"; - -export const renderMuiIcon = ( - iconName: keyof typeof MuiIcons, - width?: string, - height?: string, -) => { - const MuiIconComponent = MuiIcons[iconName]; - if (MuiIconComponent) { - return ( - - ); - } - return null; -}; diff --git a/packages/runtime/src/shared/styles.ts b/packages/runtime/src/shared/styles.ts index 781aefd7c..8d3c7a2eb 100644 --- a/packages/runtime/src/shared/styles.ts +++ b/packages/runtime/src/shared/styles.ts @@ -1,8 +1,7 @@ -import * as Icons from "@mui/icons-material"; -import type { SvgIconComponent } from "@mui/icons-material"; import { get, isInteger } from "lodash-es"; -import React from "react"; -import { TextAlignment } from "./styleSchema"; +import type React from "react"; +import { IconRegistry } from "../registry"; +import type { TextAlignment } from "./styleSchema"; type Color = number | string; @@ -97,8 +96,10 @@ export const getCrossAxis = (crossAxis: string): string | undefined => { } }; -export const getIcon = (name: string): SvgIconComponent | undefined => { - return get(Icons, name) as SvgIconComponent; +export const getIcon = >( + name: string, +): T | undefined => { + return IconRegistry.find(name) as T | undefined; }; export const getComponentStyles = ( diff --git a/packages/runtime/src/widgets/Avatar/Avatar.tsx b/packages/runtime/src/widgets/Avatar/Avatar.tsx index a09c5f8c4..6d73d7636 100644 --- a/packages/runtime/src/widgets/Avatar/Avatar.tsx +++ b/packages/runtime/src/widgets/Avatar/Avatar.tsx @@ -7,8 +7,10 @@ import { MenuItem, ListItemIcon, } from "@mui/material"; +import { isString } from "lodash-es"; import { WidgetRegistry } from "../../registry"; import type { EnsembleWidgetStyles, IconProps } from "../../shared/types"; +// eslint-disable-next-line import/no-cycle import { Icon } from "../Icon"; import { useEnsembleAction } from "../../runtime/hooks/useEnsembleAction"; import { generateInitials } from "./utils/generateInitials"; @@ -108,20 +110,24 @@ export const Avatar: React.FC = (props) => { onClose={handleMenuClose} open={isMenuOpen} > - {values?.menu.map((menuItem, idx) => ( - handleMenuClick(menuItem)}> - {menuItem.icon ? ( - - - - ) : null} - {menuItem.label} - - ))} + {values?.menu.map((menuItem, idx) => { + const icon = isString(menuItem.icon) + ? { name: menuItem.icon } + : menuItem.icon; + return ( + handleMenuClick(menuItem)} + > + {icon ? ( + + + + ) : null} + {menuItem.label} + + ); + })} ) : null} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ad7d2e5aa..2123151c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,7 @@ importers: '@craco/craco': ^7.1.0 '@ensembleui/react-framework': workspace:* '@ensembleui/react-runtime': workspace:* + '@mui/icons-material': ^6.4.1 '@testing-library/jest-dom': ^5.17.0 '@testing-library/react': ^13.4.0 '@testing-library/user-event': ^13.5.0 @@ -58,6 +59,7 @@ importers: dependencies: '@ensembleui/react-framework': link:../../packages/framework '@ensembleui/react-runtime': link:../../packages/runtime + '@mui/icons-material': 6.4.1_fb28c32afc3535fd55e20f7883f1b980 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 web-vitals: 2.1.4 @@ -336,7 +338,6 @@ importers: '@emotion/styled': ^11.11.0 '@ensembleui/react-framework': workspace:* '@lottiefiles/react-lottie-player': ^3.5.3 - '@mui/icons-material': ^5.14.9 '@mui/material': ^5.14.9 '@mui/x-date-pickers': ^6.18.3 '@react-oauth/google': ^0.12.1 @@ -374,7 +375,6 @@ importers: '@emotion/styled': 11.11.0_dd4092d1e0c7dc2863a676e563fa1e79 '@ensembleui/react-framework': link:../framework '@lottiefiles/react-lottie-player': 3.5.3 - '@mui/icons-material': 5.15.11_da55fe8c6e6066fef4b7dc0994910613 '@mui/material': 5.15.11_d729d530559e435818d6dfbb9bc0bc34 '@mui/x-date-pickers': 6.19.6_1dcf445c77f90e2d41581270c9a3b06f '@react-oauth/google': 0.12.1 @@ -2647,6 +2647,12 @@ packages: dependencies: regenerator-runtime: 0.14.1 + /@babel/runtime/7.26.0: + resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + /@babel/template/7.24.0: resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} engines: {node: '>=6.9.0'} @@ -4533,21 +4539,21 @@ packages: resolution: {integrity: sha512-JVrJ9Jo4gyU707ujnRzmE8ABBWpXd6FwL9GYULmwZRtfPg89ggXs/S3MStQkpJ1JRWfdLL6S5syXmgQGq5EDAw==} dev: true - /@mui/icons-material/5.15.11_da55fe8c6e6066fef4b7dc0994910613: - resolution: {integrity: sha512-R5ZoQqnKpd+5Ew7mBygTFLxgYsQHPhgR3TDXSgIHYIjGzYuyPLmGLSdcPUoMdi6kxiYqHlpPj4NJxlbaFD0UHA==} - engines: {node: '>=12.0.0'} + /@mui/icons-material/6.4.1_fb28c32afc3535fd55e20f7883f1b980: + resolution: {integrity: sha512-wsxFcUTQxt4s+7Bg4GgobqRjyaHLmZGNOs+HJpbwrwmLbT6mhIJxhpqsKzzWq9aDY8xIe7HCjhpH7XI5UD6teA==} + engines: {node: '>=14.0.0'} peerDependencies: - '@mui/material': ^5.0.0 - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 + '@mui/material': ^6.4.1 + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.0 - '@mui/material': 5.15.11_d729d530559e435818d6dfbb9bc0bc34 + '@babel/runtime': 7.26.0 '@types/react': 18.2.62 - dev: true + react: 18.2.0 + dev: false /@mui/material/5.15.11_d729d530559e435818d6dfbb9bc0bc34: resolution: {integrity: sha512-FA3eEuEZaDaxgN3CgfXezMWbCZ4VCeU/sv0F0/PK5n42qIgsPVD6q+j71qS7/62sp6wRFMHtDMpXRlN+tT/7NA==} @@ -7708,7 +7714,7 @@ packages: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 cosmiconfig: 7.1.0 resolve: 1.22.8 dev: true @@ -7808,7 +7814,7 @@ packages: '@babel/preset-env': 7.24.0_@babel+core@7.24.0 '@babel/preset-react': 7.23.3_@babel+core@7.24.0 '@babel/preset-typescript': 7.23.3_@babel+core@7.24.0 - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 babel-plugin-macros: 3.1.0 babel-plugin-transform-react-remove-prop-types: 0.4.24 transitivePeerDependencies: @@ -10252,7 +10258,7 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 aria-query: 5.3.0 array-includes: 3.1.8 array.prototype.flatmap: 1.3.2 @@ -17491,7 +17497,7 @@ packages: /regenerator-transform/0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 dev: true /regex-parser/2.3.0: @@ -20195,7 +20201,7 @@ packages: '@apideck/better-ajv-errors': 0.3.6_ajv@8.12.0 '@babel/core': 7.24.0 '@babel/preset-env': 7.24.0_@babel+core@7.24.0 - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rollup/plugin-babel': 5.3.1_@babel+core@7.24.0+rollup@2.79.1 '@rollup/plugin-node-resolve': 11.2.1_rollup@2.79.1 '@rollup/plugin-replace': 2.4.2_rollup@2.79.1 From 145d476a93a2275b771af5a3fd0c46c0f0043b13 Mon Sep 17 00:00:00 2001 From: sagar davara Date: Wed, 22 Jan 2025 22:43:48 +0530 Subject: [PATCH 2/8] fix: added Icons in starterApp --- apps/starter/package.json | 1 + apps/starter/src/ensemble/index.ts | 8 ++++++++ pnpm-lock.yaml | 4 +++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/starter/package.json b/apps/starter/package.json index b9da91bc4..ceaf139ff 100644 --- a/apps/starter/package.json +++ b/apps/starter/package.json @@ -5,6 +5,7 @@ "dependencies": { "@ensembleui/react-framework": "workspace:*", "@ensembleui/react-runtime": "workspace:*", + "@mui/icons-material": "^6.4.1", "firebase": "9.10.0", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/apps/starter/src/ensemble/index.ts b/apps/starter/src/ensemble/index.ts index e14b0f110..0066976a5 100644 --- a/apps/starter/src/ensemble/index.ts +++ b/apps/starter/src/ensemble/index.ts @@ -1,4 +1,5 @@ import { type ApplicationDTO } from "@ensembleui/react-framework"; +import * as Icons from "@mui/icons-material"; // Screens import MenuYAML from "./screens/menu.yaml"; import HomeYAML from "./screens/home.yaml"; @@ -55,4 +56,11 @@ export const starterApp: ApplicationDTO = { content: String(HelpYAML), }, ], + icons: { + mui: { icons: Icons as { [key: string]: React.ComponentType } }, + custom: { + prefix: "Mui", + icons: Icons as { [key: string]: React.ComponentType }, + }, + }, }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2123151c2..353582db2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -156,6 +156,7 @@ importers: '@craco/craco': ^7.1.0 '@ensembleui/react-framework': workspace:* '@ensembleui/react-runtime': workspace:* + '@mui/icons-material': ^6.4.1 '@testing-library/jest-dom': ^5.17.0 '@testing-library/react': ^13.4.0 '@testing-library/user-event': ^13.5.0 @@ -181,6 +182,7 @@ importers: dependencies: '@ensembleui/react-framework': link:../../packages/framework '@ensembleui/react-runtime': link:../../packages/runtime + '@mui/icons-material': 6.4.1_fb28c32afc3535fd55e20f7883f1b980 firebase: 9.10.0 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 @@ -5892,7 +5894,7 @@ packages: engines: {node: '>=12'} dependencies: '@babel/code-frame': 7.23.5 - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@types/aria-query': 5.0.4 aria-query: 5.1.3 chalk: 4.1.2 From 104cc55bc85b09700521f89f61cdaeb8ea313391 Mon Sep 17 00:00:00 2001 From: sagar davara Date: Wed, 22 Jan 2025 22:48:50 +0530 Subject: [PATCH 3/8] fix: icons added in preview app --- apps/preview/package.json | 1 + apps/preview/src/AppPreview.tsx | 8 +++ pnpm-lock.yaml | 98 +++++++++++++++++---------------- 3 files changed, 59 insertions(+), 48 deletions(-) diff --git a/apps/preview/package.json b/apps/preview/package.json index ecbf00a3e..f349ed2f2 100644 --- a/apps/preview/package.json +++ b/apps/preview/package.json @@ -5,6 +5,7 @@ "dependencies": { "@ensembleui/react-framework": "workspace:*", "@ensembleui/react-runtime": "workspace:*", + "@mui/icons-material": "^6.4.1", "antd": "^5.9.0", "firebase": "9.10.0", "lodash-es": "^4.17.21", diff --git a/apps/preview/src/AppPreview.tsx b/apps/preview/src/AppPreview.tsx index f50dd9b56..6018e6663 100644 --- a/apps/preview/src/AppPreview.tsx +++ b/apps/preview/src/AppPreview.tsx @@ -3,6 +3,7 @@ import type { ApplicationLoader, EnsembleDocument, } from "@ensembleui/react-framework"; +import * as Icons from "@mui/icons-material"; import { getFirestoreApplicationLoader } from "@ensembleui/react-framework"; import { EnsembleApp } from "@ensembleui/react-runtime"; import { Alert } from "antd"; @@ -32,6 +33,13 @@ const customPreviewWidgetApp: ApplicationDTO = { scripts: [], id: "customWidgetPreview", name: "customWidgetPreview", + icons: { + mui: { icons: Icons as { [key: string]: React.ComponentType } }, + custom: { + prefix: "Mui", + icons: Icons as { [key: string]: React.ComponentType }, + }, + }, }; const createCustomWidgetPreviewApp = ( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 353582db2..f6bd12aa5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,6 +89,7 @@ importers: '@craco/craco': ^7.1.0 '@ensembleui/react-framework': workspace:* '@ensembleui/react-runtime': workspace:* + '@mui/icons-material': ^6.4.1 '@testing-library/jest-dom': ^5.17.0 '@testing-library/react': ^13.4.0 '@testing-library/user-event': ^13.5.0 @@ -120,6 +121,7 @@ importers: dependencies: '@ensembleui/react-framework': link:../../packages/framework '@ensembleui/react-runtime': link:../../packages/runtime + '@mui/icons-material': 6.4.1_fb28c32afc3535fd55e20f7883f1b980 antd: 5.20.0_react-dom@18.2.0+react@18.2.0 firebase: 9.10.0 lodash-es: 4.17.21 @@ -459,7 +461,7 @@ packages: react-dom: '>=16.9.0' dependencies: '@ant-design/cssinjs': 1.21.0_react-dom@18.2.0+react@18.2.0 - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 @@ -486,7 +488,7 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@emotion/hash': 0.8.0 '@emotion/unitless': 0.7.5 classnames: 2.5.1 @@ -501,7 +503,7 @@ packages: resolution: {integrity: sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==} engines: {node: '>=8.x'} dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 /@ant-design/icons-svg/4.4.2: resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} @@ -529,7 +531,7 @@ packages: dependencies: '@ant-design/colors': 7.1.0 '@ant-design/icons-svg': 4.4.2 - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -553,7 +555,7 @@ packages: peerDependencies: react: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 json2mq: 0.2.0 react: 18.2.0 @@ -4971,7 +4973,7 @@ packages: resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==} engines: {node: '>=14.x'} dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 /@rc-component/color-picker/2.0.0: resolution: {integrity: sha512-52z3XqUwUr0+Br3B8RjN2GfuR1Pk3MZPAVd34WptWFEOyTz7OQmmn8nqgXUBOYwZem8jXp6G3iv+6Dm1+1epJA==} @@ -4992,7 +4994,7 @@ packages: react-dom: '>=16.9.0' dependencies: '@ant-design/fast-color': 2.0.6 - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -5015,7 +5017,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 @@ -5025,7 +5027,7 @@ packages: resolution: {integrity: sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==} engines: {node: '>=8.x'} dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 /@rc-component/mutate-observer/1.1.0: resolution: {integrity: sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==} @@ -5046,7 +5048,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -5072,7 +5074,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -5098,7 +5100,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -5126,7 +5128,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/portal': 1.1.2_react-dom@18.2.0+react@18.2.0 '@rc-component/trigger': 2.2.0_react-dom@18.2.0+react@18.2.0 classnames: 2.5.1 @@ -5157,7 +5159,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/portal': 1.1.2_react-dom@18.2.0+react@18.2.0 classnames: 2.5.1 rc-motion: 2.9.2_react-dom@18.2.0+react@18.2.0 @@ -16062,7 +16064,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 array-tree-filter: 2.1.0 classnames: 2.5.1 rc-select: 14.15.1_react-dom@18.2.0+react@18.2.0 @@ -16089,7 +16091,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -16114,7 +16116,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-motion: 2.9.2_react-dom@18.2.0+react@18.2.0 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 @@ -16141,7 +16143,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/portal': 1.1.2_react-dom@18.2.0+react@18.2.0 classnames: 2.5.1 rc-motion: 2.9.2_react-dom@18.2.0+react@18.2.0 @@ -16169,7 +16171,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/portal': 1.1.2_react-dom@18.2.0+react@18.2.0 classnames: 2.5.1 rc-motion: 2.9.2_react-dom@18.2.0+react@18.2.0 @@ -16196,7 +16198,7 @@ packages: react: '>=16.11.0' react-dom: '>=16.11.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/trigger': 2.2.0_react-dom@18.2.0+react@18.2.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 @@ -16223,7 +16225,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/async-validator': 5.0.4 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -16250,7 +16252,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/portal': 1.1.2_react-dom@18.2.0+react@18.2.0 classnames: 2.5.1 rc-dialog: 9.5.2_react-dom@18.2.0+react@18.2.0 @@ -16279,7 +16281,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/mini-decimal': 1.1.0 classnames: 2.5.1 rc-input: 1.6.2_react-dom@18.2.0+react@18.2.0 @@ -16305,7 +16307,7 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -16333,7 +16335,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/trigger': 2.2.0_react-dom@18.2.0+react@18.2.0 classnames: 2.5.1 rc-input: 1.6.2_react-dom@18.2.0+react@18.2.0 @@ -16364,7 +16366,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/trigger': 2.2.0_react-dom@18.2.0+react@18.2.0 classnames: 2.5.1 rc-motion: 2.9.2_react-dom@18.2.0+react@18.2.0 @@ -16391,7 +16393,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -16418,7 +16420,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-motion: 2.9.2_react-dom@18.2.0+react@18.2.0 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 @@ -16444,7 +16446,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-resize-observer: 1.4.0_react-dom@18.2.0+react@18.2.0 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 @@ -16469,7 +16471,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -16496,7 +16498,7 @@ packages: moment: optional: true dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/trigger': 2.2.0_react-dom@18.2.0+react@18.2.0 classnames: 2.5.1 dayjs: 1.11.12 @@ -16553,7 +16555,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -16579,7 +16581,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -16604,7 +16606,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -16630,7 +16632,7 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-motion: 2.9.2_react-dom@18.2.0+react@18.2.0 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 @@ -16661,7 +16663,7 @@ packages: react: '*' react-dom: '*' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/trigger': 2.2.0_react-dom@18.2.0+react@18.2.0 classnames: 2.5.1 rc-motion: 2.9.2_react-dom@18.2.0+react@18.2.0 @@ -16691,7 +16693,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -16717,7 +16719,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -16741,7 +16743,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -16770,7 +16772,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/context': 1.4.0_react-dom@18.2.0+react@18.2.0 classnames: 2.5.1 rc-resize-observer: 1.4.0_react-dom@18.2.0+react@18.2.0 @@ -16803,7 +16805,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-dropdown: 4.2.0_react-dom@18.2.0+react@18.2.0 rc-menu: 9.14.1_react-dom@18.2.0+react@18.2.0 @@ -16833,7 +16835,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-input: 1.6.2_react-dom@18.2.0+react@18.2.0 rc-resize-observer: 1.4.0_react-dom@18.2.0+react@18.2.0 @@ -16859,7 +16861,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/trigger': 2.2.0_react-dom@18.2.0+react@18.2.0 classnames: 2.5.1 react: 18.2.0 @@ -16885,7 +16887,7 @@ packages: react: '*' react-dom: '*' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-select: 14.15.1_react-dom@18.2.0+react@18.2.0 rc-tree: 5.8.8_react-dom@18.2.0+react@18.2.0 @@ -16915,7 +16917,7 @@ packages: react: '*' react-dom: '*' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-motion: 2.9.2_react-dom@18.2.0+react@18.2.0 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 @@ -16941,7 +16943,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 react: 18.2.0 @@ -16964,7 +16966,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 react-is: 18.2.0 @@ -16990,7 +16992,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-resize-observer: 1.4.0_react-dom@18.2.0+react@18.2.0 rc-util: 5.43.0_react-dom@18.2.0+react@18.2.0 From e403f9011574d6eb25db44f04f55fed52255f32e Mon Sep 17 00:00:00 2001 From: sagar davara Date: Tue, 28 Jan 2025 12:18:13 +0530 Subject: [PATCH 4/8] fix: improve icon modularization --- apps/kitchen-sink/package.json | 1 + apps/kitchen-sink/src/App.tsx | 15 +- .../src/ensemble/screens/menu.yaml | 2 +- apps/preview/src/AppPreview.tsx | 8 -- apps/starter/src/ensemble/index.ts | 8 -- packages/framework/src/shared/dto.ts | 9 +- packages/runtime/package.json | 2 + packages/runtime/src/EnsembleApp.tsx | 31 ++-- .../src/__tests__/EnsembleApp.test.tsx | 30 +--- packages/runtime/src/registry.tsx | 6 +- packages/runtime/src/runtime/menu.tsx | 2 +- packages/runtime/src/widgets/Icon.tsx | 7 +- pnpm-lock.yaml | 135 +++++++++++------- 13 files changed, 120 insertions(+), 136 deletions(-) diff --git a/apps/kitchen-sink/package.json b/apps/kitchen-sink/package.json index b5a187bc6..a63be27b2 100644 --- a/apps/kitchen-sink/package.json +++ b/apps/kitchen-sink/package.json @@ -23,6 +23,7 @@ "https-browserify": "^1.0.0", "node-polyfill-webpack-plugin": "^2.0.1", "path-browserify": "^1.0.1", + "react-feather": "^2.0.10", "react-scripts": "5.0.1", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", diff --git a/apps/kitchen-sink/src/App.tsx b/apps/kitchen-sink/src/App.tsx index c2b515c98..cd6a7c107 100644 --- a/apps/kitchen-sink/src/App.tsx +++ b/apps/kitchen-sink/src/App.tsx @@ -1,6 +1,6 @@ import type { ApplicationDTO } from "@ensembleui/react-framework"; import { EnsembleApp } from "@ensembleui/react-runtime"; -import * as Icons from "@mui/icons-material"; +import * as Icons from "react-feather"; // Screens import React from "react"; import MenuYAML from "./ensemble/screens/menu.yaml"; @@ -144,14 +144,13 @@ const testApp: ApplicationDTO = { content: String(TestActionsYAML), }, ], - icons: { - mui: { icons: Icons as { [key: string]: React.ComponentType } }, - custom: { - prefix: "Mui", - icons: Icons as { [key: string]: React.ComponentType }, - }, - }, config: EnsembleConfig, + icons: [ + { + icons: Icons, + prefix: "Fe", + }, + ], }; const App: React.FC = () => { diff --git a/apps/kitchen-sink/src/ensemble/screens/menu.yaml b/apps/kitchen-sink/src/ensemble/screens/menu.yaml index 1bdc42e50..e61c3f75a 100644 --- a/apps/kitchen-sink/src/ensemble/screens/menu.yaml +++ b/apps/kitchen-sink/src/ensemble/screens/menu.yaml @@ -30,7 +30,7 @@ ViewGroup: source: /logo.svg items: - label: Home - icon: HomeOutlined + icon: FeHome page: home selected: true - label: Widgets diff --git a/apps/preview/src/AppPreview.tsx b/apps/preview/src/AppPreview.tsx index 6018e6663..f50dd9b56 100644 --- a/apps/preview/src/AppPreview.tsx +++ b/apps/preview/src/AppPreview.tsx @@ -3,7 +3,6 @@ import type { ApplicationLoader, EnsembleDocument, } from "@ensembleui/react-framework"; -import * as Icons from "@mui/icons-material"; import { getFirestoreApplicationLoader } from "@ensembleui/react-framework"; import { EnsembleApp } from "@ensembleui/react-runtime"; import { Alert } from "antd"; @@ -33,13 +32,6 @@ const customPreviewWidgetApp: ApplicationDTO = { scripts: [], id: "customWidgetPreview", name: "customWidgetPreview", - icons: { - mui: { icons: Icons as { [key: string]: React.ComponentType } }, - custom: { - prefix: "Mui", - icons: Icons as { [key: string]: React.ComponentType }, - }, - }, }; const createCustomWidgetPreviewApp = ( diff --git a/apps/starter/src/ensemble/index.ts b/apps/starter/src/ensemble/index.ts index 0066976a5..e14b0f110 100644 --- a/apps/starter/src/ensemble/index.ts +++ b/apps/starter/src/ensemble/index.ts @@ -1,5 +1,4 @@ import { type ApplicationDTO } from "@ensembleui/react-framework"; -import * as Icons from "@mui/icons-material"; // Screens import MenuYAML from "./screens/menu.yaml"; import HomeYAML from "./screens/home.yaml"; @@ -56,11 +55,4 @@ export const starterApp: ApplicationDTO = { content: String(HelpYAML), }, ], - icons: { - mui: { icons: Icons as { [key: string]: React.ComponentType } }, - custom: { - prefix: "Mui", - icons: Icons as { [key: string]: React.ComponentType }, - }, - }, }; diff --git a/packages/framework/src/shared/dto.ts b/packages/framework/src/shared/dto.ts index d93b17674..8e294baf8 100644 --- a/packages/framework/src/shared/dto.ts +++ b/packages/framework/src/shared/dto.ts @@ -23,7 +23,7 @@ export interface ApplicationDTO extends Omit { readonly languages?: LanguageDTO[]; readonly config?: string | EnsembleConfigYAML; readonly fonts?: FontDTO[]; - readonly icons: IconDTO; + readonly icons?: IconDTO[]; readonly description?: string; readonly isPublic?: boolean; readonly isAutoGenerated?: boolean; @@ -64,12 +64,7 @@ export interface FontDTO { readonly fontStyle: string; } -export interface IconSet { +export interface IconDTO { readonly prefix?: string; readonly icons?: { [key: string]: unknown }; } - -export interface IconDTO { - readonly mui: IconSet; - readonly custom?: IconSet; -} diff --git a/packages/runtime/package.json b/packages/runtime/package.json index b1ce9999b..1aaebc28f 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -18,6 +18,7 @@ }, "peerDependencies": { "@ensembleui/react-framework": "*", + "@mui/icons-material": "^6.4.1", "react": "^18.2.0", "react-dom": "^18.2.0" }, @@ -27,6 +28,7 @@ "@emotion/styled": "^11.11.0", "@ensembleui/react-framework": "workspace:*", "@lottiefiles/react-lottie-player": "^3.5.3", + "@mui/icons-material": "^6.4.1", "@mui/material": "^5.14.9", "@mui/x-date-pickers": "^6.18.3", "@react-oauth/google": "^0.12.1", diff --git a/packages/runtime/src/EnsembleApp.tsx b/packages/runtime/src/EnsembleApp.tsx index 1ec39351e..4b4cd7387 100644 --- a/packages/runtime/src/EnsembleApp.tsx +++ b/packages/runtime/src/EnsembleApp.tsx @@ -3,7 +3,7 @@ import type { ApplicationDTO, EnsembleAppModel, ApplicationLoader, - IconSet, + IconDTO, } from "@ensembleui/react-framework"; import { ApplicationContextProvider, @@ -14,12 +14,14 @@ import { createBrowserRouter, RouterProvider } from "react-router-dom"; import { ToastContainer } from "react-toastify"; import { injectStyle } from "react-toastify/dist/inject-style"; import { QueryClientProvider } from "@tanstack/react-query"; +import * as Icons from "@mui/icons-material"; import { ThemeProvider } from "./ThemeProvider"; import { EnsembleEntry } from "./runtime/entry"; import { EnsembleScreen } from "./runtime/screen"; import { ErrorPage } from "./runtime/error"; // Register built in widgets; import "./widgets"; +import type { WidgetComponent } from "./registry"; import { IconRegistry, WidgetRegistry } from "./registry"; import { createCustomWidget } from "./runtime/customWidget"; import { ModalWrapper } from "./runtime/modal"; @@ -50,16 +52,6 @@ export const EnsembleApp: React.FC = ({ return; } - const registerIcons = (iconSet?: IconSet): void => { - const { prefix = "", icons = {} } = (iconSet || {}) as { - prefix?: string; - icons?: { [key: string]: React.ComponentType }; - }; - Object.entries(icons).forEach(([name, icon]) => { - IconRegistry.register(`${prefix}${name}`, icon); - }); - }; - const parseApp = (appDto: ApplicationDTO): void => { const parsedApp = EnsembleParser.parseApplication(appDto); parsedApp.customWidgets.forEach((customWidget) => { @@ -69,12 +61,19 @@ export const EnsembleApp: React.FC = ({ ); }); - if (!appDto.icons?.mui) { - throw new Error("An mui icons must be provided"); - } + Object.entries(Icons).forEach(([name, icon]) => { + IconRegistry.register(name, icon as WidgetComponent); + }); - registerIcons(appDto.icons.mui); - registerIcons(appDto.icons?.custom); + appDto?.icons?.forEach((iconSet: IconDTO) => { + const { prefix = "", icons = {} } = iconSet; + Object.entries(icons).forEach(([name, icon]) => { + IconRegistry.register( + `${prefix}${name}`, + icon as WidgetComponent, + ); + }); + }); setApp(parsedApp); }; diff --git a/packages/runtime/src/__tests__/EnsembleApp.test.tsx b/packages/runtime/src/__tests__/EnsembleApp.test.tsx index 41f081883..05ca521f6 100644 --- a/packages/runtime/src/__tests__/EnsembleApp.test.tsx +++ b/packages/runtime/src/__tests__/EnsembleApp.test.tsx @@ -57,12 +57,7 @@ test("Renders error page", () => { themes: {}, }); try { - render( - , - ); + render(); } catch (e) { // no-op } @@ -103,7 +98,6 @@ test("Renders view widget of home screen", () => { application={ { screens: [{ content: "" }], - icons: { mui: {} }, } as ApplicationDTO } />, @@ -149,7 +143,6 @@ test("Bind data from other widgets", async () => { application={ { screens: [{ content: "" }], - icons: { mui: {} }, } as ApplicationDTO } />, @@ -199,7 +192,6 @@ test("Updates values through Ensemble state", async () => { application={ { screens: [{ content: "" }], - icons: { mui: {} }, } as ApplicationDTO } />, @@ -214,23 +206,3 @@ test("Updates values through Ensemble state", async () => { const updatedText = await screen.findByText("Spiderman"); expect(updatedText).not.toBeNull(); }); - -test("Renders mui icon error", () => { - const logSpy = jest.spyOn(console, "error").mockImplementation(jest.fn()); - - parseApplicationMock.mockReturnValue({ - home: {}, - screens: [], - customWidgets: [], - themes: {}, - }); - try { - render(); - } catch (e) { - // no-op - } - - expect(logSpy.mock.calls.toString()).toContain( - "An mui icons must be provided", - ); -}); diff --git a/packages/runtime/src/registry.tsx b/packages/runtime/src/registry.tsx index a9a23352f..70375082d 100644 --- a/packages/runtime/src/registry.tsx +++ b/packages/runtime/src/registry.tsx @@ -35,7 +35,7 @@ export const IconRegistry = { find: (name: string): WidgetComponent | ReactElement => { const Icon = iconRegistry[name]; if (!Icon) { - return UnknownIcon; + return ; } return Icon; }, @@ -51,6 +51,6 @@ const UnknownWidget: React.FC<{ missingName: string }> = ({ missingName }) => { return ; }; -const UnknownIcon: React.FC<{ name: string }> = ({ name }) => { - return ; +const UnknownIcon: React.FC<{ missingName: string }> = ({ missingName }) => { + return ; }; diff --git a/packages/runtime/src/runtime/menu.tsx b/packages/runtime/src/runtime/menu.tsx index c4122b173..475622ead 100644 --- a/packages/runtime/src/runtime/menu.tsx +++ b/packages/runtime/src/runtime/menu.tsx @@ -401,7 +401,7 @@ const MenuItems: React.FC<{ {items.map((item, itemIndex) => ( {getCustomIcon(item)}} key={item.page || item.url || `customItem${itemIndex}`} onClick={(): void => { if (!item.openNewTab && item.page) { diff --git a/packages/runtime/src/widgets/Icon.tsx b/packages/runtime/src/widgets/Icon.tsx index c2b78f4c1..732aa9c1c 100644 --- a/packages/runtime/src/widgets/Icon.tsx +++ b/packages/runtime/src/widgets/Icon.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { isValidElement, useState } from "react"; import { useRegisterBindings } from "@ensembleui/react-framework"; import { WidgetRegistry } from "../registry"; import type { IconProps } from "../shared/types"; @@ -36,6 +36,9 @@ export const Icon: React.FC = ({ if (!IconComponent) { return null; } + if (isValidElement(IconComponent)) { + return IconComponent; + } const handleMouseOver = (event: React.MouseEvent): void => { const { clientX, clientY } = event; if (!isMouseOver) { @@ -56,7 +59,7 @@ export const Icon: React.FC = ({ onClick={(): unknown => onTapActionCallback?.callback()} onMouseEnter={handleMouseOver} onMouseLeave={handleMouseLeave} - sx={{ + style={{ cursor: onTap ? "pointer" : "auto", ...values?.styles, color: values?.color && getColor(String(values.color)), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f6bd12aa5..acee412a7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,6 +48,7 @@ importers: path-browserify: ^1.0.1 react: ^18.2.0 react-dom: ^18.2.0 + react-feather: ^2.0.10 react-scripts: 5.0.1 stream-browserify: ^3.0.0 stream-http: ^3.2.0 @@ -76,6 +77,7 @@ importers: https-browserify: 1.0.0 node-polyfill-webpack-plugin: 2.0.1 path-browserify: 1.0.1 + react-feather: 2.0.10_react@18.2.0 react-scripts: 5.0.1_d0d00780f67467135f0be55299847f4a stream-browserify: 3.0.0 stream-http: 3.2.0 @@ -342,6 +344,7 @@ importers: '@emotion/styled': ^11.11.0 '@ensembleui/react-framework': workspace:* '@lottiefiles/react-lottie-player': ^3.5.3 + '@mui/icons-material': ^6.4.1 '@mui/material': ^5.14.9 '@mui/x-date-pickers': ^6.18.3 '@react-oauth/google': ^0.12.1 @@ -379,6 +382,7 @@ importers: '@emotion/styled': 11.11.0_dd4092d1e0c7dc2863a676e563fa1e79 '@ensembleui/react-framework': link:../framework '@lottiefiles/react-lottie-player': 3.5.3 + '@mui/icons-material': 6.4.1_da55fe8c6e6066fef4b7dc0994910613 '@mui/material': 5.15.11_d729d530559e435818d6dfbb9bc0bc34 '@mui/x-date-pickers': 6.19.6_1dcf445c77f90e2d41581270c9a3b06f '@react-oauth/google': 0.12.1 @@ -450,7 +454,7 @@ packages: react-dom: '>=16.9.0' dependencies: '@ant-design/cssinjs': 1.21.0 - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 rc-util: 5.43.0 dev: true @@ -473,7 +477,7 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@emotion/hash': 0.8.0 '@emotion/unitless': 0.7.5 classnames: 2.5.1 @@ -543,7 +547,7 @@ packages: peerDependencies: react: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 json2mq: 0.2.0 resize-observer-polyfill: 1.5.1 @@ -3075,7 +3079,7 @@ packages: resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} dependencies: '@babel/helper-module-imports': 7.22.15 - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@emotion/hash': 0.9.1 '@emotion/memoize': 0.8.1 '@emotion/serialize': 1.1.3 @@ -4529,7 +4533,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@floating-ui/react-dom': 2.0.8 '@mui/types': 7.2.13_@types+react@18.2.62 '@mui/utils': 5.15.11_@types+react@18.2.62 @@ -4543,6 +4547,22 @@ packages: resolution: {integrity: sha512-JVrJ9Jo4gyU707ujnRzmE8ABBWpXd6FwL9GYULmwZRtfPg89ggXs/S3MStQkpJ1JRWfdLL6S5syXmgQGq5EDAw==} dev: true + /@mui/icons-material/6.4.1_da55fe8c6e6066fef4b7dc0994910613: + resolution: {integrity: sha512-wsxFcUTQxt4s+7Bg4GgobqRjyaHLmZGNOs+HJpbwrwmLbT6mhIJxhpqsKzzWq9aDY8xIe7HCjhpH7XI5UD6teA==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@mui/material': ^6.4.1 + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.26.0 + '@mui/material': 5.15.11_d729d530559e435818d6dfbb9bc0bc34 + '@types/react': 18.2.62 + dev: true + /@mui/icons-material/6.4.1_fb28c32afc3535fd55e20f7883f1b980: resolution: {integrity: sha512-wsxFcUTQxt4s+7Bg4GgobqRjyaHLmZGNOs+HJpbwrwmLbT6mhIJxhpqsKzzWq9aDY8xIe7HCjhpH7XI5UD6teA==} engines: {node: '>=14.0.0'} @@ -4603,7 +4623,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@mui/utils': 5.15.11_@types+react@18.2.62 '@types/react': 18.2.62 prop-types: 15.8.1 @@ -4622,7 +4642,7 @@ packages: '@emotion/styled': optional: true dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@emotion/cache': 11.11.0 '@emotion/react': 11.11.4_@types+react@18.2.62 '@emotion/styled': 11.11.0_dd4092d1e0c7dc2863a676e563fa1e79 @@ -4646,7 +4666,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@emotion/react': 11.11.4_@types+react@18.2.62 '@emotion/styled': 11.11.0_dd4092d1e0c7dc2863a676e563fa1e79 '@mui/private-theming': 5.15.11_@types+react@18.2.62 @@ -4680,7 +4700,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@types/prop-types': 15.7.11 '@types/react': 18.2.62 prop-types: 15.8.1 @@ -4982,7 +5002,7 @@ packages: react-dom: '>=16.9.0' dependencies: '@ant-design/fast-color': 2.0.6 - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -5007,7 +5027,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 rc-util: 5.43.0 dev: true @@ -5036,7 +5056,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -5062,7 +5082,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -5088,7 +5108,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -5114,7 +5134,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/portal': 1.1.2 '@rc-component/trigger': 2.2.0 classnames: 2.5.1 @@ -5144,7 +5164,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/portal': 1.1.2 classnames: 2.5.1 rc-motion: 2.9.2 @@ -9454,7 +9474,7 @@ packages: /dom-helpers/5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 csstype: 3.1.3 dev: true @@ -16050,7 +16070,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 array-tree-filter: 2.1.0 classnames: 2.5.1 rc-select: 14.15.1 @@ -16080,7 +16100,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -16104,7 +16124,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-motion: 2.9.2 rc-util: 5.43.0 @@ -16130,7 +16150,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/portal': 1.1.2 classnames: 2.5.1 rc-motion: 2.9.2 @@ -16158,7 +16178,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/portal': 1.1.2 classnames: 2.5.1 rc-motion: 2.9.2 @@ -16186,7 +16206,7 @@ packages: react: '>=16.11.0' react-dom: '>=16.11.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/trigger': 2.2.0 classnames: 2.5.1 rc-util: 5.43.0 @@ -16213,7 +16233,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/async-validator': 5.0.4 rc-util: 5.43.0 dev: true @@ -16238,7 +16258,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/portal': 1.1.2 classnames: 2.5.1 rc-dialog: 9.5.2 @@ -16268,7 +16288,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/mini-decimal': 1.1.0 classnames: 2.5.1 rc-input: 1.6.2 @@ -16296,7 +16316,7 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -16320,7 +16340,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/trigger': 2.2.0 classnames: 2.5.1 rc-input: 1.6.2 @@ -16352,7 +16372,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/trigger': 2.2.0 classnames: 2.5.1 rc-motion: 2.9.2 @@ -16382,7 +16402,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -16407,7 +16427,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-motion: 2.9.2 rc-util: 5.43.0 @@ -16434,7 +16454,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-resize-observer: 1.4.0 rc-util: 5.43.0 @@ -16460,7 +16480,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -16529,7 +16549,7 @@ packages: moment: optional: true dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/trigger': 2.2.0 classnames: 2.5.1 dayjs: 1.11.12 @@ -16544,7 +16564,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -16569,7 +16589,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -16594,7 +16614,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 resize-observer-polyfill: 1.5.1 @@ -16620,7 +16640,7 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-motion: 2.9.2 rc-util: 5.43.0 @@ -16647,7 +16667,7 @@ packages: react: '*' react-dom: '*' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/trigger': 2.2.0 classnames: 2.5.1 rc-motion: 2.9.2 @@ -16681,7 +16701,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -16707,7 +16727,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -16732,7 +16752,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -16757,7 +16777,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/context': 1.4.0 classnames: 2.5.1 rc-resize-observer: 1.4.0 @@ -16789,7 +16809,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-dropdown: 4.2.0 rc-menu: 9.14.1 @@ -16822,7 +16842,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-input: 1.6.2 rc-resize-observer: 1.4.0 @@ -16850,7 +16870,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 '@rc-component/trigger': 2.2.0 classnames: 2.5.1 dev: true @@ -16874,7 +16894,7 @@ packages: react: '*' react-dom: '*' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-select: 14.15.1 rc-tree: 5.8.8 @@ -16903,7 +16923,7 @@ packages: react: '*' react-dom: '*' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-motion: 2.9.2 rc-util: 5.43.0 @@ -16932,7 +16952,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-util: 5.43.0 dev: true @@ -16956,7 +16976,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 react-is: 18.2.0 dev: true @@ -16979,7 +16999,7 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 classnames: 2.5.1 rc-resize-observer: 1.4.0 rc-util: 5.43.0 @@ -17104,6 +17124,15 @@ packages: resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} dev: true + /react-feather/2.0.10_react@18.2.0: + resolution: {integrity: sha512-BLhukwJ+Z92Nmdcs+EMw6dy1Z/VLiJTzEQACDUEnWMClhYnFykJCGWQx+NmwP/qQHGX/5CzQ+TGi8ofg2+HzVQ==} + peerDependencies: + react: '>=16.8.6' + dependencies: + prop-types: 15.8.1 + react: 18.2.0 + dev: true + /react-i18next/14.1.2_i18next@23.11.5: resolution: {integrity: sha512-FSIcJy6oauJbGEXfhUgVeLzvWBhIBIS+/9c6Lj4niwKZyGaGb4V4vUbATXSlsHJDXXB+ociNxqFNiFuV1gmoqg==} peerDependencies: @@ -17328,7 +17357,7 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 @@ -17786,7 +17815,7 @@ packages: /rtl-css-js/1.16.1: resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==} dependencies: - '@babel/runtime': 7.25.0 + '@babel/runtime': 7.26.0 dev: true /run-async/2.4.1: From 8e416793bfd36e64e2a9e09a8f6e22dd8b1540f5 Mon Sep 17 00:00:00 2001 From: sagar davara Date: Fri, 31 Jan 2025 21:19:04 +0530 Subject: [PATCH 5/8] fix: remove span from icon in menu --- packages/runtime/src/runtime/menu.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/runtime/src/runtime/menu.tsx b/packages/runtime/src/runtime/menu.tsx index 475622ead..36b2b0006 100644 --- a/packages/runtime/src/runtime/menu.tsx +++ b/packages/runtime/src/runtime/menu.tsx @@ -401,7 +401,7 @@ const MenuItems: React.FC<{ {items.map((item, itemIndex) => ( {getCustomIcon(item)}} + icon={getCustomIcon(item)} key={item.page || item.url || `customItem${itemIndex}`} onClick={(): void => { if (!item.openNewTab && item.page) { @@ -409,6 +409,7 @@ const MenuItems: React.FC<{ } }} style={{ + gap: "10px", color: selectedItem === item.page ? (styles.selectedColor as string) ?? "white" From f6b26754ead8de3bf77869b7bf8361b29e81fe57 Mon Sep 17 00:00:00 2001 From: sagar davara Date: Mon, 3 Feb 2025 18:28:36 +0530 Subject: [PATCH 6/8] fix: wrap icon component --- packages/runtime/src/widgets/Icon.tsx | 66 +++++++++++++-------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/packages/runtime/src/widgets/Icon.tsx b/packages/runtime/src/widgets/Icon.tsx index 732aa9c1c..fdcbb1224 100644 --- a/packages/runtime/src/widgets/Icon.tsx +++ b/packages/runtime/src/widgets/Icon.tsx @@ -36,9 +36,6 @@ export const Icon: React.FC = ({ if (!IconComponent) { return null; } - if (isValidElement(IconComponent)) { - return IconComponent; - } const handleMouseOver = (event: React.MouseEvent): void => { const { clientX, clientY } = event; if (!isMouseOver) { @@ -53,36 +50,39 @@ export const Icon: React.FC = ({ onMouseLeaveAction?.callback(); setIsMouseOver(false); }; - return ( - onTapActionCallback?.callback()} - onMouseEnter={handleMouseOver} - onMouseLeave={handleMouseLeave} - style={{ - cursor: onTap ? "pointer" : "auto", - ...values?.styles, - color: values?.color && getColor(String(values.color)), - fontSize: props.size, - backgroundColor: `${ - values?.styles?.backgroundColor - ? values.styles.backgroundColor - : "transparent" - }`, - padding: evaluateStyleValue(values?.styles?.padding), - margin: evaluateStyleValue(values?.styles?.margin), - borderRadius: evaluateStyleValue(values?.styles?.borderRadius), - borderWidth: evaluateStyleValue(values?.styles?.borderWidth), - borderColor: values?.styles?.borderColor - ? getColor(String(values.styles.borderColor)) - : undefined, - borderStyle: values?.styles?.borderWidth ? "solid" : undefined, - ...(values?.styles?.visible === false - ? { display: "none" } - : undefined), - }} - /> - ); + + const iconProps = { + className: values?.styles?.names, + onClick: (): unknown => onTapActionCallback?.callback(), + onMouseEnter: handleMouseOver, + onMouseLeave: handleMouseLeave, + style: { + cursor: onTap ? "pointer" : "auto", + ...values?.styles, + color: values?.color && getColor(String(values.color)), + fontSize: props.size, + backgroundColor: `${ + values?.styles?.backgroundColor + ? values.styles.backgroundColor + : "transparent" + }`, + padding: evaluateStyleValue(values?.styles?.padding), + margin: evaluateStyleValue(values?.styles?.margin), + borderRadius: evaluateStyleValue(values?.styles?.borderRadius), + borderWidth: evaluateStyleValue(values?.styles?.borderWidth), + borderColor: values?.styles?.borderColor + ? getColor(String(values.styles.borderColor)) + : undefined, + borderStyle: values?.styles?.borderWidth ? "solid" : undefined, + ...(values?.styles?.visible === false ? { display: "none" } : undefined), + }, + }; + + if (isValidElement(IconComponent)) { + return React.cloneElement(IconComponent, { ...iconProps }); + } + + return ; }; WidgetRegistry.register(widgetName, Icon); From 78233990cc947c12c4fd23a5c3eda97174c52d19 Mon Sep 17 00:00:00 2001 From: sagar davara Date: Tue, 4 Feb 2025 19:07:20 +0530 Subject: [PATCH 7/8] fix: added normalizeIconProp util --- packages/runtime/src/runtime/menu.tsx | 12 +++++------- packages/runtime/src/shared/utils.ts | 13 +++++++++++++ packages/runtime/src/widgets/Avatar/Avatar.tsx | 7 +++---- 3 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 packages/runtime/src/shared/utils.ts diff --git a/packages/runtime/src/runtime/menu.tsx b/packages/runtime/src/runtime/menu.tsx index 36b2b0006..a981dc090 100644 --- a/packages/runtime/src/runtime/menu.tsx +++ b/packages/runtime/src/runtime/menu.tsx @@ -14,9 +14,10 @@ import { EnsembleMenuModelType, } from "@ensembleui/react-framework"; import { Outlet, Link, useLocation } from "react-router-dom"; -import { cloneDeep, isString, omit } from "lodash-es"; +import { cloneDeep, omit } from "lodash-es"; import { getColor } from "../shared/styles"; import type { IconProps } from "../shared/types"; +import { normalizeIconProps } from "../shared/utils"; import { EnsembleRuntime } from "./runtime"; // eslint-disable-next-line import/no-cycle import { useEnsembleAction } from "./hooks"; @@ -347,12 +348,9 @@ const MenuItems: React.FC<{ return null; } - const icon = isString(iconProps) - ? { - name: iconProps, - styles: { width: styles.iconWidth, height: styles.iconHeight }, - } - : iconProps; + const icon = normalizeIconProps(iconProps, { + styles: { width: styles.iconWidth, height: styles.iconHeight }, + }); return EnsembleRuntime.render([{ ...unwrapWidget({ Icon: icon }), key }]); }, diff --git a/packages/runtime/src/shared/utils.ts b/packages/runtime/src/shared/utils.ts new file mode 100644 index 000000000..4e65c577f --- /dev/null +++ b/packages/runtime/src/shared/utils.ts @@ -0,0 +1,13 @@ +import { isString } from "lodash-es"; +import { IconProps } from "./types"; + +export const normalizeIconProps = ( + iconProps?: string | IconProps, + additionalProps?: { [key: string]: unknown }, +): IconProps | undefined => { + const props = isString(iconProps) + ? { name: iconProps, ...(additionalProps || {}) } + : iconProps; + + return props; +}; diff --git a/packages/runtime/src/widgets/Avatar/Avatar.tsx b/packages/runtime/src/widgets/Avatar/Avatar.tsx index 6d73d7636..867d842fc 100644 --- a/packages/runtime/src/widgets/Avatar/Avatar.tsx +++ b/packages/runtime/src/widgets/Avatar/Avatar.tsx @@ -7,9 +7,9 @@ import { MenuItem, ListItemIcon, } from "@mui/material"; -import { isString } from "lodash-es"; import { WidgetRegistry } from "../../registry"; import type { EnsembleWidgetStyles, IconProps } from "../../shared/types"; +import { normalizeIconProps } from "../../shared/utils"; // eslint-disable-next-line import/no-cycle import { Icon } from "../Icon"; import { useEnsembleAction } from "../../runtime/hooks/useEnsembleAction"; @@ -111,9 +111,8 @@ export const Avatar: React.FC = (props) => { open={isMenuOpen} > {values?.menu.map((menuItem, idx) => { - const icon = isString(menuItem.icon) - ? { name: menuItem.icon } - : menuItem.icon; + const icon = normalizeIconProps(menuItem.icon); + return ( Date: Fri, 7 Feb 2025 18:26:31 +0530 Subject: [PATCH 8/8] fix: revert props --- packages/runtime/src/widgets/Icon.tsx | 60 ++++++++++++++------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/packages/runtime/src/widgets/Icon.tsx b/packages/runtime/src/widgets/Icon.tsx index fdcbb1224..7ec9e570f 100644 --- a/packages/runtime/src/widgets/Icon.tsx +++ b/packages/runtime/src/widgets/Icon.tsx @@ -51,38 +51,40 @@ export const Icon: React.FC = ({ setIsMouseOver(false); }; - const iconProps = { - className: values?.styles?.names, - onClick: (): unknown => onTapActionCallback?.callback(), - onMouseEnter: handleMouseOver, - onMouseLeave: handleMouseLeave, - style: { - cursor: onTap ? "pointer" : "auto", - ...values?.styles, - color: values?.color && getColor(String(values.color)), - fontSize: props.size, - backgroundColor: `${ - values?.styles?.backgroundColor - ? values.styles.backgroundColor - : "transparent" - }`, - padding: evaluateStyleValue(values?.styles?.padding), - margin: evaluateStyleValue(values?.styles?.margin), - borderRadius: evaluateStyleValue(values?.styles?.borderRadius), - borderWidth: evaluateStyleValue(values?.styles?.borderWidth), - borderColor: values?.styles?.borderColor - ? getColor(String(values.styles.borderColor)) - : undefined, - borderStyle: values?.styles?.borderWidth ? "solid" : undefined, - ...(values?.styles?.visible === false ? { display: "none" } : undefined), - }, - }; - if (isValidElement(IconComponent)) { - return React.cloneElement(IconComponent, { ...iconProps }); + return IconComponent; } - return ; + return ( + onTapActionCallback?.callback()} + onMouseEnter={handleMouseOver} + onMouseLeave={handleMouseLeave} + style={{ + cursor: onTap ? "pointer" : "auto", + ...values?.styles, + color: values?.color && getColor(String(values.color)), + fontSize: props.size, + backgroundColor: `${ + values?.styles?.backgroundColor + ? values.styles.backgroundColor + : "transparent" + }`, + padding: evaluateStyleValue(values?.styles?.padding), + margin: evaluateStyleValue(values?.styles?.margin), + borderRadius: evaluateStyleValue(values?.styles?.borderRadius), + borderWidth: evaluateStyleValue(values?.styles?.borderWidth), + borderColor: values?.styles?.borderColor + ? getColor(String(values.styles.borderColor)) + : undefined, + borderStyle: values?.styles?.borderWidth ? "solid" : undefined, + ...(values?.styles?.visible === false + ? { display: "none" } + : undefined), + }} + /> + ); }; WidgetRegistry.register(widgetName, Icon);