Skip to content

Commit

Permalink
Unified Data Cartouches (#5575)
Browse files Browse the repository at this point in the history
* unifying the cartouches

* ooops

* splitting out MapListSourceCartouche to be reused in the navigator

* putting the MapListSourceCartouche in the navigator

* fixing textTransform on the cartouche

* moving textTransform down

* Update data-reference-cartouche.tsx

* inversion!

* shorter cartouche!

* updating snapshots

* fixing border color to always be blue for selection

* removing unused imports
  • Loading branch information
balazsbajorics authored May 6, 2024
1 parent add2b5c commit 0d38f63
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 168 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,84 +2,33 @@ import React from 'react'
import { when } from '../../../../utils/react-conditionals'
import { FlexRow, Icn, Tooltip, colorTheme } from '../../../../uuiui'
import { stopPropagation } from '../../common/inspector-utils'
import { DataCartoucheInner } from './data-reference-cartouche'
import { NO_OP } from '../../../../core/shared/utils'

interface IdentifierExpressionCartoucheControlProps {
contents: string
icon: React.ReactChild
matchType: 'full' | 'partial' | 'none'
matchType: 'full' | 'partial'
onOpenDataPicker: () => void
onDeleteCartouche: () => void
safeToDelete: boolean
testId: string
}
export const IdentifierExpressionCartoucheControl = React.memo(
(props: IdentifierExpressionCartoucheControlProps) => {
const { onDeleteCartouche, testId, safeToDelete } = props
const onDelete = React.useCallback<React.MouseEventHandler<HTMLDivElement>>(
(e) => {
stopPropagation(e)
onDeleteCartouche()
},
[onDeleteCartouche],
)
const { onOpenDataPicker, onDeleteCartouche, testId, safeToDelete } = props

return (
<FlexRow
style={{
cursor: 'pointer',
fontSize: 10,
color:
props.matchType === 'full'
? colorTheme.white.value
: colorTheme.neutralForeground.value,
backgroundColor:
props.matchType === 'full'
? colorTheme.primary.value
: props.matchType === 'partial'
? colorTheme.primary10.value
: colorTheme.bg4.value,
padding: '0px 4px',
borderRadius: 4,
height: 22,
display: 'flex',
flex: 1,
gap: 2,
}}
onClick={props.onOpenDataPicker}
>
{props.icon}
<Tooltip title={props.contents}>
<div
style={{
flex: 1,
/* Standard CSS ellipsis */
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',

/* Beginning of string */
direction: 'rtl', // TODO we need a better way to ellipsize the beginnign because rtl eats ' " marks
textAlign: 'left',
}}
>
{props.contents}
&lrm;
{/* the &lrm; non-printing character is added to fix the punctuation marks disappearing because of direction: rtl */}
</div>
</Tooltip>
{when(
safeToDelete,
<Icn
category='semantic'
type='cross-medium'
color='on-highlight-main'
width={16}
height={16}
data-testid={`delete-${testId}`}
onClick={onDelete}
/>,
)}
</FlexRow>
<DataCartoucheInner
contentsToDisplay={{ label: props.contents, type: 'reference' }}
onClick={onOpenDataPicker}
selected={false}
onDoubleClick={NO_OP}
safeToDelete={safeToDelete}
onDelete={onDeleteCartouche}
testId={testId}
inverted={false}
/>
)
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import type {
import { getJSXElementNameLastPart } from '../../../../core/shared/element-template'
import type { ElementPath } from '../../../../core/shared/project-file-types'
import * as PP from '../../../../core/shared/property-path'
import { assertNever } from '../../../../core/shared/utils'
import { NO_OP, assertNever } from '../../../../core/shared/utils'
import { FlexRow, Icn, Icons, Tooltip, UtopiaStyles, colorTheme } from '../../../../uuiui'
import { Substores, useEditorState } from '../../../editor/store/store-hook'
import { IdentifierExpressionCartoucheControl } from './cartouche-control'
import { useDataPickerButton } from './component-section'
import { useDispatch } from '../../../editor/store/dispatch-context'
import { selectComponents } from '../../../editor/actions/meta-actions'
import { when } from '../../../../utils/react-conditionals'

interface DataReferenceCartoucheControlProps {
elementPath: ElementPath
Expand Down Expand Up @@ -62,29 +62,62 @@ export const DataReferenceCartoucheControl = React.memo(
onDoubleClick={dataPickerButtonData.openPopup}
contentsToDisplay={contentsToDisplay}
selected={selected}
safeToDelete={false}
inverted={false}
onDelete={NO_OP}
testId={`data-reference-cartouche-${EP.toString(elementPath)}`}
/>
</>
)
},
)

interface DataCartoucheInnerProps {
onClick: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void
onDoubleClick: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void
selected: boolean
inverted: boolean
contentsToDisplay: { type: 'literal' | 'reference'; label: string | null }
safeToDelete: boolean
onDelete: () => void
testId: string
}

export const DataCartoucheInner = React.forwardRef(
(
props: {
onClick: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void
onDoubleClick: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void
selected: boolean
contentsToDisplay: { type: 'literal' | 'reference'; label: string | null }
},
ref: React.Ref<HTMLDivElement>,
) => {
const { onClick, onDoubleClick, selected, contentsToDisplay } = props

const cartoucheIconColor = contentsToDisplay.type === 'reference' ? 'primary' : 'secondary'
const foregroundColor =
contentsToDisplay.type === 'reference'
? colorTheme.primary.value
: colorTheme.neutralForeground.value
(props: DataCartoucheInnerProps, ref: React.Ref<HTMLDivElement>) => {
const {
onClick,
onDoubleClick,
safeToDelete,
onDelete,
selected,
inverted,
contentsToDisplay,
} = props

const onDeleteInner = React.useCallback(
(e: React.MouseEvent) => {
e.stopPropagation()
onDelete()
},
[onDelete],
)

const cartoucheIconColor = inverted
? 'on-highlight-main'
: contentsToDisplay.type === 'reference'
? 'primary'
: 'secondary'

const borderColor = inverted
? colorTheme.neutralInvertedBackground.value
: colorTheme.primary.value

const foregroundColor = inverted
? colorTheme.neutralInvertedForeground.value
: contentsToDisplay.type === 'reference'
? colorTheme.primary.value
: colorTheme.neutralForeground.value
const backgroundColor =
contentsToDisplay.type === 'reference' ? colorTheme.primary10.value : colorTheme.bg4.value

Expand All @@ -105,10 +138,10 @@ export const DataCartoucheInner = React.forwardRef(
fontSize: 10,
color: foregroundColor,
backgroundColor: backgroundColor,
border: selected ? '1px solid ' + colorTheme.primary.value : '1px solid transparent',
border: selected ? '1px solid ' + borderColor : '1px solid transparent',
padding: '0px 4px',
borderRadius: 4,
height: 22,
height: 20,
display: 'flex',
flex: 1,
gap: 4,
Expand Down Expand Up @@ -140,6 +173,18 @@ export const DataCartoucheInner = React.forwardRef(
{/* the &lrm; non-printing character is added to fix the punctuation marks disappearing because of direction: rtl */}
</div>
</Tooltip>
{when(
safeToDelete,
<Icn
category='semantic'
type='cross-medium'
color={cartoucheIconColor}
width={16}
height={16}
data-testid={`delete-${props.testId}`}
onClick={onDeleteInner}
/>,
)}
</FlexRow>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ import {
} from '../component-section/data-reference-cartouche'
import { JSXPropertyControlForListSection } from '../component-section/property-control-controls'
import { useVariablesInScopeForSelectedElement } from '../component-section/variables-in-scope-utils'
import { MapListSourceCartouche } from './list-source-cartouche'

type MapExpression = JSXMapExpression | 'multiselect' | 'not-a-mapexpression'

const mapExpressionValueToMapSelector = createCachedSelector(
export const mapExpressionValueToMapSelector = createCachedSelector(
(store: MetadataSubstate) => store.editor.jsxMetadata,
(_store: MetadataSubstate, paths: ElementPath[]) => paths,
(jsxMetadata: ElementInstanceMetadataMap, paths: ElementPath[]): MapExpression => {
Expand Down Expand Up @@ -89,7 +90,7 @@ function getMapExpressionMetadata(

export const ListSectionTestId = 'list-section'

function useDataPickerButton(selectedElements: Array<ElementPath>) {
export function useDataPickerButtonListSource(selectedElements: Array<ElementPath>) {
const [referenceElement, setReferenceElement] = React.useState<HTMLDivElement | null>(null)
const [popperElement, setPopperElement] = React.useState<HTMLDivElement | null>(null)
const popper = usePopper(referenceElement, popperElement, {
Expand Down Expand Up @@ -172,6 +173,7 @@ function useDataPickerButton(selectedElements: Array<ElementPath>) {
}

export const ListSection = React.memo(({ paths }: { paths: ElementPath[] }) => {
const target = paths.at(0)
const colorTheme = useColorTheme()

const originalMapExpression = useEditorState(
Expand All @@ -180,26 +182,10 @@ export const ListSection = React.memo(({ paths }: { paths: ElementPath[] }) => {
'ConditionalSection condition expression',
)

const metadataForElement = useEditorState(
Substores.metadata,
(store) => MetadataUtils.findElementByElementPath(store.editor.jsxMetadata, paths.at(0)),
'ConditionalSection metadata',
)

const controlDescription: ArrayControlDescription = {
control: 'array',
propertyControl: {
control: 'none',
},
}

const { popupIsOpen, DataPickerOpener, DataPickerComponent, setReferenceElement, openPopup } =
useDataPickerButton(paths)

const mappedRootElementToDisplay = useEditorState(
Substores.metadata,
(store) => {
const path = paths.at(0)
const path = target
const elementMetadata: ElementInstanceMetadata | null | undefined =
path == null
? null
Expand All @@ -216,15 +202,14 @@ export const ListSection = React.memo(({ paths }: { paths: ElementPath[] }) => {
'ConditionalSection mappedRootElement',
)

if (originalMapExpression === 'multiselect' || originalMapExpression === 'not-a-mapexpression') {
if (
originalMapExpression === 'multiselect' ||
originalMapExpression === 'not-a-mapexpression' ||
target == null
) {
return null
}

const contentsToDisplay = getTextContentOfElement(
originalMapExpression.valueToMap,
metadataForElement,
)

return (
<div style={{ paddingBottom: 8 }} data-testid={ListSectionTestId}>
<FlexRow
Expand Down Expand Up @@ -253,29 +238,18 @@ export const ListSection = React.memo(({ paths }: { paths: ElementPath[] }) => {
<span>List</span>
</FlexRow>
</FlexRow>
{popupIsOpen ? DataPickerComponent : null}
<UIGridRow
padded={false}
style={{ paddingLeft: 8, paddingRight: 8, paddingTop: 3, paddingBottom: 3 }}
variant='<--1fr--><--1fr-->|-18px-|'
>
List Source
<div
style={{
display: 'flex',
flexDirection: 'row',
minWidth: 0,
}}
ref={setReferenceElement}
>
<DataCartoucheInner
contentsToDisplay={contentsToDisplay}
onClick={openPopup}
onDoubleClick={NO_OP}
selected={false}
/>
</div>
{DataPickerOpener}
<MapListSourceCartouche
target={target}
openOn='single-click'
inverted={false}
selected={false}
/>
</UIGridRow>
<UIGridRow
padded={false}
Expand All @@ -289,7 +263,6 @@ export const ListSection = React.memo(({ paths }: { paths: ElementPath[] }) => {
flexDirection: 'row',
minWidth: 0,
}}
ref={setReferenceElement}
>
<JSXPropertyControlForListSection
value={
Expand Down
Loading

0 comments on commit 0d38f63

Please sign in to comment.