diff --git a/packages/fuselage-ui-kit/.eslintrc.json b/packages/fuselage-ui-kit/.eslintrc.json index ea14af17f859d..d5db8560f3e86 100644 --- a/packages/fuselage-ui-kit/.eslintrc.json +++ b/packages/fuselage-ui-kit/.eslintrc.json @@ -1,3 +1,65 @@ { - "extends": ["@rocket.chat/eslint-config", "@rocket.chat/eslint-config/react"] + "extends": [ + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/eslint-recommended", + "@rocket.chat/eslint-config/original", + "@rocket.chat/eslint-config/react", + "prettier", + "plugin:anti-trojan-source/recommended", + "plugin:react/jsx-runtime", + "plugin:storybook/recommended" + ], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint", "prettier"], + "rules": { + "func-call-spacing": "off", + "import/named": "error", + "import/order": [ + "error", + { + "newlines-between": "always", + "groups": ["builtin", "external", "internal", ["parent", "sibling", "index"]], + "alphabetize": { + "order": "asc" + } + } + ], + "indent": "off", + "jsx-quotes": ["error", "prefer-single"], + "new-cap": ["error"], + "no-extra-parens": "off", + "no-spaced-func": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-useless-constructor": "off", + "no-use-before-define": "off", + "prefer-arrow-callback": ["error", { "allowNamedFunctions": true }], + "prettier/prettier": 2 + }, + "settings": { + "import/resolver": { + "node": { + "extensions": [".js", ".ts", ".tsx"] + } + } + }, + "ignorePatterns": ["**/dist"], + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "@typescript-eslint/ban-ts-ignore": "off", + "@typescript-eslint/indent": "off", + "@typescript-eslint/no-extra-parens": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_" + } + ], + "@typescript-eslint/prefer-optional-chain": "warn" + } + } + ] } diff --git a/packages/fuselage-ui-kit/.prettierrc.js b/packages/fuselage-ui-kit/.prettierrc.js deleted file mode 100644 index b57f474edb93a..0000000000000 --- a/packages/fuselage-ui-kit/.prettierrc.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('@rocket.chat/prettier-config/fuselage'); diff --git a/packages/fuselage-ui-kit/.storybook/DocsContainer.tsx b/packages/fuselage-ui-kit/.storybook/DocsContainer.tsx index fa750d0d0d04e..217b6b05910d1 100644 --- a/packages/fuselage-ui-kit/.storybook/DocsContainer.tsx +++ b/packages/fuselage-ui-kit/.storybook/DocsContainer.tsx @@ -7,19 +7,15 @@ import { DARK_MODE_EVENT_NAME } from 'storybook-dark-mode'; const channel = addons.getChannel(); -const DocsContainer = ( - props: ComponentPropsWithoutRef, -) => { - const [isDark, setDark] = useState(false); +const DocsContainer = (props: ComponentPropsWithoutRef) => { + const [isDark, setDark] = useState(false); - useEffect(() => { - channel.on(DARK_MODE_EVENT_NAME, setDark); - return () => channel.removeListener(DARK_MODE_EVENT_NAME, setDark); - }, [setDark]); + useEffect(() => { + channel.on(DARK_MODE_EVENT_NAME, setDark); + return () => channel.removeListener(DARK_MODE_EVENT_NAME, setDark); + }, [setDark]); - return ( - - ); + return ; }; export default DocsContainer; diff --git a/packages/fuselage-ui-kit/.storybook/helpers.ts b/packages/fuselage-ui-kit/.storybook/helpers.ts index aee5f8ad0969a..748b7609c0ca6 100644 --- a/packages/fuselage-ui-kit/.storybook/helpers.ts +++ b/packages/fuselage-ui-kit/.storybook/helpers.ts @@ -1,4 +1,4 @@ export const surface = { - sidebar: '#2F343D', - main: '#262931', + sidebar: '#2F343D', + main: '#262931', }; diff --git a/packages/fuselage-ui-kit/.storybook/main.ts b/packages/fuselage-ui-kit/.storybook/main.ts index 5bfe48ebf7302..b3247a95502b7 100644 --- a/packages/fuselage-ui-kit/.storybook/main.ts +++ b/packages/fuselage-ui-kit/.storybook/main.ts @@ -3,27 +3,27 @@ import { dirname, join } from 'path'; import type { StorybookConfig } from '@storybook/react-webpack5'; export default { - stories: ['../src/**/*.stories.tsx', '../src/**/stories.tsx'], + stories: ['../src/**/*.stories.tsx', '../src/**/stories.tsx'], - addons: [ - getAbsolutePath('@storybook/addon-essentials'), - getAbsolutePath('storybook-dark-mode'), - './webpackAddon', - getAbsolutePath('@storybook/addon-styling-webpack'), - ], + addons: [ + getAbsolutePath('@storybook/addon-essentials'), + getAbsolutePath('storybook-dark-mode'), + './webpackAddon', + getAbsolutePath('@storybook/addon-styling-webpack'), + ], - framework: { - name: getAbsolutePath('@storybook/react-webpack5'), - options: {}, - }, + framework: { + name: getAbsolutePath('@storybook/react-webpack5'), + options: {}, + }, - typescript: { - reactDocgen: 'react-docgen', - }, + typescript: { + reactDocgen: 'react-docgen', + }, - docs: {}, + docs: {}, } satisfies StorybookConfig; function getAbsolutePath(value: string): any { - return dirname(require.resolve(join(value, 'package.json'))); + return dirname(require.resolve(join(value, 'package.json'))); } diff --git a/packages/fuselage-ui-kit/.storybook/preview.tsx b/packages/fuselage-ui-kit/.storybook/preview.tsx index 1fba8b68e34d7..d3080e682f608 100644 --- a/packages/fuselage-ui-kit/.storybook/preview.tsx +++ b/packages/fuselage-ui-kit/.storybook/preview.tsx @@ -14,55 +14,55 @@ import '@rocket.chat/icons/dist/rocketchat.css'; import 'normalize.css/normalize.css'; export const parameters: Parameters = { - backgrounds: { - grid: { - cellSize: 4, - cellAmount: 4, - opacity: 0.5, - }, - }, - options: { - storySort: { - method: 'alphabetical', - }, - }, - layout: 'fullscreen', - docs: { - container: DocsContainer, - }, - darkMode: { - dark: { - ...themes.dark, - appBg: surface.sidebar, - appContentBg: surface.main, - barBg: surface.main, - brandTitle: manifest.name, - brandImage: logo, - brandUrl: manifest.homepage, - }, - light: { - ...themes.normal, - brandTitle: manifest.name, - brandImage: logo, - brandUrl: manifest.homepage, - }, - }, + backgrounds: { + grid: { + cellSize: 4, + cellAmount: 4, + opacity: 0.5, + }, + }, + options: { + storySort: { + method: 'alphabetical', + }, + }, + layout: 'fullscreen', + docs: { + container: DocsContainer, + }, + darkMode: { + dark: { + ...themes.dark, + appBg: surface.sidebar, + appContentBg: surface.main, + barBg: surface.main, + brandTitle: manifest.name, + brandImage: logo, + brandUrl: manifest.homepage, + }, + light: { + ...themes.normal, + brandTitle: manifest.name, + brandImage: logo, + brandUrl: manifest.homepage, + }, + }, }; const queryClient = new QueryClient(); export const decorators: Decorator[] = [ - (fn) => { - const dark = useDarkMode(); + (fn) => { + const dark = useDarkMode(); - return ( - <> - - {fn()} - - ); - }, - (fn) => , + return ( + <> + + {fn()} + + ); + }, + (fn) => , ]; export const tags = ['autodocs']; diff --git a/packages/fuselage-ui-kit/jest.config.ts b/packages/fuselage-ui-kit/jest.config.ts index 4ce09e8344cda..45bc947f274c2 100644 --- a/packages/fuselage-ui-kit/jest.config.ts +++ b/packages/fuselage-ui-kit/jest.config.ts @@ -2,11 +2,11 @@ import client from '@rocket.chat/jest-presets/client'; import type { Config } from 'jest'; export default { - preset: client.preset, - setupFilesAfterEnv: [...client.setupFilesAfterEnv], - moduleNameMapper: { - '^react($|/.+)': '/../../node_modules/react$1', - '^react-dom($|/.+)': '/../../node_modules/react-dom$1', - '^react-i18next($|/.+)': '/../../node_modules/react-i18next$1', - }, + preset: client.preset, + setupFilesAfterEnv: [...client.setupFilesAfterEnv], + moduleNameMapper: { + '^react($|/.+)': '/../../node_modules/react$1', + '^react-dom($|/.+)': '/../../node_modules/react-dom$1', + '^react-i18next($|/.+)': '/../../node_modules/react-i18next$1', + }, } satisfies Config; diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 244a8e8452d28..42438861ea583 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -60,7 +60,6 @@ "@rocket.chat/icons": "^0.43.0", "@rocket.chat/jest-presets": "workspace:~", "@rocket.chat/mock-providers": "workspace:^", - "@rocket.chat/prettier-config": "~0.31.25", "@rocket.chat/styled": "~0.32.0", "@rocket.chat/tsconfig": "workspace:*", "@rocket.chat/ui-avatar": "workspace:^", @@ -105,7 +104,6 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/fuselage-polyfills": "*", "@rocket.chat/icons": "*", - "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", "@rocket.chat/ui-avatar": "workspace:^", "@rocket.chat/ui-contexts": "workspace:^", diff --git a/packages/fuselage-ui-kit/src/blocks/ActionsBlock.Action.tsx b/packages/fuselage-ui-kit/src/blocks/ActionsBlock.Action.tsx index e17d8899b0e16..b6ace8354d8f2 100644 --- a/packages/fuselage-ui-kit/src/blocks/ActionsBlock.Action.tsx +++ b/packages/fuselage-ui-kit/src/blocks/ActionsBlock.Action.tsx @@ -3,34 +3,28 @@ import * as UiKit from '@rocket.chat/ui-kit'; import type { ReactElement } from 'react'; type ActionProps = { - element: UiKit.ActionsBlock['elements'][number]; - parser: UiKit.SurfaceRenderer; - index: number; + element: UiKit.ActionsBlock['elements'][number]; + parser: UiKit.SurfaceRenderer; + index: number; }; -const Action = ({ - element, - parser, - index, -}: ActionProps): ReactElement | null => { - const renderedElement = parser.renderActionsBlockElement(element, index); +const Action = ({ element, parser, index }: ActionProps): ReactElement | null => { + const renderedElement = parser.renderActionsBlockElement(element, index); - if (!renderedElement) { - return null; - } + if (!renderedElement) { + return null; + } - return ( - - {renderedElement} - - ); + return ( + + {renderedElement} + + ); }; export default Action; diff --git a/packages/fuselage-ui-kit/src/blocks/ActionsBlock.tsx b/packages/fuselage-ui-kit/src/blocks/ActionsBlock.tsx index 5254e4751cb71..2126973be8c34 100644 --- a/packages/fuselage-ui-kit/src/blocks/ActionsBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/ActionsBlock.tsx @@ -9,51 +9,39 @@ import type { BlockProps } from '../utils/BlockProps'; type ActionsBlockProps = BlockProps; -const ActionsBlock = ({ - className, - block, - surfaceRenderer, -}: ActionsBlockProps): ReactElement => { - const surfaceType = useSurfaceType(); - - const [showMoreVisible, setShowMoreVisible] = useState( - () => block.elements.length > 5 && surfaceType !== 'banner', - ); - - const handleShowMoreClick = useCallback(() => { - setShowMoreVisible(false); - }, []); - - const actionElements = useMemo( - () => - (showMoreVisible ? block.elements.slice(0, 5) : block.elements).map( - (element) => ({ - ...element, - appId: element.appId ?? block.appId, - blockId: element.blockId ?? block.blockId, - }), - ), - [block.appId, block.blockId, block.elements, showMoreVisible], - ); - - return ( - - {actionElements.map((element, i) => ( - - ))} - {showMoreVisible && ( - - - - )} - - ); +const ActionsBlock = ({ className, block, surfaceRenderer }: ActionsBlockProps): ReactElement => { + const surfaceType = useSurfaceType(); + + const [showMoreVisible, setShowMoreVisible] = useState(() => block.elements.length > 5 && surfaceType !== 'banner'); + + const handleShowMoreClick = useCallback(() => { + setShowMoreVisible(false); + }, []); + + const actionElements = useMemo( + () => + (showMoreVisible ? block.elements.slice(0, 5) : block.elements).map((element) => ({ + ...element, + appId: element.appId ?? block.appId, + blockId: element.blockId ?? block.blockId, + })), + [block.appId, block.blockId, block.elements, showMoreVisible], + ); + + return ( + + {actionElements.map((element, i) => ( + + ))} + {showMoreVisible && ( + + + + )} + + ); }; export default memo(ActionsBlock); diff --git a/packages/fuselage-ui-kit/src/blocks/CalloutBlock.tsx b/packages/fuselage-ui-kit/src/blocks/CalloutBlock.tsx index 1a57fdbda8ce9..61c2d92eb0fdf 100644 --- a/packages/fuselage-ui-kit/src/blocks/CalloutBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/CalloutBlock.tsx @@ -6,26 +6,14 @@ import type { BlockProps } from '../utils/BlockProps'; type CalloutBlockProps = BlockProps; -const CalloutBlock = ({ - block, - surfaceRenderer, -}: CalloutBlockProps): ReactElement => { - return ( - - {surfaceRenderer.renderTextObject(block.text, 0, UiKit.BlockContext.NONE)} - - ); -}; +const CalloutBlock = ({ block, surfaceRenderer }: CalloutBlockProps): ReactElement => ( + + {surfaceRenderer.renderTextObject(block.text, 0, UiKit.BlockContext.NONE)} + +); export default CalloutBlock; diff --git a/packages/fuselage-ui-kit/src/blocks/ContextBlock.Item.tsx b/packages/fuselage-ui-kit/src/blocks/ContextBlock.Item.tsx index d0faaa940174a..3e5ca68b8e8a0 100644 --- a/packages/fuselage-ui-kit/src/blocks/ContextBlock.Item.tsx +++ b/packages/fuselage-ui-kit/src/blocks/ContextBlock.Item.tsx @@ -3,34 +3,30 @@ import * as UiKit from '@rocket.chat/ui-kit'; import type { ReactElement } from 'react'; type ItemProps = { - block: UiKit.ContextBlock['elements'][number]; - surfaceRenderer: UiKit.SurfaceRenderer; - index: number; + block: UiKit.ContextBlock['elements'][number]; + surfaceRenderer: UiKit.SurfaceRenderer; + index: number; }; -const Item = ({ - block: element, - surfaceRenderer: parser, - index, -}: ItemProps): ReactElement | null => { - const renderedElement = parser.renderContextBlockElement(element, index); +const Item = ({ block: element, surfaceRenderer: parser, index }: ItemProps): ReactElement | null => { + const renderedElement = parser.renderContextBlockElement(element, index); - if (!renderedElement) { - return null; - } + if (!renderedElement) { + return null; + } - switch (element.type) { - case UiKit.TextObjectType.PLAIN_TEXT: - case UiKit.TextObjectType.MARKDOWN: - return ( - - {renderedElement} - - ); + switch (element.type) { + case UiKit.TextObjectType.PLAIN_TEXT: + case UiKit.TextObjectType.MARKDOWN: + return ( + + {renderedElement} + + ); - default: - return renderedElement; - } + default: + return renderedElement; + } }; export default Item; diff --git a/packages/fuselage-ui-kit/src/blocks/ContextBlock.tsx b/packages/fuselage-ui-kit/src/blocks/ContextBlock.tsx index db40de7e3f6c3..16b96c7bc7427 100644 --- a/packages/fuselage-ui-kit/src/blocks/ContextBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/ContextBlock.tsx @@ -8,33 +8,24 @@ import type { BlockProps } from '../utils/BlockProps'; type ContextBlockProps = BlockProps; -const ContextBlock = ({ - className, - block, - surfaceRenderer, -}: ContextBlockProps): ReactElement => { - const itemElements = useMemo( - () => - block.elements.map((element) => ({ - ...element, - appId: block.appId, - blockId: block.blockId, - })), - [block.appId, block.blockId, block.elements], - ); +const ContextBlock = ({ className, block, surfaceRenderer }: ContextBlockProps): ReactElement => { + const itemElements = useMemo( + () => + block.elements.map((element) => ({ + ...element, + appId: block.appId, + blockId: block.blockId, + })), + [block.appId, block.blockId, block.elements], + ); - return ( - - {itemElements.map((element, i) => ( - - ))} - - ); + return ( + + {itemElements.map((element, i) => ( + + ))} + + ); }; export default memo(ContextBlock); diff --git a/packages/fuselage-ui-kit/src/blocks/DividerBlock.tsx b/packages/fuselage-ui-kit/src/blocks/DividerBlock.tsx index 77f6d00a83d04..6f685daaeddd8 100644 --- a/packages/fuselage-ui-kit/src/blocks/DividerBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/DividerBlock.tsx @@ -7,8 +7,6 @@ import type { BlockProps } from '../utils/BlockProps'; type DividerBlockProps = BlockProps; -const DividerBlock = ({ className }: DividerBlockProps): ReactElement => ( - -); +const DividerBlock = ({ className }: DividerBlockProps): ReactElement => ; export default memo(DividerBlock); diff --git a/packages/fuselage-ui-kit/src/blocks/ImageBlock.styles.tsx b/packages/fuselage-ui-kit/src/blocks/ImageBlock.styles.tsx index 060b15ee919d7..84513c3c8e11c 100644 --- a/packages/fuselage-ui-kit/src/blocks/ImageBlock.styles.tsx +++ b/packages/fuselage-ui-kit/src/blocks/ImageBlock.styles.tsx @@ -1,24 +1,24 @@ import styled from '@rocket.chat/styled'; const filterImageProps = ({ - imageUrl: _imageUrl, - width: _width, - height: _height, - ...props + imageUrl: _imageUrl, + width: _width, + height: _height, + ...props }: { - imageUrl: string; - width: number; - height: number; + imageUrl: string; + width: number; + height: number; }) => props; export const Image = styled('div', filterImageProps)` - box-shadow: 0 0 0px 1px rgba(204, 204, 204, 38%); - background-repeat: no-repeat; - background-position: 50%; - background-size: cover; - background-color: rgba(204, 204, 204, 38%); - background-image: url(${(props) => props.imageUrl}); - width: ${(props) => String(props.width)}px; - height: ${(props) => String(props.height)}px; - overflow: hidden; + box-shadow: 0 0 0px 1px rgba(204, 204, 204, 38%); + background-repeat: no-repeat; + background-position: 50%; + background-size: cover; + background-color: rgba(204, 204, 204, 38%); + background-image: url(${(props) => props.imageUrl}); + width: ${(props) => String(props.width)}px; + height: ${(props) => String(props.height)}px; + overflow: hidden; `; diff --git a/packages/fuselage-ui-kit/src/blocks/ImageBlock.tsx b/packages/fuselage-ui-kit/src/blocks/ImageBlock.tsx index 10ee2502ff0e9..3bd88eecf582f 100644 --- a/packages/fuselage-ui-kit/src/blocks/ImageBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/ImageBlock.tsx @@ -10,97 +10,75 @@ import type { BlockProps } from '../utils/BlockProps'; const maxSize = 360; const fetchImageState = (img: HTMLImageElement) => { - if (!img.complete) { - return { - loading: true, - width: maxSize, - height: (maxSize * 9) / 21, - }; - } - - const { naturalWidth, naturalHeight } = img; - - const scaleRatio = - naturalWidth > naturalHeight - ? Math.min(naturalWidth, maxSize) / naturalWidth - : Math.min(naturalHeight, maxSize) / naturalHeight; - - return { - loading: false, - width: naturalWidth * scaleRatio, - height: naturalHeight * scaleRatio, - }; + if (!img.complete) { + return { + loading: true, + width: maxSize, + height: (maxSize * 9) / 21, + }; + } + + const { naturalWidth, naturalHeight } = img; + + const scaleRatio = + naturalWidth > naturalHeight ? Math.min(naturalWidth, maxSize) / naturalWidth : Math.min(naturalHeight, maxSize) / naturalHeight; + + return { + loading: false, + width: naturalWidth * scaleRatio, + height: naturalHeight * scaleRatio, + }; }; type ImageBlockProps = BlockProps; -const ImageBlock = ({ - className, - block, - surfaceRenderer, -}: ImageBlockProps): ReactElement => { - const surface = useSurfaceType(); - - const alignment = - surface === 'banner' || surface === 'message' ? 'flex-start' : 'center'; - - const [{ loading, width, height }, setState] = useState(() => { - const img = document.createElement('img'); - img.src = block.imageUrl; - return fetchImageState(img); - }); - - useEffect(() => { - const img = document.createElement('img'); - - const handleLoad = () => { - setState(fetchImageState(img)); - }; - - img.addEventListener('load', handleLoad); - img.src = block.imageUrl; - - if (img.complete) { - img.removeEventListener('load', handleLoad); - setState(fetchImageState(img)); - } - - return () => { - img.removeEventListener('load', handleLoad); - }; - }, [block.imageUrl]); - - return ( - - - {block.title && ( - - {surfaceRenderer.renderTextObject( - block.title, - 0, - UiKit.BlockContext.NONE, - )} - - )} - {loading ? ( - - ) : ( - - )} - - - ); +const ImageBlock = ({ className, block, surfaceRenderer }: ImageBlockProps): ReactElement => { + const surface = useSurfaceType(); + + const alignment = surface === 'banner' || surface === 'message' ? 'flex-start' : 'center'; + + const [{ loading, width, height }, setState] = useState(() => { + const img = document.createElement('img'); + img.src = block.imageUrl; + return fetchImageState(img); + }); + + useEffect(() => { + const img = document.createElement('img'); + + const handleLoad = () => { + setState(fetchImageState(img)); + }; + + img.addEventListener('load', handleLoad); + img.src = block.imageUrl; + + if (img.complete) { + img.removeEventListener('load', handleLoad); + setState(fetchImageState(img)); + } + + return () => { + img.removeEventListener('load', handleLoad); + }; + }, [block.imageUrl]); + + return ( + + + {block.title && ( + + {surfaceRenderer.renderTextObject(block.title, 0, UiKit.BlockContext.NONE)} + + )} + {loading ? ( + + ) : ( + + )} + + + ); }; export default memo(ImageBlock); diff --git a/packages/fuselage-ui-kit/src/blocks/InputBlock.tsx b/packages/fuselage-ui-kit/src/blocks/InputBlock.tsx index 8a4cee136a07f..72a34133e4c83 100644 --- a/packages/fuselage-ui-kit/src/blocks/InputBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/InputBlock.tsx @@ -1,10 +1,4 @@ -import { - Field, - FieldLabel, - FieldRow, - FieldError, - FieldHint, -} from '@rocket.chat/fuselage'; +import { Field, FieldLabel, FieldRow, FieldError, FieldHint } from '@rocket.chat/fuselage'; import * as UiKit from '@rocket.chat/ui-kit'; import type { ReactElement } from 'react'; import { memo, useMemo } from 'react'; @@ -14,49 +8,26 @@ import type { BlockProps } from '../utils/BlockProps'; type InputBlockProps = BlockProps; -const InputBlock = ({ - className, - block, - surfaceRenderer, - context, -}: InputBlockProps): ReactElement => { - const inputElement = useMemo( - () => ({ - ...block.element, - appId: block.element.appId ?? block.appId, - blockId: block.element.blockId ?? block.blockId, - }), - [block.element, block.appId, block.blockId], - ); +const InputBlock = ({ className, block, surfaceRenderer, context }: InputBlockProps): ReactElement => { + const inputElement = useMemo( + () => ({ + ...block.element, + appId: block.element.appId ?? block.appId, + blockId: block.element.blockId ?? block.blockId, + }), + [block.element, block.appId, block.blockId], + ); - const [{ error }] = useUiKitState(inputElement, context); + const [{ error }] = useUiKitState(inputElement, context); - return ( - - {block.label && ( - - {surfaceRenderer.renderTextObject( - block.label, - 0, - UiKit.BlockContext.NONE, - )} - - )} - - {surfaceRenderer.renderInputBlockElement(inputElement, 0)} - - {error && {error}} - {block.hint && ( - - {surfaceRenderer.renderTextObject( - block.hint, - 0, - UiKit.BlockContext.NONE, - )} - - )} - - ); + return ( + + {block.label && {surfaceRenderer.renderTextObject(block.label, 0, UiKit.BlockContext.NONE)}} + {surfaceRenderer.renderInputBlockElement(inputElement, 0)} + {error && {error}} + {block.hint && {surfaceRenderer.renderTextObject(block.hint, 0, UiKit.BlockContext.NONE)}} + + ); }; export default memo(InputBlock); diff --git a/packages/fuselage-ui-kit/src/blocks/PreviewBlock.tsx b/packages/fuselage-ui-kit/src/blocks/PreviewBlock.tsx index 23b4b0cacb3a0..77c6872cdf04d 100644 --- a/packages/fuselage-ui-kit/src/blocks/PreviewBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/PreviewBlock.tsx @@ -1,18 +1,15 @@ import { - MessageGenericPreview, - MessageGenericPreviewContent, - MessageGenericPreviewDescription, - MessageGenericPreviewCoverImage, - MessageGenericPreviewTitle, - MessageGenericPreviewFooter, - MessageGenericPreviewThumb, - Box, + MessageGenericPreview, + MessageGenericPreviewContent, + MessageGenericPreviewDescription, + MessageGenericPreviewCoverImage, + MessageGenericPreviewTitle, + MessageGenericPreviewFooter, + MessageGenericPreviewThumb, + Box, } from '@rocket.chat/fuselage'; import * as UiKit from '@rocket.chat/ui-kit'; -import { - isPreviewBlockWithThumb, - isPreviewBlockWithPreview, -} from '@rocket.chat/ui-kit'; +import { isPreviewBlockWithThumb, isPreviewBlockWithPreview } from '@rocket.chat/ui-kit'; import type { ReactElement } from 'react'; import { memo } from 'react'; @@ -21,71 +18,43 @@ import type { BlockProps } from '../utils/BlockProps'; type PreviewBlockProps = BlockProps; -const PreviewBlock = ({ - block, - surfaceRenderer, -}: PreviewBlockProps): ReactElement => ( - - - {isPreviewBlockWithPreview(block) && block.preview?.dimensions && ( - - )} - - - - ) : undefined - } - > - {Array.isArray(block.title) ? ( - - {block.title.map((title) => - surfaceRenderer.renderTextObject( - title, - 0, - UiKit.BlockContext.NONE, - ), - )} - - ) : null} - {Array.isArray(block.description) ? ( - - {block.description.map((description) => - surfaceRenderer.renderTextObject( - description, - 0, - UiKit.BlockContext.NONE, - ), - )} - - ) : null} - {block.footer && ( - - - - )} - - - +const PreviewBlock = ({ block, surfaceRenderer }: PreviewBlockProps): ReactElement => ( + + + {isPreviewBlockWithPreview(block) && block.preview?.dimensions && ( + + )} + + + + ) : undefined + } + > + {Array.isArray(block.title) ? ( + + {block.title.map((title) => surfaceRenderer.renderTextObject(title, 0, UiKit.BlockContext.NONE))} + + ) : null} + {Array.isArray(block.description) ? ( + + {block.description.map((description) => surfaceRenderer.renderTextObject(description, 0, UiKit.BlockContext.NONE))} + + ) : null} + {block.footer && ( + + + + )} + + + ); export default memo(PreviewBlock); diff --git a/packages/fuselage-ui-kit/src/blocks/SectionBlock.Fields.tsx b/packages/fuselage-ui-kit/src/blocks/SectionBlock.Fields.tsx index a92ad87ad0eef..78bd70667a967 100644 --- a/packages/fuselage-ui-kit/src/blocks/SectionBlock.Fields.tsx +++ b/packages/fuselage-ui-kit/src/blocks/SectionBlock.Fields.tsx @@ -3,26 +3,26 @@ import * as UiKit from '@rocket.chat/ui-kit'; import type { ReactElement } from 'react'; const breakpoints = { - xs: 4, - sm: 4, - md: 4, - lg: 6, - xl: 6, + xs: 4, + sm: 4, + md: 4, + lg: 6, + xl: 6, } as const; type FieldsProps = { - fields: readonly UiKit.TextObject[]; - surfaceRenderer: UiKit.SurfaceRenderer; + fields: readonly UiKit.TextObject[]; + surfaceRenderer: UiKit.SurfaceRenderer; }; const Fields = ({ fields, surfaceRenderer }: FieldsProps): ReactElement => ( - - {fields.map((field, i) => ( - - {surfaceRenderer.renderTextObject(field, 0, UiKit.BlockContext.NONE)} - - ))} - + + {fields.map((field, i) => ( + + {surfaceRenderer.renderTextObject(field, 0, UiKit.BlockContext.NONE)} + + ))} + ); export default Fields; diff --git a/packages/fuselage-ui-kit/src/blocks/SectionBlock.tsx b/packages/fuselage-ui-kit/src/blocks/SectionBlock.tsx index dab4662ea0ec0..ce423d60f72e6 100644 --- a/packages/fuselage-ui-kit/src/blocks/SectionBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/SectionBlock.tsx @@ -8,49 +8,38 @@ import type { BlockProps } from '../utils/BlockProps'; type SectionBlockProps = BlockProps; -const SectionBlock = ({ - className, - block, - surfaceRenderer, -}: SectionBlockProps): ReactElement => { - const { text, fields } = block; +const SectionBlock = ({ className, block, surfaceRenderer }: SectionBlockProps): ReactElement => { + const { text, fields } = block; - const accessoryElement = useMemo( - () => - block.accessory - ? { - appId: block.appId, - blockId: block.blockId, - ...block.accessory, - } - : undefined, - [block.appId, block.blockId, block.accessory], - ); + const accessoryElement = useMemo( + () => + block.accessory + ? { + appId: block.appId, + blockId: block.blockId, + ...block.accessory, + } + : undefined, + [block.appId, block.blockId, block.accessory], + ); - return ( - - - {text && ( - - {surfaceRenderer.text(text)} - - )} - {fields && } - - {block.accessory && ( - - - {accessoryElement - ? surfaceRenderer.renderSectionAccessoryBlockElement( - accessoryElement, - 0, - ) - : null} - - - )} - - ); + return ( + + + {text && ( + + {surfaceRenderer.text(text)} + + )} + {fields && } + + {block.accessory && ( + + {accessoryElement ? surfaceRenderer.renderSectionAccessoryBlockElement(accessoryElement, 0) : null} + + )} + + ); }; export default memo(SectionBlock); diff --git a/packages/fuselage-ui-kit/src/blocks/TabNavigationBlock.tsx b/packages/fuselage-ui-kit/src/blocks/TabNavigationBlock.tsx index 9d5d4f4e1f488..2c47b64ab9d3e 100644 --- a/packages/fuselage-ui-kit/src/blocks/TabNavigationBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/TabNavigationBlock.tsx @@ -8,37 +8,35 @@ import type { BlockProps } from '../utils/BlockProps'; type TabNavigationBlockProps = BlockProps; -const TabNavigationBlock = ( - blockProps: TabNavigationBlockProps, -): ReactElement => { - const { - block: { tabs }, - context, - surfaceRenderer, - } = blockProps; +const TabNavigationBlock = (blockProps: TabNavigationBlockProps): ReactElement => { + const { + block: { tabs }, + context, + surfaceRenderer, + } = blockProps; - const [selected, select] = useState(); + const [selected, select] = useState(); - return ( - - {tabs.map((innerBlock, idx) => { - if (selected !== undefined) { - innerBlock.selected = idx === selected; - } + return ( + + {tabs.map((innerBlock, idx) => { + if (selected !== undefined) { + innerBlock.selected = idx === selected; + } - return ( - - ); - })} - - ); + return ( + + ); + })} + + ); }; export default memo(TabNavigationBlock); diff --git a/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx b/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx index a1937e0416d78..f6901911d554d 100644 --- a/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx +++ b/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx @@ -1,28 +1,19 @@ -import { - getUserDisplayName, - VideoConferenceStatus, -} from '@rocket.chat/core-typings'; -import { - useGoToRoom, - useSetting, - useTranslation, - useUserId, - useUserPreference, -} from '@rocket.chat/ui-contexts'; +import { getUserDisplayName, VideoConferenceStatus } from '@rocket.chat/core-typings'; +import { useGoToRoom, useSetting, useTranslation, useUserId, useUserPreference } from '@rocket.chat/ui-contexts'; import type * as UiKit from '@rocket.chat/ui-kit'; import { - VideoConfMessageSkeleton, - VideoConfMessage, - VideoConfMessageRow, - VideoConfMessageIcon, - VideoConfMessageText, - VideoConfMessageFooter, - VideoConfMessageUserStack, - VideoConfMessageFooterText, - VideoConfMessageButton, - VideoConfMessageContent, - VideoConfMessageActions, - VideoConfMessageAction, + VideoConfMessageSkeleton, + VideoConfMessage, + VideoConfMessageRow, + VideoConfMessageIcon, + VideoConfMessageText, + VideoConfMessageFooter, + VideoConfMessageUserStack, + VideoConfMessageFooterText, + VideoConfMessageButton, + VideoConfMessageContent, + VideoConfMessageActions, + VideoConfMessageAction, } from '@rocket.chat/ui-video-conf'; import type { MouseEventHandler, ReactElement } from 'react'; import { useContext, memo, useMemo } from 'react'; @@ -36,218 +27,190 @@ type VideoConferenceBlockProps = BlockProps; const MAX_USERS = 3; -const VideoConferenceBlock = ({ - block, -}: VideoConferenceBlockProps): ReactElement => { - const t = useTranslation(); - const { callId, appId = 'videoconf-core' } = block; - const surfaceType = useSurfaceType(); - const userId = useUserId(); - const goToRoom = useGoToRoom(); - const displayAvatars = useUserPreference('displayAvatars'); - const showRealName = useSetting('UI_Use_Real_Name', false); - - const { action, viewId = undefined, rid } = useContext(UiKitContext); - - if (surfaceType !== 'message') { - throw new Error('VideoConferenceBlock cannot be rendered outside message'); - } - - if (!rid) { - throw new Error('VideoConferenceBlock cannot be rendered without rid'); - } - - const result = useVideoConfDataStream({ rid, callId }); - - const joinHandler: MouseEventHandler = (e): void => { - action( - { - blockId: block.blockId || '', - appId, - actionId: 'join', - value: block.blockId || '', - viewId, - }, - e, - ); - }; - - const callAgainHandler: MouseEventHandler = (e): void => { - action( - { - blockId: rid || '', - appId, - actionId: 'callBack', - value: rid || '', - viewId, - }, - e, - ); - }; - - const openCallInfo: MouseEventHandler = (e) => { - action( - { - blockId: callId, - appId, - actionId: 'info', - value: rid, - viewId, - }, - e, - ); - }; - - const openDiscussion: MouseEventHandler = (_e) => { - if (data.discussionRid) { - goToRoom(data.discussionRid); - } - }; - - const messageFooterText = useMemo(() => { - const usersCount = result.data?.users.length; - - if (!displayAvatars) { - return t('__usersCount__joined', { - count: usersCount, - }); - } - - return usersCount && usersCount > MAX_USERS - ? t('plus__usersCount__joined', { - count: usersCount - MAX_USERS, - }) - : t('joined'); - }, [displayAvatars, t, result.data?.users.length]); - - if (result.isPending || result.isError) { - // TODO: error handling - return ; - } - - const { data } = result; - const isUserCaller = data.createdBy._id === userId; - - const joinedNamesOrUsernames = [...data.users] - .splice(0, MAX_USERS) - .map(({ name, username }) => - getUserDisplayName(name, username, showRealName), - ) - .join(', '); - - const title = - data.users.length > MAX_USERS - ? t('__usernames__and__count__more_joined', { - usernames: joinedNamesOrUsernames, - count: data.users.length - MAX_USERS, - }) - : t('__usernames__joined', { usernames: joinedNamesOrUsernames }); - - const actions = ( - - {data.discussionRid && ( - - )} - - - ); - - if ('endedAt' in data) { - return ( - - - - - {t('Call_ended')} - - {actions} - - - {data.type === 'direct' && ( - <> - - {isUserCaller ? t('Call_again') : t('Call_back')} - - {[ - VideoConferenceStatus.EXPIRED, - VideoConferenceStatus.DECLINED, - ].includes(data.status) && ( - - {t('Call_was_not_answered')} - - )} - - )} - {data.type !== 'direct' && - (data.users.length ? ( - <> - - - {messageFooterText} - - - ) : ( - [ - VideoConferenceStatus.EXPIRED, - VideoConferenceStatus.DECLINED, - ].includes(data.status) && ( - - {t('Call_was_not_answered')} - - ) - ))} - - - ); - } - - if (data.type === 'direct' && data.status === VideoConferenceStatus.CALLING) { - return ( - - - - - {t('Calling')} - - {actions} - - - - {t('Waiting_for_answer')} - - - - ); - } - - return ( - - - - - {t('Call_ongoing')} - - {actions} - - - - {t('Join')} - - {Boolean(data.users.length) && ( - <> - - - {messageFooterText} - - - )} - - - ); +const VideoConferenceBlock = ({ block }: VideoConferenceBlockProps): ReactElement => { + const t = useTranslation(); + const { callId, appId = 'videoconf-core' } = block; + const surfaceType = useSurfaceType(); + const userId = useUserId(); + const goToRoom = useGoToRoom(); + const displayAvatars = useUserPreference('displayAvatars'); + const showRealName = useSetting('UI_Use_Real_Name', false); + + const { action, viewId = undefined, rid } = useContext(UiKitContext); + + if (surfaceType !== 'message') { + throw new Error('VideoConferenceBlock cannot be rendered outside message'); + } + + if (!rid) { + throw new Error('VideoConferenceBlock cannot be rendered without rid'); + } + + const result = useVideoConfDataStream({ rid, callId }); + + const joinHandler: MouseEventHandler = (e): void => { + action( + { + blockId: block.blockId || '', + appId, + actionId: 'join', + value: block.blockId || '', + viewId, + }, + e, + ); + }; + + const callAgainHandler: MouseEventHandler = (e): void => { + action( + { + blockId: rid || '', + appId, + actionId: 'callBack', + value: rid || '', + viewId, + }, + e, + ); + }; + + const openCallInfo: MouseEventHandler = (e) => { + action( + { + blockId: callId, + appId, + actionId: 'info', + value: rid, + viewId, + }, + e, + ); + }; + + const openDiscussion: MouseEventHandler = (_e) => { + if (data.discussionRid) { + goToRoom(data.discussionRid); + } + }; + + const messageFooterText = useMemo(() => { + const usersCount = result.data?.users.length; + + if (!displayAvatars) { + return t('__usersCount__joined', { + count: usersCount, + }); + } + + return usersCount && usersCount > MAX_USERS + ? t('plus__usersCount__joined', { + count: usersCount - MAX_USERS, + }) + : t('joined'); + }, [displayAvatars, t, result.data?.users.length]); + + if (result.isPending || result.isError) { + // TODO: error handling + return ; + } + + const { data } = result; + const isUserCaller = data.createdBy._id === userId; + + const joinedNamesOrUsernames = [...data.users] + .splice(0, MAX_USERS) + .map(({ name, username }) => getUserDisplayName(name, username, showRealName)) + .join(', '); + + const title = + data.users.length > MAX_USERS + ? t('__usernames__and__count__more_joined', { + usernames: joinedNamesOrUsernames, + count: data.users.length - MAX_USERS, + }) + : t('__usernames__joined', { usernames: joinedNamesOrUsernames }); + + const actions = ( + + {data.discussionRid && } + + + ); + + if ('endedAt' in data) { + return ( + + + + + {t('Call_ended')} + + {actions} + + + {data.type === 'direct' && ( + <> + {isUserCaller ? t('Call_again') : t('Call_back')} + {[VideoConferenceStatus.EXPIRED, VideoConferenceStatus.DECLINED].includes(data.status) && ( + {t('Call_was_not_answered')} + )} + + )} + {data.type !== 'direct' && + (data.users.length ? ( + <> + + {messageFooterText} + + ) : ( + [VideoConferenceStatus.EXPIRED, VideoConferenceStatus.DECLINED].includes(data.status) && ( + {t('Call_was_not_answered')} + ) + ))} + + + ); + } + + if (data.type === 'direct' && data.status === VideoConferenceStatus.CALLING) { + return ( + + + + + {t('Calling')} + + {actions} + + + {t('Waiting_for_answer')} + + + ); + } + + return ( + + + + + {t('Call_ongoing')} + + {actions} + + + + {t('Join')} + + {Boolean(data.users.length) && ( + <> + + {messageFooterText} + + )} + + + ); }; export default memo(VideoConferenceBlock); diff --git a/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/hooks/useVideoConfData.ts b/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/hooks/useVideoConfData.ts index 92c4b4be2a460..94072f93c0549 100644 --- a/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/hooks/useVideoConfData.ts +++ b/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/hooks/useVideoConfData.ts @@ -2,19 +2,19 @@ import { useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; export const useVideoConfData = ({ callId }: { callId: string }) => { - const getVideoConfInfo = useEndpoint('GET', '/v1/video-conference.info'); + const getVideoConfInfo = useEndpoint('GET', '/v1/video-conference.info'); - return useQuery({ - queryKey: ['video-conference', callId], - queryFn: () => getVideoConfInfo({ callId }), - staleTime: Infinity, + return useQuery({ + queryKey: ['video-conference', callId], + queryFn: () => getVideoConfInfo({ callId }), + staleTime: Infinity, - refetchOnMount: (query) => { - if (query.state.data?.endedAt) { - return false; - } + refetchOnMount: (query) => { + if (query.state.data?.endedAt) { + return false; + } - return 'always'; - }, - }); + return 'always'; + }, + }); }; diff --git a/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/hooks/useVideoConfDataStream.ts b/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/hooks/useVideoConfDataStream.ts index 42cdeb24ae2b4..dc9cf04f4f84b 100644 --- a/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/hooks/useVideoConfDataStream.ts +++ b/packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/hooks/useVideoConfDataStream.ts @@ -5,27 +5,23 @@ import { useEffect } from 'react'; import { useVideoConfData } from './useVideoConfData'; -export const useVideoConfDataStream = ({ - rid, - callId, -}: { - rid: IRoom['_id']; - callId: string; -}) => { - const queryClient = useQueryClient(); +export const useVideoConfDataStream = ({ rid, callId }: { rid: IRoom['_id']; callId: string }) => { + const queryClient = useQueryClient(); - const subscribeNotifyRoom = useStream('notify-room'); + const subscribeNotifyRoom = useStream('notify-room'); - useEffect(() => { - return subscribeNotifyRoom( - `${rid}/videoconf`, - (id) => - id === callId && - queryClient.invalidateQueries({ - queryKey: ['video-conference', callId], - }), - ); - }, [rid, callId, subscribeNotifyRoom, queryClient]); + useEffect( + () => + subscribeNotifyRoom( + `${rid}/videoconf`, + (id) => + id === callId && + queryClient.invalidateQueries({ + queryKey: ['video-conference', callId], + }), + ), + [rid, callId, subscribeNotifyRoom, queryClient], + ); - return useVideoConfData({ callId }); + return useVideoConfData({ callId }); }; diff --git a/packages/fuselage-ui-kit/src/contexts/AppIdContext.tsx b/packages/fuselage-ui-kit/src/contexts/AppIdContext.tsx index 717c5fa9a58a1..d3d6dc597df2a 100644 --- a/packages/fuselage-ui-kit/src/contexts/AppIdContext.tsx +++ b/packages/fuselage-ui-kit/src/contexts/AppIdContext.tsx @@ -6,25 +6,23 @@ import { UiKitContext } from './UiKitContext'; const AppIdContext = createContext(undefined); type AppIdProviderProps = { - children: ReactNode; - appId?: string; + children: ReactNode; + appId?: string; }; export const AppIdProvider = ({ children, appId }: AppIdProviderProps) => { - if (!appId) { - return <>{children}; - } + if (!appId) { + return <>{children}; + } - return ( - {children} - ); + return {children}; }; export const useAppId = () => { - const outerAppId = useContext(UiKitContext).appId ?? 'core'; - const appId = useContext(AppIdContext) ?? outerAppId; + const outerAppId = useContext(UiKitContext).appId ?? 'core'; + const appId = useContext(AppIdContext) ?? outerAppId; - useDebugValue(appId); + useDebugValue(appId); - return appId; + return appId; }; diff --git a/packages/fuselage-ui-kit/src/contexts/SurfaceContext.ts b/packages/fuselage-ui-kit/src/contexts/SurfaceContext.ts index 97af38bbc51e0..cf1fdc3f534f7 100644 --- a/packages/fuselage-ui-kit/src/contexts/SurfaceContext.ts +++ b/packages/fuselage-ui-kit/src/contexts/SurfaceContext.ts @@ -1,11 +1,5 @@ import { createContext } from 'react'; -export type SurfaceContextValue = - | 'attachment' - | 'banner' - | 'message' - | 'modal' - | 'contextualBar' - | 'custom'; +export type SurfaceContextValue = 'attachment' | 'banner' | 'message' | 'modal' | 'contextualBar' | 'custom'; export const SurfaceContext = createContext('message'); diff --git a/packages/fuselage-ui-kit/src/contexts/UiKitContext.ts b/packages/fuselage-ui-kit/src/contexts/UiKitContext.ts index 2cdaeb175c4c4..3cf1b5efa341c 100644 --- a/packages/fuselage-ui-kit/src/contexts/UiKitContext.ts +++ b/packages/fuselage-ui-kit/src/contexts/UiKitContext.ts @@ -1,43 +1,34 @@ -import type { - ActionableElement, - InputElementDispatchAction, -} from '@rocket.chat/ui-kit'; +import type { ActionableElement, InputElementDispatchAction } from '@rocket.chat/ui-kit'; import type { MouseEventHandler } from 'react'; import { createContext } from 'react'; type ActionId = ActionableElement['actionId']; type ActionParams = { - blockId: string; - appId: string; - actionId: ActionId; - value: unknown; - viewId?: string; - dispatchActionConfig?: InputElementDispatchAction[]; - mid?: string; + blockId: string; + appId: string; + actionId: ActionId; + value: unknown; + viewId?: string; + dispatchActionConfig?: InputElementDispatchAction[]; + mid?: string; }; type UiKitContextValue = { - action: ( - state: ActionParams, - event: Parameters>[0], - ) => Promise | void; - updateState?: ( - state: ActionParams, - event: Parameters>[0], - ) => Promise | void; - appId?: string; - errors?: { [field: string]: string }[] | { [field: string]: string }; - values: Record; - viewId?: string; - rid?: string; + action: (state: ActionParams, event: Parameters>[0]) => Promise | void; + updateState?: (state: ActionParams, event: Parameters>[0]) => Promise | void; + appId?: string; + errors?: { [field: string]: string }[] | { [field: string]: string }; + values: Record; + viewId?: string; + rid?: string; }; export const UiKitContext = createContext({ - action: () => undefined, - updateState: () => undefined, - appId: 'core', - values: {}, + action: () => undefined, + updateState: () => undefined, + appId: 'core', + values: {}, }); Object.assign(UiKitContext.Provider, { displayName: 'UiKitContext.Provider' }); diff --git a/packages/fuselage-ui-kit/src/elements/ButtonElement.tsx b/packages/fuselage-ui-kit/src/elements/ButtonElement.tsx index 1f80358b3d933..699722c90c6a0 100644 --- a/packages/fuselage-ui-kit/src/elements/ButtonElement.tsx +++ b/packages/fuselage-ui-kit/src/elements/ButtonElement.tsx @@ -7,63 +7,51 @@ import type { BlockProps } from '../utils/BlockProps'; type ButtonElementProps = BlockProps; -const ButtonElement = ({ - block, - context, - surfaceRenderer, -}: ButtonElementProps): ReactElement => { - const [{ loading }, action] = useUiKitState(block, context); - const { style, url, text, value, secondary } = block; +const ButtonElement = ({ block, context, surfaceRenderer }: ButtonElementProps): ReactElement => { + const [{ loading }, action] = useUiKitState(block, context); + const { style, url, text, value, secondary } = block; - const handleClick: MouseEventHandler = (e) => { - action({ target: e.currentTarget }); - }; + const handleClick: MouseEventHandler = (e) => { + action({ target: e.currentTarget }); + }; - if (url) { - return ( - - ); - } + if (url) { + return ( + + ); + } - return ( - - ); + return ( + + ); }; export default ButtonElement; diff --git a/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.spec.tsx b/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.spec.tsx index d299f20b86aa0..d477025bc2424 100644 --- a/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.spec.tsx +++ b/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.spec.tsx @@ -10,86 +10,81 @@ import { contextualBarParser } from '../../surfaces'; import { useChannelsData } from './hooks/useChannelsData'; const channelsBlock: ChannelsSelectElementType = { - type: 'channels_select', - appId: 'test', - blockId: 'test', - actionId: 'test', + type: 'channels_select', + appId: 'test', + blockId: 'test', + actionId: 'test', }; jest.mock('./hooks/useChannelsData'); const mockedOptions: ReturnType = [ - { - value: 'channel1_id', - label: { - name: 'Channel 1', - avatarETag: 'test', - type: RoomType.CHANNEL, - }, - }, - { - value: 'channel2_id', - label: { - name: 'Channel 2', - avatarETag: 'test', - type: RoomType.CHANNEL, - }, - }, - { - value: 'channel3_id', - label: { - name: 'Channel 3', - avatarETag: 'test', - type: RoomType.CHANNEL, - }, - }, + { + value: 'channel1_id', + label: { + name: 'Channel 1', + avatarETag: 'test', + type: RoomType.CHANNEL, + }, + }, + { + value: 'channel2_id', + label: { + name: 'Channel 2', + avatarETag: 'test', + type: RoomType.CHANNEL, + }, + }, + { + value: 'channel3_id', + label: { + name: 'Channel 3', + avatarETag: 'test', + type: RoomType.CHANNEL, + }, + }, ]; const mockUseChannelsData = jest.mocked(useChannelsData); mockUseChannelsData.mockReturnValue(mockedOptions); describe('UiKit ChannelsSelect Element', () => { - beforeAll(() => { - jest.useFakeTimers(); - }); + beforeAll(() => { + jest.useFakeTimers(); + }); - afterAll(() => { - jest.useRealTimers(); - }); + afterAll(() => { + jest.useRealTimers(); + }); - beforeEach(() => { - render( - - - , - ); - }); + beforeEach(() => { + render( + + + , + ); + }); - it('should render a UiKit channel selector', async () => { - expect(await screen.findByRole('textbox')).toBeInTheDocument(); - }); + it('should render a UiKit channel selector', async () => { + expect(await screen.findByRole('textbox')).toBeInTheDocument(); + }); - it('should open the channel selector', async () => { - const input = await screen.findByRole('textbox'); - input.focus(); + it('should open the channel selector', async () => { + const input = await screen.findByRole('textbox'); + input.focus(); - expect(await screen.findByRole('listbox')).toBeInTheDocument(); - }); + expect(await screen.findByRole('listbox')).toBeInTheDocument(); + }); - it('should select a channel', async () => { - const input = await screen.findByRole('textbox'); + it('should select a channel', async () => { + const input = await screen.findByRole('textbox'); - input.focus(); + input.focus(); - const option = (await screen.findAllByRole('option'))[0]; - await userEvent.click(option, { delay: null }); + const option = (await screen.findAllByRole('option'))[0]; + await userEvent.click(option, { delay: null }); - const selected = await screen.findByRole('button'); - expect(selected).toHaveValue('channel1_id'); - }); + const selected = await screen.findByRole('button'); + expect(selected).toHaveValue('channel1_id'); + }); }); diff --git a/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.tsx b/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.tsx index 96d055253ac24..c5a3699907b97 100644 --- a/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.tsx +++ b/packages/fuselage-ui-kit/src/elements/ChannelsSelectElement/ChannelsSelectElement.tsx @@ -10,63 +10,57 @@ import type { BlockProps } from '../../utils/BlockProps'; type ChannelsSelectElementProps = BlockProps; -const ChannelsSelectElement = ({ - block, - context, -}: ChannelsSelectElementProps) => { - const [{ value, loading }, action] = useUiKitState(block, context); +const ChannelsSelectElement = ({ block, context }: ChannelsSelectElementProps) => { + const [{ value, loading }, action] = useUiKitState(block, context); - const [filter, setFilter] = useState(''); - const filterDebounced = useDebouncedValue(filter, 300); + const [filter, setFilter] = useState(''); + const filterDebounced = useDebouncedValue(filter, 300); - const options = useChannelsData({ filter: filterDebounced }); + const options = useChannelsData({ filter: filterDebounced }); - const handleChange = useCallback( - (value: string | string[]) => { - if (!Array.isArray(value)) action({ target: { value } }); - }, - [action], - ); + const handleChange = useCallback( + (value: string | string[]) => { + if (!Array.isArray(value)) action({ target: { value } }); + }, + [action], + ); - return ( - ( - - - - {label.name} - - - )} - renderItem={({ value, label, ...props }) => ( -