Skip to content

Commit

Permalink
Remix nav items (#4249)
Browse files Browse the repository at this point in the history
* aqua10 and remixItemType

* link has background

* lock/eye buttons cover nav items with lozenge background;

* attempt at isDescendantOfOutlet

* show link target

* path for outlet

* add remixItemType to other ItemLabel instance

* color variables for legibility

* adjust test to confirm outlet row shows path

* delete comments

* adjust lock/eye background not to cover target parent outline

* color inside outlet

* drop target lines and target parent outline aqua when inside outlet

* findAmongAncestorsOfPath

* refactor to use findAmongAncestorsOfPath

* no background for links, outlet says outlet: ~

* new link icons

* Update editor/src/uuiui/styles/theme/light.ts

Co-authored-by: RheeseyB <[email protected]>

* update tests

---------

Co-authored-by: Berci Kormendy <[email protected]>
Co-authored-by: RheeseyB <[email protected]>
  • Loading branch information
3 people authored Oct 3, 2023
1 parent 7cb9001 commit 504083e
Show file tree
Hide file tree
Showing 25 changed files with 187 additions and 28 deletions.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified editor/resources/editor/icons/light/component/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ describe('Remix navigator', () => {
expect(navigatorItemElement.style.color).toEqual('var(--utopitheme-fg0)')
})

it('Remix Outlet navigator item label contains route component name', async () => {
it('Remix Outlet navigator item label contains the suffix of the full path', async () => {
const project = createModifiedProject({
[StoryboardFilePath]: `import * as React from 'react'
import { RemixScene, Storyboard } from 'utopia-api'
Expand Down Expand Up @@ -277,7 +277,7 @@ describe('Remix navigator', () => {
),
),
)
expect(outletItemElement.textContent).toEqual('Outlet: Index')
expect(outletItemElement.textContent).toEqual('Outlet: (home)')
})
})
describe('Reparenting in Remix projects in the navigator', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ interface RemixNavigationContext {
entries: Array<Location>
}

interface RemixNavigationAtomData {
export interface RemixNavigationAtomData {
[pathString: string]: RemixNavigationContext | undefined
}

Expand Down
1 change: 1 addition & 0 deletions editor/src/components/navigator/navigator-drag-layer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export const NavigatorDragLayer = React.memo(() => {
selected={selected}
dispatch={NO_OP}
inputVisible={false}
remixItemType={'none'}
/>
</FlexRow>
</FlexRow>
Expand Down
59 changes: 51 additions & 8 deletions editor/src/components/navigator/navigator-item/item-label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,18 @@ import {
getConditionalFlag,
} from '../../../core/model/conditionals'
import { colorTheme, flexRowStyle, StringInput } from '../../../uuiui'
import type { EditorDispatch } from '../../editor/action-types'
import type { EditorDispatch, ElementPaste } from '../../editor/action-types'
import * as EditorActions from '../../editor/actions/action-creators'
import { Substores, useEditorState } from '../../editor/store/store-hook'
import { renameComponent } from '../actions'
import type { RemixItemType } from './navigator-item'
import { NavigatorItemTestId } from './navigator-item'
import { useAtom } from 'jotai'
import type { RemixNavigationAtomData } from '../../canvas/remix/utopia-remix-root-component'
import { RemixNavigationAtom } from '../../canvas/remix/utopia-remix-root-component'
import * as EP from '../../../core/shared/element-path'
import type { ElementPath } from '../../../core/shared/project-file-types'
import type { Location } from 'react-router'

export function itemLabelTestIdForEntry(navigatorEntry: NavigatorEntry): string {
return `${NavigatorItemTestId(varSafeNavigatorEntryToKey(navigatorEntry))}-label`
Expand All @@ -33,6 +40,7 @@ interface ItemLabelProps {
suffix?: string
inputVisible: boolean
style?: CSSProperties
remixItemType: RemixItemType
}

export const ItemLabel = React.memo((props: ItemLabelProps) => {
Expand Down Expand Up @@ -87,9 +95,35 @@ export const ItemLabel = React.memo((props: ItemLabelProps) => {
}
}, [inputVisible, testId])

const value = React.useMemo(() => {
return suffix == null ? name : `${name} ${suffix}`
}, [suffix, name])
const maybeLinkTarget = useEditorState(
Substores.metadata,
(store) => {
if (props.remixItemType !== 'link') {
return null
}
return store.editor.allElementProps[EP.toString(props.target.elementPath)]?.['to'] ?? null
},
'ItemLabel maybeLinkTarget',
)

const [remixNavigationData] = useAtom(RemixNavigationAtom)

const maybePathForOutlet = React.useMemo(() => {
if (props.remixItemType !== 'outlet') {
return null
}
return remixSceneLocationFromOutletPath(props.target.elementPath, remixNavigationData)?.pathname
}, [props.remixItemType, props.target.elementPath, remixNavigationData])

const label = React.useMemo(() => {
if (maybeLinkTarget != null) {
return maybeLinkTarget
}
if (maybePathForOutlet != null) {
return maybePathForOutlet === '/' ? 'Outlet: (home)' : `Outlet: ${maybePathForOutlet}`
}
return suffix == null ? name : `Outlet: ${name} ${suffix}`
}, [maybeLinkTarget, maybePathForOutlet, suffix, name])

const cancelRename = React.useCallback(() => {
setName(name)
Expand Down Expand Up @@ -225,9 +259,7 @@ export const ItemLabel = React.memo((props: ItemLabelProps) => {
key='item-label'
data-testid={itemLabelTestIdForEntry(target)}
style={{
backgroundColor: 'transparent',
paddingTop: 3,
paddingBottom: 3,
padding: '3px 0px',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
Expand All @@ -245,9 +277,20 @@ export const ItemLabel = React.memo((props: ItemLabelProps) => {
}
}}
>
{value}
{label}
</div>
)}
</div>
)
})

// here
function remixSceneLocationFromOutletPath(
outletPath: ElementPath,
remixNavigationData: RemixNavigationAtomData,
): Location | null {
return EP.findAmongAncestorsOfPath(
outletPath,
(p) => remixNavigationData[EP.toString(p)]?.location ?? null,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@ import type { SelectionLocked } from '../../canvas/canvas-types'

export const NavigatorHintCircleDiameter = 8

const outletAwareBackgroundColor = (
colorTheme: ReturnType<typeof useColorTheme>,
isOutlet: boolean,
) => (isOutlet ? colorTheme.aqua.value : colorTheme.navigatorResizeHintBorder.value)

interface NavigatorHintProps {
testId: string
shouldBeShown: boolean
shouldAcceptMouseEvents: boolean
margin: number
isOutletOrDescendantOfOutlet: boolean
}

export const NavigatorHintTop = React.forwardRef<HTMLDivElement, NavigatorHintProps>(
Expand Down Expand Up @@ -61,7 +67,10 @@ export const NavigatorHintTop = React.forwardRef<HTMLDivElement, NavigatorHintPr
>
<div
style={{
backgroundColor: colorTheme.navigatorResizeHintBorder.value,
backgroundColor: outletAwareBackgroundColor(
colorTheme,
props.isOutletOrDescendantOfOutlet,
),
height: 2,
flexGrow: 1,
}}
Expand All @@ -73,7 +82,10 @@ export const NavigatorHintTop = React.forwardRef<HTMLDivElement, NavigatorHintPr
width: NavigatorHintCircleDiameter,
height: NavigatorHintCircleDiameter,
contain: 'layout',
border: `2px solid ${colorTheme.navigatorResizeHintBorder.value}`,
border: `2px solid ${outletAwareBackgroundColor(
colorTheme,
props.isOutletOrDescendantOfOutlet,
)}`,
borderRadius: '50%',
}}
/>
Expand Down Expand Up @@ -118,7 +130,10 @@ export const NavigatorHintBottom = React.forwardRef<HTMLDivElement, NavigatorHin
>
<div
style={{
backgroundColor: colorTheme.navigatorResizeHintBorder.value,
backgroundColor: outletAwareBackgroundColor(
colorTheme,
props.isOutletOrDescendantOfOutlet,
),
height: 2,
flexGrow: 1,
}}
Expand All @@ -130,7 +145,10 @@ export const NavigatorHintBottom = React.forwardRef<HTMLDivElement, NavigatorHin
width: NavigatorHintCircleDiameter,
height: NavigatorHintCircleDiameter,
contain: 'layout',
border: `2px solid ${colorTheme.navigatorResizeHintBorder.value}`,
border: `2px solid ${outletAwareBackgroundColor(
colorTheme,
props.isOutletOrDescendantOfOutlet,
)}`,
borderRadius: '50%',
}}
/>
Expand Down Expand Up @@ -338,7 +356,7 @@ export const NavigatorItemActionSheet: React.FunctionComponent<
return (
<FlexRow
style={{
padding: '0 5px',
padding: '4px 5px',
position: 'fixed',
right: 0,
background:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ import { AlwaysFalse, usePubSubAtomReadOnly } from '../../../core/shared/atom-wi
import type { CanvasPoint } from '../../../core/shared/math-utils'
import { canvasPoint, zeroCanvasPoint } from '../../../core/shared/math-utils'
import { createNavigatorReparentPostActionActions } from '../../canvas/canvas-strategies/post-action-options/post-action-options'
import createCachedSelector from 're-reselect'
import type { MetadataSubstate } from '../../editor/store/store-hook-substore-types'

export const WiggleUnit = BasePaddingUnit * 1.5

Expand Down Expand Up @@ -120,16 +122,19 @@ export interface NavigatorItemDragAndDropWrapperProps

export interface SyntheticNavigatorItemContainerProps
extends NavigatorItemDragAndDropWrapperPropsBase {
isOutletOrDescendantOfOutlet: boolean
elementPath: ElementPath
childOrAttribute: JSXElementChild
}

export interface ConditionalClauseNavigatorItemContainerProps
extends NavigatorItemDragAndDropWrapperPropsBase {
isOutletOrDescendantOfOutlet: boolean
navigatorEntry: ConditionalClauseNavigatorEntry
}

export interface ErrorNavigatorItemContainerProps extends NavigatorItemDragAndDropWrapperPropsBase {
isOutletOrDescendantOfOutlet: boolean
navigatorEntry: InvalidOverrideNavigatorEntry
}

Expand Down Expand Up @@ -308,6 +313,14 @@ function getHintPaddingForDepth(depth: number): number {
)
}

const isDescendantOfOutletOrOutletSelector = createCachedSelector(
metadataSelector,
(_: MetadataSubstate, x: ElementPath) => x,
(metadata, path) => {
return isDescendantOfOutletOrOutlet(path, metadata)
},
)((_, x) => EP.toString(x))

function onHoverDropTargetLine(
propsOfDraggedItem: NavigatorItemDragAndDropWrapperProps,
propsOfDropTargetItem: NavigatorItemDragAndDropWrapperProps,
Expand Down Expand Up @@ -800,6 +813,12 @@ export const NavigatorItemContainer = React.memo((props: NavigatorItemDragAndDro
[props.elementPath],
)

const isOutletOrDescendantOfOutlet = useEditorState(
Substores.metadata,
(store) => isDescendantOfOutletOrOutletSelector(store, props.elementPath),
'NavigatorItemContainer isOutlet',
)

const mouseEventStopPropagation = React.useCallback((event: React.MouseEvent<HTMLElement>) => {
// Prevent mouse events from passing through this element so that the same event
// on a containing element will only trigger de-selection if the event doesn't hit
Expand All @@ -826,6 +845,7 @@ export const NavigatorItemContainer = React.memo((props: NavigatorItemDragAndDro
shouldBeShown={shouldShowTopHint}
shouldAcceptMouseEvents={shouldTopDropLineInterceptMouseEvents}
margin={margin}
isOutletOrDescendantOfOutlet={isOutletOrDescendantOfOutlet}
/>,
)}
<div
Expand All @@ -848,6 +868,7 @@ export const NavigatorItemContainer = React.memo((props: NavigatorItemDragAndDro
selected={props.selected}
parentOutline={parentOutline}
visibleNavigatorTargets={props.visibleNavigatorTargets}
isOutletOrDescendantOfOutlet={isOutletOrDescendantOfOutlet}
/>
</div>
<NavigatorHintBottom
Expand All @@ -856,6 +877,7 @@ export const NavigatorItemContainer = React.memo((props: NavigatorItemDragAndDro
shouldBeShown={shouldShowBottomHint}
shouldAcceptMouseEvents={shouldBottomDropLineInterceptMouseEvents}
margin={margin}
isOutletOrDescendantOfOutlet={isOutletOrDescendantOfOutlet}
/>
</div>
)
Expand Down Expand Up @@ -1002,6 +1024,7 @@ export const SyntheticNavigatorItemContainer = React.memo(
selected={props.selected}
parentOutline={parentOutline}
visibleNavigatorTargets={props.visibleNavigatorTargets}
isOutletOrDescendantOfOutlet={props.isOutletOrDescendantOfOutlet}
/>
</div>
</div>
Expand Down Expand Up @@ -1048,6 +1071,7 @@ export const ConditionalClauseNavigatorItemContainer = React.memo(
selected={props.selected}
parentOutline={'none'}
visibleNavigatorTargets={props.visibleNavigatorTargets}
isOutletOrDescendantOfOutlet={props.isOutletOrDescendantOfOutlet}
/>
</div>
</div>
Expand Down Expand Up @@ -1092,8 +1116,20 @@ export const ErrorNavigatorItemContainer = React.memo((props: ErrorNavigatorItem
selected={props.selected}
parentOutline={'none'}
visibleNavigatorTargets={props.visibleNavigatorTargets}
isOutletOrDescendantOfOutlet={props.isOutletOrDescendantOfOutlet}
/>
</div>
</div>
)
})

function isDescendantOfOutletOrOutlet(
path: ElementPath,
metadata: ElementInstanceMetadataMap,
): boolean {
return (
EP.findAmongAncestorsOfPath(path, (p) =>
MetadataUtils.isProbablyRemixOutlet(metadata, p) ? true : null,
) === true
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ export const NavigatorItemWrapper: React.FunctionComponent<
...navigatorItemProps,
childOrAttribute: props.navigatorEntry.childOrAttribute,
elementPath: props.navigatorEntry.elementPath,
isOutletOrDescendantOfOutlet: false,
}
return <SyntheticNavigatorItemContainer {...entryProps} />
}
Expand All @@ -358,6 +359,7 @@ export const NavigatorItemWrapper: React.FunctionComponent<
const entryProps: ConditionalClauseNavigatorItemContainerProps = {
...navigatorItemProps,
navigatorEntry: props.navigatorEntry,
isOutletOrDescendantOfOutlet: false,
}
return <ConditionalClauseNavigatorItemContainer {...entryProps} />
}
Expand All @@ -366,6 +368,7 @@ export const NavigatorItemWrapper: React.FunctionComponent<
const entryProps: ErrorNavigatorItemContainerProps = {
...navigatorItemProps,
navigatorEntry: props.navigatorEntry,
isOutletOrDescendantOfOutlet: false,
}

return <ErrorNavigatorItemContainer {...entryProps} />
Expand Down
Loading

0 comments on commit 504083e

Please sign in to comment.