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/ChatInput/ChatInput.js b/packages/react/src/components/ChatInput/ChatInput.js index 8f1237023..502445f6b 100644 --- a/packages/react/src/components/ChatInput/ChatInput.js +++ b/packages/react/src/components/ChatInput/ChatInput.js @@ -199,7 +199,9 @@ const ChatInput = ({ scrollToBottom }) => { if (!editMessage.msg) { if (message.startsWith('/')) { // its a slash command - const [command, params] = message.split(/\s+/); + const [command, ...paramsArray] = message.split(' '); + const params = paramsArray.join(' '); + if (commands.find((c) => c.command === command.replace('/', ''))) { messageRef.current.value = ''; setDisableButton(true); diff --git a/packages/react/src/components/Icon/icons/Key.js b/packages/react/src/components/Icon/icons/Key.js new file mode 100644 index 000000000..492f5cda0 --- /dev/null +++ b/packages/react/src/components/Icon/icons/Key.js @@ -0,0 +1,15 @@ +import React from 'react'; + +const Key = (props) => ( + + + +); + +export default Key; diff --git a/packages/react/src/components/Icon/icons/index.js b/packages/react/src/components/Icon/icons/index.js index 3f468a8f4..60aed7b64 100644 --- a/packages/react/src/components/Icon/icons/index.js +++ b/packages/react/src/components/Icon/icons/index.js @@ -44,6 +44,7 @@ import Download from './Download'; import At from './At'; import ChevronDown from './ChevronDown'; import ChevronLeft from './ChevronLeft'; +import Key from './Key'; const icons = { file: File, @@ -92,6 +93,7 @@ const icons = { at: At, 'chevron-down': ChevronDown, 'chevron-left': ChevronLeft, + key: Key, }; export default icons; diff --git a/packages/react/src/components/Markup/elements/BoldSpan.js b/packages/react/src/components/Markup/elements/BoldSpan.js index a921fba6a..36f1ee945 100644 --- a/packages/react/src/components/Markup/elements/BoldSpan.js +++ b/packages/react/src/components/Markup/elements/BoldSpan.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import PlainSpan from './PlainSpan'; import ItalicSpan from './ItalicSpan'; import StrikeSpan from './StrikeSpan'; +import LinkSpan from './LinkSpan'; const BoldSpan = ({ contents }) => ( @@ -16,6 +17,18 @@ const BoldSpan = ({ contents }) => ( case 'ITALIC': return ; + case 'LINK': + return ( + + ); default: return null; 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( + 'MessageGenericPreview' + ); + const messageGenericPreviewStyles = css` + display: flex; + overflow: hidden; + flex-direction: column; + padding: 0.75rem; + border: 1px solid #ccc; + border-radius: 5px; + background-color: #eff0f1; + `; + return ( +
+ ); +}; + +export default MessageGenericPreview; diff --git a/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewContent.js b/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewContent.js new file mode 100644 index 000000000..67d780a3a --- /dev/null +++ b/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewContent.js @@ -0,0 +1,32 @@ +import React from 'react'; +import { css } from '@emotion/react'; +import useComponentOverrides from '../../theme/useComponentOverrides'; + +const MessageGenericPreviewContent = ({ + className = '', + style = {}, + thumb, + ...props +}) => { + const { classNames, styleOverrides } = useComponentOverrides( + 'MessageGenericPreviewContent' + ); + + const MessageGenericPreviewContentCss = css` + display: flex; + flex-direction: row; + `; + + return ( +
+ {thumb} +
+
+ ); +}; + +export default MessageGenericPreviewContent; diff --git a/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewCoverImage.js b/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewCoverImage.js new file mode 100644 index 000000000..d0e1fe5f6 --- /dev/null +++ b/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewCoverImage.js @@ -0,0 +1,34 @@ +import React from 'react'; +import { css } from '@emotion/react'; +import useComponentOverrides from '../../theme/useComponentOverrides'; + +const MessageGenericPreviewCoverImage = ({ + className = '', + style = {}, + url, + width, + height, + ...props +}) => { + const { classNames, styleOverrides } = useComponentOverrides( + 'MessageGenericPreviewCoverImage' + ); + + const previewCoverImageCss = css` + background-image: url(${url}); + max-width: 100%; + `; + + return ( +
+
+
+ ); +}; + +export default MessageGenericPreviewCoverImage; diff --git a/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewDescription.js b/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewDescription.js new file mode 100644 index 000000000..6725848bf --- /dev/null +++ b/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewDescription.js @@ -0,0 +1,28 @@ +import React from 'react'; +import useComponentOverrides from '../../theme/useComponentOverrides'; + +const MessageGenericPreviewDescription = ({ + children, + clamp = false, + className = '', + style = {}, + ...props +}) => { + const { classNames, styleOverrides } = useComponentOverrides( + 'MessageGenericPreviewDescription' + ); + + return ( +
+ {children} +
+ ); +}; + +export default MessageGenericPreviewDescription; diff --git a/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewFooter.js b/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewFooter.js new file mode 100644 index 000000000..6648be05d --- /dev/null +++ b/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewFooter.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { css } from '@emotion/react'; +import useComponentOverrides from '../../theme/useComponentOverrides'; + +const MessageGenericPreviewFooter = ({ + children, + className = '', + style = {}, + ...props +}) => { + const { classNames, styleOverrides } = useComponentOverrides( + 'MessageGenericPreviewFooter' + ); + const MessageGenericPreviewFooterCss = css` + padding: 0.5rem 0; + `; + + return ( +
+ {children} +
+ ); +}; + +export default MessageGenericPreviewFooter; diff --git a/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewThumb.js b/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewThumb.js new file mode 100644 index 000000000..66a8b1cf4 --- /dev/null +++ b/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewThumb.js @@ -0,0 +1,17 @@ +import React from 'react'; +import useComponentOverrides from '../../theme/useComponentOverrides'; + +const MessageGenericPreviewThumb = (className = '', style = {}, ...props) => { + const { classNames, styleOverrides } = useComponentOverrides( + 'MessageGenericPreviewThumb' + ); + return ( +
+ ); +}; + +export default MessageGenericPreviewThumb; diff --git a/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewTitle.js b/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewTitle.js new file mode 100644 index 000000000..c2980037e --- /dev/null +++ b/packages/react/src/components/MessageGenericPreview/MessageGenericPreviewTitle.js @@ -0,0 +1,40 @@ +import React from 'react'; +import useComponentOverrides from '../../theme/useComponentOverrides'; + +const MessageGenericPreviewTitle = ({ + externalUrl, + children, + className = '', + style = {}, + ...props +}) => { + const { classNames, styleOverrides } = useComponentOverrides( + 'MessageGenericPreviewTitle' + ); + + if (externalUrl) { + return ( + + {children} + + ); + } + return ( + + {children} + + ); +}; + +export default MessageGenericPreviewTitle; diff --git a/packages/react/src/components/MessageGenericPreview/index.js b/packages/react/src/components/MessageGenericPreview/index.js new file mode 100644 index 000000000..07df81c7c --- /dev/null +++ b/packages/react/src/components/MessageGenericPreview/index.js @@ -0,0 +1,7 @@ +export { default as MessageGenericPreview } from './MessageGenericPreview'; +export { default as MessageGenericPreviewCoverImage } from './MessageGenericPreviewCoverImage'; +export { default as MessageGenericPreviewThumb } from './MessageGenericPreviewThumb'; +export { default as MessageGenericPreviewTitle } from './MessageGenericPreviewTitle'; +export { default as MessageGenericPreviewContent } from './MessageGenericPreviewContent'; +export { default as MessageGenericPreviewDescription } from './MessageGenericPreviewDescription'; +export { default as MessageGenericPreviewFooter } from './MessageGenericPreviewFooter'; diff --git a/packages/react/src/components/MultiSelect/MultiSelect.js b/packages/react/src/components/MultiSelect/MultiSelect.js new file mode 100644 index 000000000..bb1b9e070 --- /dev/null +++ b/packages/react/src/components/MultiSelect/MultiSelect.js @@ -0,0 +1,102 @@ +import React, { useState } from 'react'; +import { css, useTheme } from '@emotion/react'; +import PropTypes from 'prop-types'; +import useComponentOverrides from '../../theme/useComponentOverrides'; +import { Box } from '../Box'; + +const MultiSelect = ({ + className = '', + style = {}, + color = 'primary', + options = [], + onChange, + ...props +}) => { + const { classNames, styleOverrides } = useComponentOverrides('MultiSelect'); + const theme = useTheme(); + const [selectedOptions, setSelectedOptions] = useState([]); + + const handleOptionToggle = (value) => { + const isSelected = selectedOptions.includes(value); + if (isSelected) { + setSelectedOptions(selectedOptions.filter((item) => item !== value)); + } else { + setSelectedOptions([...selectedOptions, value]); + } + }; + + const MultiSelectCss = 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; + &:focus { + border-color: ${theme.palette[color].main || 'currentColor'}; + box-shadow: 0px 0px 2.5px ${theme.palette[color].light || 'currentColor'}; + } + `; + + const CheckboxCss = css` + margin-right: 8px; + cursor: pointer; + `; + + return ( + + + {options.map((option) => ( + // eslint-disable-next-line jsx-a11y/label-has-associated-control + + ))} + + + ); +}; + +MultiSelect.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 MultiSelect; diff --git a/packages/react/src/components/MultiSelect/index.js b/packages/react/src/components/MultiSelect/index.js new file mode 100644 index 000000000..7860a30ca --- /dev/null +++ b/packages/react/src/components/MultiSelect/index.js @@ -0,0 +1 @@ +export { default as MultiSelect } from './MultiSelect'; diff --git a/packages/react/src/components/StaticSelect/StaticSelect.js b/packages/react/src/components/StaticSelect/StaticSelect.js new file mode 100644 index 000000000..003f55611 --- /dev/null +++ b/packages/react/src/components/StaticSelect/StaticSelect.js @@ -0,0 +1,88 @@ +import React from 'react'; +import { css, useTheme } from '@emotion/react'; +import PropTypes from 'prop-types'; +import useComponentOverrides from '../../theme/useComponentOverrides'; + +const StaticSelect = ({ + className = '', + style = {}, + color = 'primary', + options = [], + placeholder = '', + onChange, + ...props +}) => { + 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/ContextBlock.Item.js b/packages/react/src/components/uiKit/blocks/ContextBlock.Item.js index ee77575f3..45641507d 100644 --- a/packages/react/src/components/uiKit/blocks/ContextBlock.Item.js +++ b/packages/react/src/components/uiKit/blocks/ContextBlock.Item.js @@ -9,8 +9,9 @@ const Item = ({ block: element, surfaceRenderer: parser, index }) => { useComponentOverrides('ContextBlockItem'); const ContextBlockCss = css` display: inline-block; + padding: 0 0.75rem; font-size: 0.8rem; - color: #ffffff3f; + color: #3d3d3d; margin: -0.25rem; `; const renderedElement = parser.renderContextBlockElement(element, index); diff --git a/packages/react/src/components/uiKit/blocks/ContextBlock.js b/packages/react/src/components/uiKit/blocks/ContextBlock.js index 8eaff8b41..d891693ee 100644 --- a/packages/react/src/components/uiKit/blocks/ContextBlock.js +++ b/packages/react/src/components/uiKit/blocks/ContextBlock.js @@ -30,6 +30,7 @@ const ContextBlock = ({ className, block, surfaceRenderer }) => { > {itemElements.map((element, i) => ( ( -// -// -// {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 }) => ( + + + {isPreviewBlockWithPreview(block) && block.preview?.dimensions && ( + + )} + + + + ) : undefined + } + > + {Array.isArray(block.title) ? ( + + {block.title.map((title, index) => + surfaceRenderer.renderTextObject( + title, + index, + 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); +export default memo(PreviewBlock); diff --git a/packages/react/src/components/uiKit/blocks/UiKitModal.js b/packages/react/src/components/uiKit/blocks/UiKitModal.js deleted file mode 100644 index 7a3929bf7..000000000 --- a/packages/react/src/components/uiKit/blocks/UiKitModal.js +++ /dev/null @@ -1,164 +0,0 @@ -/* 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/MultiStaticSelectElement.js b/packages/react/src/components/uiKit/elements/MultiStaticSelectElement.js index 7d389c847..6a150cd0f 100644 --- a/packages/react/src/components/uiKit/elements/MultiStaticSelectElement.js +++ b/packages/react/src/components/uiKit/elements/MultiStaticSelectElement.js @@ -1,44 +1,39 @@ -// import { MultiSelectFiltered } from '@rocket.chat/fuselage'; -// import React, { memo, useCallback, useMemo } from 'react'; +import React, { memo, useMemo, useCallback } from 'react'; -// import { useUiKitState } from '../hooks/useUiKitState'; -// import { fromTextObjectToString } from '../utils/fromTextObjectToString'; +import { useUiKitState } from '../hooks/useUiKitState'; +import { fromTextObjectToString } from '../utils/fromTextObjectToString'; +import { MultiSelect } from '../../MultiSelect'; -// const MultiStaticSelectElement = ({ block, context, surfaceRenderer }) => { -// const [{ loading, value, error }, action] = useUiKitState(block, context); +const MultiStaticSelectElement = ({ block, context, surfaceRenderer }) => { + const [{ loading }, action] = useUiKitState(block, context); -// const options = useMemo( -// () => -// // eslint-disable-next-line no-shadow -// block.options.map(({ value, text }, i) => [ -// value, -// fromTextObjectToString(surfaceRenderer, text, i) ?? '', -// ]), -// [block.options, surfaceRenderer] -// ); + const options = useMemo( + () => + block.options.map((option, i) => ({ + value: option.value, + label: fromTextObjectToString(surfaceRenderer, option.text, i) ?? '', + })), + [block.options, surfaceRenderer] + ); -// const handleChange = useCallback( -// // eslint-disable-next-line no-shadow -// (value) => { -// action({ target: { value } }); -// }, -// [action] -// ); + const handleChange = useCallback( + (val) => { + action({ target: { val } }); + }, + [action] + ); -// return ( -// -// ); -// }; + return ( + + ); +}; -// export default memo(MultiStaticSelectElement); +export default memo(MultiStaticSelectElement); diff --git a/packages/react/src/components/uiKit/elements/OverflowElement.js b/packages/react/src/components/uiKit/elements/OverflowElement.js index 66c085813..462ae212d 100644 --- a/packages/react/src/components/uiKit/elements/OverflowElement.js +++ b/packages/react/src/components/uiKit/elements/OverflowElement.js @@ -1,83 +1,44 @@ -// import { -// IconButton, -// PositionAnimated, -// Options, -// useCursor, -// } from '@rocket.chat/fuselage'; -// import React, { useRef, useCallback, useMemo } from 'react'; - -// import { useUiKitState } from '../hooks/useUiKitState'; -// import { fromTextObjectToString } from '../utils/fromTextObjectToString'; - -// const OverflowElement = ({ block, context, surfaceRenderer }) => { -// const [{ loading }, action] = useUiKitState(block, context); - -// const fireChange = useCallback( -// ([value]) => action({ target: { value } }), -// [action] -// ); - -// const options = useMemo( -// () => -// block.options.map(({ value, text, url }, i) => [ -// value, -// fromTextObjectToString(surfaceRenderer, text, i) ?? '', -// undefined, -// undefined, -// undefined, -// url, -// ]), -// [block.options, surfaceRenderer] -// ); - -// const [cursor, handleKeyDown, handleKeyUp, reset, [visible, hide, show]] = -// // eslint-disable-next-line no-shadow -// useCursor(-1, options, (selectedOption, [, hide]) => { -// fireChange([selectedOption[0], selectedOption[1]]); -// reset(); -// hide(); -// }); - -// const ref = useRef(null); -// const onClick = useCallback(() => { -// ref.current?.focus(); -// show(); -// }, [show]); - -// const handleSelection = useCallback( -// ([value, _label, _selected, _type, url]) => { -// if (url) { -// window.open(url); -// } -// action({ target: { value: String(value) } }); -// reset(); -// hide(); -// }, -// [action, hide, reset] -// ); - -// return ( -// <> -// -// -// -// -// -// ); -// }; - -// export default OverflowElement; +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); 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, value, error }, action] = useUiKitState(block, context); +const StaticSelectElement = ({ block, context, surfaceRenderer }) => { + const [{ loading }, action] = useUiKitState(block, context); -// const options = useMemo( -// () => -// block.options.map((option, i) => [ -// option.value, -// fromTextObjectToString(surfaceRenderer, option.text, i) ?? '', -// ]), -// [block.options, surfaceRenderer] -// ); + const options = useMemo( + () => + block.options.map((option, i) => ({ + value: option.value, + label: fromTextObjectToString(surfaceRenderer, option.text, i) ?? '', + })), + [block.options, surfaceRenderer] + ); -// const handleChange = useCallback( -// // eslint-disable-next-line no-shadow -// (value) => { -// action({ target: { value } }); -// }, -// [action] -// ); + const handleChange = useCallback( + (val) => { + action({ target: { val } }); + }, + [action] + ); -// return ( -// -// ); -// }; + return ( + + ); +}; -// export default memo(StaticSelectElement); +export default memo(StaticSelectElement); diff --git a/packages/react/src/components/uiKit/surfaces/FuselageSurfaceRenderer.js b/packages/react/src/components/uiKit/surfaces/FuselageSurfaceRenderer.js index 12fabb478..a301ba51a 100644 --- a/packages/react/src/components/uiKit/surfaces/FuselageSurfaceRenderer.js +++ b/packages/react/src/components/uiKit/surfaces/FuselageSurfaceRenderer.js @@ -6,16 +6,16 @@ import ContextBlock from '../blocks/ContextBlock'; import DividerBlock from '../blocks/DividerBlock'; import ImageBlock from '../blocks/ImageBlock'; import InputBlock from '../blocks/InputBlock'; -// import PreviewBlock from '../blocks/PreviewBlock'; +import PreviewBlock from '../blocks/PreviewBlock'; import SectionBlock from '../blocks/SectionBlock'; import ButtonElement from '../elements/ButtonElement'; 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 MultiStaticSelectElement from '../elements/MultiStaticSelectElement'; +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 { @@ -79,18 +79,16 @@ export class FuselageSurfaceRenderer extends UiKit.SurfaceRenderer { if (context !== UiKit.BlockContext.BLOCK) { return null; } - return null; - // TODO: Implement this without fuselage. - // return ( - // - // ); + return ( + + ); } context(block, context, index) { @@ -218,17 +216,15 @@ export class FuselageSurfaceRenderer extends UiKit.SurfaceRenderer { return null; } - return null; - // implement this without fuselage - // return ( - // - // ); + return ( + + ); } multi_static_select(block, context, index) { @@ -236,17 +232,15 @@ export class FuselageSurfaceRenderer extends UiKit.SurfaceRenderer { return null; } - return null; - // implement this without fuselage - // return ( - // - // ); + return ( + + ); } overflow(block, context, index) { @@ -254,17 +248,15 @@ export class FuselageSurfaceRenderer extends UiKit.SurfaceRenderer { return null; } - return null; - // implement this without fuselage - // return ( - // - // ); + return ( + + ); } plain_text_input(block, context, index) { diff --git a/packages/react/src/components/uiKit/surfaces/ModalSurface.js b/packages/react/src/components/uiKit/surfaces/ModalSurface.js index b7be565b5..865619588 100644 --- a/packages/react/src/components/uiKit/surfaces/ModalSurface.js +++ b/packages/react/src/components/uiKit/surfaces/ModalSurface.js @@ -4,7 +4,16 @@ import { Box } from '../../Box'; const ModalSurface = ({ children }) => ( - {children} + + {children} + ); diff --git a/packages/react/tools/icons-generator.js b/packages/react/tools/icons-generator.js index 12d55a300..710904c97 100644 --- a/packages/react/tools/icons-generator.js +++ b/packages/react/tools/icons-generator.js @@ -41,6 +41,7 @@ const iconsList = [ 'error-circle', 'chevron-down', 'chevron-left', + 'key', ]; const svgDirPath = path.join( __dirname,