From de7afad5b00adb83ab7549d36db0a2be652f0f9c Mon Sep 17 00:00:00 2001 From: Balazs Bajorics <2226774+balazsbajorics@users.noreply.github.com> Date: Thu, 13 Jun 2024 23:34:30 +0200 Subject: [PATCH] Short Cartouches (#5925) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Problem:** The cartouches in the navigator and the inspector don't currently have a max width and they can be overlong. **Fix:** For property and element accessors, only show the last bit. image image image **Commit Details:** - Added `shortLabel` to `getTextContentOfElement` - If the DataReferenceCartouche has a non-null shortLabel, it is used - The tooltip always shows the long label **Bonus** The PR also changes when do we hide the cartouche icon – the new ruleset only hides the cartouche icon for inline value literals such as `myProp="value"` and `
{'myValue'}
` --- .../component-section/cartouche-control.tsx | 9 +++- .../component-section/cartouche-ui.tsx | 15 ++---- .../component-section-children.tsx | 4 +- .../component-section/component-section.tsx | 5 +- .../data-reference-cartouche.tsx | 53 ++++++++++++------- .../data-selector-cartouche.tsx | 7 ++- .../navigator-condensed-entry.tsx | 1 - 7 files changed, 55 insertions(+), 39 deletions(-) diff --git a/editor/src/components/inspector/sections/component-section/cartouche-control.tsx b/editor/src/components/inspector/sections/component-section/cartouche-control.tsx index b8dc71b89fba..725643c4285f 100644 --- a/editor/src/components/inspector/sections/component-section/cartouche-control.tsx +++ b/editor/src/components/inspector/sections/component-section/cartouche-control.tsx @@ -2,6 +2,7 @@ /** @jsx jsx */ import React from 'react' import { jsx } from '@emotion/react' +import type { DataReferenceCartoucheContentType } from './data-reference-cartouche' import { DataCartoucheInner } from './data-reference-cartouche' import { NO_OP } from '../../../../core/shared/utils' import type { ElementPath, PropertyPath } from '../../../../core/shared/project-file-types' @@ -12,7 +13,11 @@ import type { CartoucheDataType } from './cartouche-ui' import { useColorTheme } from '../../../../uuiui' interface IdentifierExpressionCartoucheControlProps { - contents: string + contents: { + type: DataReferenceCartoucheContentType + label: string | null + shortLabel: string | null + } icon: React.ReactChild matchType: 'full' | 'partial' onOpenDataPicker: () => void @@ -42,7 +47,7 @@ export const IdentifierExpressionCartoucheControl = React.memo( return ( - {source === 'literal' ? null : ( + {source === 'inline-literal' ? null : ( {/* this div prevents the popup form putting padding into the condensed rows */} @@ -170,16 +168,20 @@ export const DataReferenceCartoucheControl = React.memo( }, ) +export type DataReferenceCartoucheContentType = 'value-literal' | 'object-literal' | 'reference' interface DataCartoucheInnerProps { onClick: (e: React.MouseEvent) => void onDoubleClick: (e: React.MouseEvent) => void selected: boolean - contentsToDisplay: { type: 'literal' | 'reference'; label: string | null } + contentsToDisplay: { + type: DataReferenceCartoucheContentType + label: string | null + shortLabel: string | null + } safeToDelete: boolean onDelete: () => void testId: string contentIsComingFromServer: boolean - hideTooltip?: boolean datatype: CartoucheDataType highlight?: CartoucheHighlight | null badge?: React.ReactNode @@ -211,8 +213,10 @@ export const DataCartoucheInner = React.forwardRef( const onDelete = safeToDelete ? onDeleteInner : undefined const source: CartoucheUIProps['source'] = - contentsToDisplay.type === 'literal' - ? 'literal' + contentsToDisplay.type === 'value-literal' + ? 'inline-literal' + : contentsToDisplay.type === 'object-literal' + ? 'internal' : contentIsComingFromServer ? 'external' : 'internal' @@ -226,13 +230,13 @@ export const DataCartoucheInner = React.forwardRef( selected={selected} highlight={highlight} testId={testId} - tooltip={!props.hideTooltip ? contentsToDisplay.label ?? 'DATA' : null} + tooltip={contentsToDisplay.label ?? contentsToDisplay.shortLabel ?? 'DATA'} role='selection' source={source} ref={ref} badge={props.badge} > - {contentsToDisplay.label ?? 'DATA'} + {contentsToDisplay.shortLabel ?? contentsToDisplay.label ?? 'DATA'} ) }, @@ -241,46 +245,55 @@ export const DataCartoucheInner = React.forwardRef( export function getTextContentOfElement( element: JSXElementChild, metadata: ElementInstanceMetadata | null, -): { type: 'literal' | 'reference'; label: string | null } { +): { + type: DataReferenceCartoucheContentType + label: string | null + shortLabel: string | null +} { switch (element.type) { case 'ATTRIBUTE_VALUE': - return { type: 'literal', label: `${JSON.stringify(element.value)}` } + return { type: 'value-literal', label: `${JSON.stringify(element.value)}`, shortLabel: null } case 'JSX_TEXT_BLOCK': - return { type: 'literal', label: element.text.trim() } + return { type: 'value-literal', label: element.text.trim(), shortLabel: null } case 'JS_IDENTIFIER': - return { type: 'reference', label: element.name.trim() } + return { type: 'reference', label: element.name.trim(), shortLabel: null } case 'JS_ELEMENT_ACCESS': return { type: 'reference', label: `${getTextContentOfElement(element.onValue, null).label}[${ getTextContentOfElement(element.element, null).label }]`, + shortLabel: `${TruncationPrefix}${getTextContentOfElement(element.element, null).label}`, } case 'JS_PROPERTY_ACCESS': return { type: 'reference', label: `${getTextContentOfElement(element.onValue, null).label}.${element.property}`, + shortLabel: `${TruncationPrefix}${element.property}`, } case 'ATTRIBUTE_FUNCTION_CALL': - return { type: 'reference', label: `${element.functionName}(...` } + return { type: 'reference', label: `${element.functionName}(...`, shortLabel: null } case 'JSX_ELEMENT': return { - type: 'literal', + type: 'object-literal', label: metadata?.textContent ?? `${getJSXElementNameLastPart(element.name)}`, + shortLabel: null, } case 'ATTRIBUTE_NESTED_ARRAY': - return { type: 'literal', label: '[...]' } + return { type: 'object-literal', label: '[...]', shortLabel: null } case 'ATTRIBUTE_NESTED_OBJECT': - return { type: 'literal', label: '{...}' } + return { type: 'object-literal', label: '{...}', shortLabel: null } case 'JSX_MAP_EXPRESSION': - return { type: 'literal', label: 'List' } + return { type: 'object-literal', label: 'List', shortLabel: null } case 'JSX_CONDITIONAL_EXPRESSION': - return { type: 'literal', label: 'Conditional' } + return { type: 'object-literal', label: 'Conditional', shortLabel: null } case 'ATTRIBUTE_OTHER_JAVASCRIPT': - return { type: 'literal', label: element.originalJavascript } + return { type: 'object-literal', label: element.originalJavascript, shortLabel: null } case 'JSX_FRAGMENT': - return { type: 'literal', label: 'Fragment' } + return { type: 'object-literal', label: 'Fragment', shortLabel: null } default: assertNever(element) } } + +const TruncationPrefix = `…` diff --git a/editor/src/components/inspector/sections/component-section/data-selector-cartouche.tsx b/editor/src/components/inspector/sections/component-section/data-selector-cartouche.tsx index e3b82e694d80..78ecb262cf3b 100644 --- a/editor/src/components/inspector/sections/component-section/data-selector-cartouche.tsx +++ b/editor/src/components/inspector/sections/component-section/data-selector-cartouche.tsx @@ -26,6 +26,7 @@ export const DataPickerCartouche = React.memo( return ( { @@ -77,7 +80,7 @@ export function useVariableDataSource(variable: DataPickerOption | null) { return 'external' case 'literal-attribute': case 'literal-assignment': - return 'literal' + return 'literal-assignment' case 'component-prop': case 'element-at-scope': case 'failed': diff --git a/editor/src/components/navigator/navigator-item/navigator-condensed-entry.tsx b/editor/src/components/navigator/navigator-item/navigator-condensed-entry.tsx index 16ba8ea481cc..60f9e0afce4e 100644 --- a/editor/src/components/navigator/navigator-item/navigator-condensed-entry.tsx +++ b/editor/src/components/navigator/navigator-item/navigator-condensed-entry.tsx @@ -426,7 +426,6 @@ const CondensedEntryItemContent = React.memo( highlight={ props.rowRootSelected ? 'strong' : props.wholeRowInsideSelection ? 'subtle' : null } - hideTooltip={true} />, )}