diff --git a/packages/react/src/components/ChatBody/ChatBody.js b/packages/react/src/components/ChatBody/ChatBody.js index a13a472f2..2899ecfdb 100644 --- a/packages/react/src/components/ChatBody/ChatBody.js +++ b/packages/react/src/components/ChatBody/ChatBody.js @@ -136,18 +136,21 @@ const ChatBody = ({ setViewData(null); }; - const onModalSubmit = useCallback(async (data, value) => { - console.log(data); - // const { actionId, value, blockId, appId, viewId } = data; - // await RCInstance?.triggerBlockAction({ - // rid: RCInstance.rid, - // actionId, - // value, - // blockId, - // appId, - // viewId, - // }); - }); + const onModalSubmit = useCallback( + async (data) => { + console.log(data); + const { actionId, value, blockId, appId, viewId } = data; + await RCInstance?.triggerBlockAction({ + rid: RCInstance.rid, + actionId, + value, + blockId, + appId, + viewId, + }); + }, + [RCInstance] + ); useEffect(() => { RCInstance.auth.onAuthChange((user) => { diff --git a/packages/react/src/components/Menu/Menu.js b/packages/react/src/components/Menu/Menu.js index e544228ba..9a1811634 100644 --- a/packages/react/src/components/Menu/Menu.js +++ b/packages/react/src/components/Menu/Menu.js @@ -31,6 +31,7 @@ const Menu = ({ className = '', style = {}, anchor = 'right bottom', + isToolTip = true, }) => { const theme = useTheme(); const shadowCss = css` @@ -84,10 +85,14 @@ const Menu = ({ className={appendClassNames('ec-menu-wrapper', wrapperClasses)} style={wrapperStyles} > - - {' '} + {isToolTip ? ( + + {' '} + setOpen(!isOpen)} /> + + ) : ( setOpen(!isOpen)} /> - + )} {isOpen ? ( { + const { classNames, styleOverrides } = useComponentOverrides('StaticSelect'); + const theme = useTheme(); + + const SelectCss = css` + position: relative; + display: inline-flex; + flex: 1 0 auto; + min-width: 8rem; + padding: 0.5rem 0.9375rem; + vertical-align: baseline; + outline: 0; + background-color: transparent; + letter-spacing: 0rem; + font-size: 0.875rem; + font-weight: 400; + line-height: 1.25rem; + overflow: hidden; + color: #2f343d; + border-right: 0.9375rem transparent; + border-width: 1px; + border-color: #cbced1; + border-style: solid; + border-radius: 0.25rem; + background-color: white; + box-shadow: none; + -webkit-appearance: none; + appearance: none; + transition: all 230ms; + background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23111111" width="24px" height="24px"%3E%3Cpath d="M0 0h24v24H0z" fill="none"/%3E%3Cpath d="M7 10l5 5 5-5z" /%3E%3C/svg%3E'); + background-size: 24px; + background-repeat: no-repeat; + background-position: calc(100% - 8px) center; + &:focus { + border-color: ${theme.palette[color].main || 'currentColor'}; + box-shadow: 0px 0px 2.5px ${theme.palette[color].light || 'currentColor'}; + } + `; + + return ( + + ); +}; + +StaticSelect.propTypes = { + className: PropTypes.string, + style: PropTypes.object, + color: PropTypes.string, + options: PropTypes.arrayOf( + PropTypes.shape({ + value: PropTypes.string, + label: PropTypes.string, + }) + ), + onChange: PropTypes.func, +}; + +export default StaticSelect; diff --git a/packages/react/src/components/StaticSelect/index.js b/packages/react/src/components/StaticSelect/index.js new file mode 100644 index 000000000..be1b753c7 --- /dev/null +++ b/packages/react/src/components/StaticSelect/index.js @@ -0,0 +1 @@ +export { default as StaticSelect } from './StaticSelect'; diff --git a/packages/react/src/components/uiKit/blocks/UiKitModal.js b/packages/react/src/components/uiKit/blocks/UiKitModal.js index 7a3929bf7..33a90b004 100644 --- a/packages/react/src/components/uiKit/blocks/UiKitModal.js +++ b/packages/react/src/components/uiKit/blocks/UiKitModal.js @@ -1,164 +1,166 @@ -/* eslint-disable react/jsx-no-undef */ -/* eslint-disable import/extensions */ -/* eslint-disable import/no-unresolved */ -/* eslint-disable no-shadow */ -/* eslint-disable react/jsx-no-constructed-context-values */ -import React from 'react'; -import { - useDebouncedCallback, - useMutableCallback, -} from '@rocket.chat/fuselage-hooks'; -import { kitContext } from '../contexts/kitContext'; - -import * as ActionManager from '../../../../app/ui-message/client/ActionManager'; -import { detectEmoji } from '../../../lib/utils/detectEmoji'; -import ModalBlock from './ModalBlock'; -import { useActionManagerState } from './hooks/useActionManagerState'; -import { useValues } from './hooks/useValues'; - -const UiKitModal = (props) => { - const state = useActionManagerState(props); - - const { appId, viewId, mid: _mid, errors, view } = state; - - const [values, updateValues] = useValues(view.blocks); - - const groupStateByBlockId = (values) => - Object.entries(values).reduce((obj, [key, { blockId, value }]) => { - obj[blockId] = obj[blockId] || {}; - obj[blockId][key] = value; - - return obj; - }, {}); - - const prevent = (e) => { - if (e) { - (e.nativeEvent || e).stopImmediatePropagation(); - e.stopPropagation(); - e.preventDefault(); - } - }; - - const debouncedBlockAction = useDebouncedCallback( - (actionId, appId, value, blockId, mid) => { - ActionManager.triggerBlockAction({ - container: { - type: 'view', - id: viewId, - }, - actionId, - appId, - value, - blockId, - mid, - }); - }, - 700 - ); - - // TODO: this structure is atrociously wrong; we should revisit this - const context = { - // @ts-expect-error Property 'mid' does not exist on type 'ActionParams'. - action: ({ - actionId, - appId, - value, - blockId, - mid = _mid, - dispatchActionConfig, - }) => { - if ( - Array.isArray(dispatchActionConfig) && - dispatchActionConfig.includes('on_character_entered') - ) { - debouncedBlockAction(actionId, appId, value, blockId, mid); - } else { - ActionManager.triggerBlockAction({ - container: { - type: 'view', - id: viewId, - }, - actionId, - appId, - value, - blockId, - mid, - }); - } - }, - - state: ({ actionId, value, /* ,appId, */ blockId = 'default' }) => { - updateValues({ - actionId, - payload: { - blockId, - value, - }, - }); - }, - ...state, - values, - }; - - const handleSubmit = useMutableCallback((e) => { - prevent(e); - ActionManager.triggerSubmitView({ - viewId, - appId, - payload: { - view: { - ...view, - id: viewId, - state: groupStateByBlockId(values), - }, - }, - }); - }); - - const handleCancel = useMutableCallback((e) => { - prevent(e); - ActionManager.triggerCancel({ - viewId, - appId, - view: { - ...view, - id: viewId, - state: groupStateByBlockId(values), - }, - }); - }); - - const handleClose = useMutableCallback(() => { - ActionManager.triggerCancel({ - viewId, - appId, - view: { - ...view, - id: viewId, - state: groupStateByBlockId(values), - }, - isCleared: true, - }); - }); - - return ( - - - - - - ); -}; - -export default UiKitModal; +// File is never used, already implemented a fuselage surface renderer in which everything is defined + +// /* eslint-disable react/jsx-no-undef */ +// /* eslint-disable import/extensions */ +// /* eslint-disable import/no-unresolved */ +// /* eslint-disable no-shadow */ +// /* eslint-disable react/jsx-no-constructed-context-values */ +// import React from 'react'; +// import { +// useDebouncedCallback, +// useMutableCallback, +// } from '@rocket.chat/fuselage-hooks'; +// import { kitContext } from '../contexts/kitContext'; + +// import * as ActionManager from '../../../../app/ui-message/client/ActionManager'; +// import { detectEmoji } from '../../../lib/utils/detectEmoji'; +// import ModalBlock from './ModalBlock'; +// import { useActionManagerState } from './hooks/useActionManagerState'; +// import { useValues } from './hooks/useValues'; + +// const UiKitModal = (props) => { +// const state = useActionManagerState(props); + +// const { appId, viewId, mid: _mid, errors, view } = state; + +// const [values, updateValues] = useValues(view.blocks); + +// const groupStateByBlockId = (values) => +// Object.entries(values).reduce((obj, [key, { blockId, value }]) => { +// obj[blockId] = obj[blockId] || {}; +// obj[blockId][key] = value; + +// return obj; +// }, {}); + +// const prevent = (e) => { +// if (e) { +// (e.nativeEvent || e).stopImmediatePropagation(); +// e.stopPropagation(); +// e.preventDefault(); +// } +// }; + +// const debouncedBlockAction = useDebouncedCallback( +// (actionId, appId, value, blockId, mid) => { +// ActionManager.triggerBlockAction({ +// container: { +// type: 'view', +// id: viewId, +// }, +// actionId, +// appId, +// value, +// blockId, +// mid, +// }); +// }, +// 700 +// ); + +// // TODO: this structure is atrociously wrong; we should revisit this +// const context = { +// // @ts-expect-error Property 'mid' does not exist on type 'ActionParams'. +// action: ({ +// actionId, +// appId, +// value, +// blockId, +// mid = _mid, +// dispatchActionConfig, +// }) => { +// if ( +// Array.isArray(dispatchActionConfig) && +// dispatchActionConfig.includes('on_character_entered') +// ) { +// debouncedBlockAction(actionId, appId, value, blockId, mid); +// } else { +// ActionManager.triggerBlockAction({ +// container: { +// type: 'view', +// id: viewId, +// }, +// actionId, +// appId, +// value, +// blockId, +// mid, +// }); +// } +// }, + +// state: ({ actionId, value, /* ,appId, */ blockId = 'default' }) => { +// updateValues({ +// actionId, +// payload: { +// blockId, +// value, +// }, +// }); +// }, +// ...state, +// values, +// }; + +// const handleSubmit = useMutableCallback((e) => { +// prevent(e); +// ActionManager.triggerSubmitView({ +// viewId, +// appId, +// payload: { +// view: { +// ...view, +// id: viewId, +// state: groupStateByBlockId(values), +// }, +// }, +// }); +// }); + +// const handleCancel = useMutableCallback((e) => { +// prevent(e); +// ActionManager.triggerCancel({ +// viewId, +// appId, +// view: { +// ...view, +// id: viewId, +// state: groupStateByBlockId(values), +// }, +// }); +// }); + +// const handleClose = useMutableCallback(() => { +// ActionManager.triggerCancel({ +// viewId, +// appId, +// view: { +// ...view, +// id: viewId, +// state: groupStateByBlockId(values), +// }, +// isCleared: true, +// }); +// }); + +// return ( +// +// +// +// +// +// ); +// }; + +// export default UiKitModal; diff --git a/packages/react/src/components/uiKit/elements/OverflowElement.js b/packages/react/src/components/uiKit/elements/OverflowElement.js index 66c085813..6b67d08c8 100644 --- a/packages/react/src/components/uiKit/elements/OverflowElement.js +++ b/packages/react/src/components/uiKit/elements/OverflowElement.js @@ -1,3 +1,48 @@ +import React, { useMemo, memo } from 'react'; +import { Menu } from '../../Menu'; +import { Box } from '../../Box'; +import { useUiKitState } from '../hooks/useUiKitState'; +import { fromTextObjectToString } from '../utils/fromTextObjectToString'; + +const OverflowElement = ({ block, context, surfaceRenderer }) => { + const [{ loading }, action] = useUiKitState(block, context); + + const options = useMemo( + () => + block.options.map(({ value, text, url }, i) => ({ + id: value, + label: fromTextObjectToString(surfaceRenderer, text, i) ?? '', + icon: undefined, + action: () => { + if (url) { + window.open(url); + } + action({ target: { value: String(value) } }); + }, + })), + [action, block.options, surfaceRenderer] + ); + + return ( + + + + ); +}; + +export default memo(OverflowElement); + // import { // IconButton, // PositionAnimated, diff --git a/packages/react/src/components/uiKit/elements/PlainTextInputElement.js b/packages/react/src/components/uiKit/elements/PlainTextInputElement.js index fc640853a..c2fbfc378 100644 --- a/packages/react/src/components/uiKit/elements/PlainTextInputElement.js +++ b/packages/react/src/components/uiKit/elements/PlainTextInputElement.js @@ -28,7 +28,6 @@ const PlainTextInputElement = ({ block, context, surfaceRenderer }) => { return ( { + const [{ loading }, action] = useUiKitState(block, context); + + const options = useMemo( + () => + block.options.map((option, i) => ({ + value: option.value, + label: fromTextObjectToString(surfaceRenderer, option.text, i) ?? '', + })), + [block.options, surfaceRenderer] + ); + + const handleChange = useCallback( + (val) => { + action({ target: { val } }); + }, + [action] + ); + + return ( + + ); +}; + +export default memo(StaticSelectElement); + // import { SelectFiltered } from '@rocket.chat/fuselage'; // import React, { memo, useCallback, useMemo } from 'react'; diff --git a/packages/react/src/components/uiKit/surfaces/FuselageSurfaceRenderer.js b/packages/react/src/components/uiKit/surfaces/FuselageSurfaceRenderer.js index 12fabb478..c9141e886 100644 --- a/packages/react/src/components/uiKit/surfaces/FuselageSurfaceRenderer.js +++ b/packages/react/src/components/uiKit/surfaces/FuselageSurfaceRenderer.js @@ -13,9 +13,9 @@ import DatePickerElement from '../elements/DatePickerElement'; import ImageElement from '../elements/ImageElement'; import LinearScaleElement from '../elements/LinearScaleElement'; // import MultiStaticSelectElement from '../elements/MultiStaticSelectElement'; -// import OverflowElement from '../elements/OverflowElement'; +import OverflowElement from '../elements/OverflowElement'; import PlainTextInputElement from '../elements/PlainTextInputElement'; -// import StaticSelectElement from '../elements/StaticSelectElement'; +import StaticSelectElement from '../elements/StaticSelectElement'; import { Markup } from '../../Markup'; export class FuselageSurfaceRenderer extends UiKit.SurfaceRenderer { @@ -218,17 +218,15 @@ export class FuselageSurfaceRenderer extends UiKit.SurfaceRenderer { return null; } - return null; - // implement this without fuselage - // return ( - // - // ); + return ( + + ); } multi_static_select(block, context, index) { @@ -254,17 +252,15 @@ export class FuselageSurfaceRenderer extends UiKit.SurfaceRenderer { return null; } - return null; - // implement this without fuselage - // return ( - // - // ); + return ( + + ); } plain_text_input(block, context, index) {