From 05dcff85a605b28d3a5886914c91663a378789d0 Mon Sep 17 00:00:00 2001 From: David Drazic Date: Mon, 24 Apr 2023 12:56:44 +0200 Subject: [PATCH] [FLASK] Fix text selection bug in snap ui (#18719) * Fix text selection bug in snap ui * Fix template mapping calls in other places * Fix template mapping calls in snap-prompt --- .../snap-ui-renderer/snap-ui-renderer.js | 21 +++++++++++-------- .../templates/flask/snap-alert/snap-alert.js | 3 ++- .../snap-confirmation/snap-confirmation.js | 3 ++- .../flask/snap-prompt/snap-prompt.js | 3 ++- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/ui/components/app/flask/snap-ui-renderer/snap-ui-renderer.js b/ui/components/app/flask/snap-ui-renderer/snap-ui-renderer.js index 20197923f..4a30ff8fa 100644 --- a/ui/components/app/flask/snap-ui-renderer/snap-ui-renderer.js +++ b/ui/components/app/flask/snap-ui-renderer/snap-ui-renderer.js @@ -1,6 +1,5 @@ import React from 'react'; import PropTypes from 'prop-types'; -import nanoid from 'nanoid'; import { isComponent } from '@metamask/snaps-ui'; import { useSelector } from 'react-redux'; import MetaMaskTemplateRenderer from '../../metamask-template-renderer/metamask-template-renderer'; @@ -22,10 +21,12 @@ import { Copyable } from '../copyable'; import { DelineatorType } from '../../../../helpers/constants/flask'; export const UI_MAPPING = { - panel: (props) => ({ + panel: (props, elementKey) => ({ element: 'Box', - // eslint-disable-next-line no-use-before-define - children: props.children.map(mapToTemplate), + children: props.children.map((element) => + // eslint-disable-next-line no-use-before-define + mapToTemplate(element, elementKey), + ), props: { display: DISPLAY.FLEX, flexDirection: FLEX_DIRECTION.COLUMN, @@ -66,11 +67,12 @@ export const UI_MAPPING = { }; // TODO: Stop exporting this when we remove the mapToTemplate hack in confirmation templates. -export const mapToTemplate = (data) => { +export const mapToTemplate = (data, elementKeyIndex) => { const { type } = data; - const mapped = UI_MAPPING[type](data); - // TODO: We may want to have deterministic keys at some point - return { ...mapped, key: nanoid() }; + elementKeyIndex.value += 1; + const indexKey = `snap_ui_element_${type}__${elementKeyIndex.value}`; + const mapped = UI_MAPPING[type](data, elementKeyIndex); + return { ...mapped, key: indexKey }; }; // Component that maps Snaps UI JSON format to MetaMask Template Renderer format @@ -97,7 +99,8 @@ export const SnapUIRenderer = ({ ); } - const sections = mapToTemplate(data); + const elementKeyIndex = { value: 0 }; + const sections = mapToTemplate(data, elementKeyIndex); return ( diff --git a/ui/pages/confirmation/templates/flask/snap-alert/snap-alert.js b/ui/pages/confirmation/templates/flask/snap-alert/snap-alert.js index f4b39dbc0..a3595c343 100644 --- a/ui/pages/confirmation/templates/flask/snap-alert/snap-alert.js +++ b/ui/pages/confirmation/templates/flask/snap-alert/snap-alert.js @@ -6,6 +6,7 @@ function getValues(pendingApproval, t, actions) { snapName, requestData: { content }, } = pendingApproval; + const elementKeyIndex = { value: 0 }; return { content: [ @@ -24,7 +25,7 @@ function getValues(pendingApproval, t, actions) { snapName, }, // TODO: Replace with SnapUIRenderer when we don't need to inject the input manually. - children: mapToTemplate(content), + children: mapToTemplate(content, elementKeyIndex), }, }, ], diff --git a/ui/pages/confirmation/templates/flask/snap-confirmation/snap-confirmation.js b/ui/pages/confirmation/templates/flask/snap-confirmation/snap-confirmation.js index 6b7d71b2a..bf50923d2 100644 --- a/ui/pages/confirmation/templates/flask/snap-confirmation/snap-confirmation.js +++ b/ui/pages/confirmation/templates/flask/snap-confirmation/snap-confirmation.js @@ -6,6 +6,7 @@ function getValues(pendingApproval, t, actions) { snapName, requestData: { content }, } = pendingApproval; + const elementKeyIndex = { value: 0 }; return { content: [ @@ -24,7 +25,7 @@ function getValues(pendingApproval, t, actions) { snapName, }, // TODO: Replace with SnapUIRenderer when we don't need to inject the input manually. - children: mapToTemplate(content), + children: mapToTemplate(content, elementKeyIndex), }, }, ], diff --git a/ui/pages/confirmation/templates/flask/snap-prompt/snap-prompt.js b/ui/pages/confirmation/templates/flask/snap-prompt/snap-prompt.js index b54db0e03..ef9d5de48 100644 --- a/ui/pages/confirmation/templates/flask/snap-prompt/snap-prompt.js +++ b/ui/pages/confirmation/templates/flask/snap-prompt/snap-prompt.js @@ -7,6 +7,7 @@ function getValues(pendingApproval, t, actions, _history, setInputState) { snapName, requestData: { content, placeholder }, } = pendingApproval; + const elementKeyIndex = { value: 0 }; return { content: [ @@ -26,7 +27,7 @@ function getValues(pendingApproval, t, actions, _history, setInputState) { }, children: [ // TODO: Replace with SnapUIRenderer when we don't need to inject the input manually. - mapToTemplate(content), + mapToTemplate(content, elementKeyIndex), { element: 'div', key: 'snap-prompt-container',