fix: fixing bug with enter with project loader name ref
This commit is contained in:
@ -5,8 +5,7 @@ import {
|
|||||||
type FileExplorerRow,
|
type FileExplorerRow,
|
||||||
type FileExplorerRender,
|
type FileExplorerRender,
|
||||||
type FileExplorerRowContextMenuProps,
|
type FileExplorerRowContextMenuProps,
|
||||||
FILE_PLACEHOLDER_NAME,
|
isRowFake,
|
||||||
FOLDER_PLACEHOLDER_NAME,
|
|
||||||
} from '@src/components/Explorer/utils'
|
} from '@src/components/Explorer/utils'
|
||||||
import { ContextMenu, ContextMenuItem } from '@src/components/ContextMenu'
|
import { ContextMenu, ContextMenuItem } from '@src/components/ContextMenu'
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
@ -16,11 +15,14 @@ export const StatusDot = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement a dynamic spacer with rem to offset the row
|
* A dynamic spacer that will add spaces based on the level it is in the tree
|
||||||
* in the tree based on the level within the tree
|
* @param level supported be from 0 to N
|
||||||
* level 0 to level N
|
* @returns
|
||||||
*/
|
*/
|
||||||
const Spacer = (level: number) => {
|
const Spacer = (level: number) => {
|
||||||
|
if (level < 0) {
|
||||||
|
return <div>Do not pass a number less than 0.</div>
|
||||||
|
}
|
||||||
const containerRemSpacing = `${level}rem`
|
const containerRemSpacing = `${level}rem`
|
||||||
return level === 0 ? (
|
return level === 0 ? (
|
||||||
<div></div>
|
<div></div>
|
||||||
@ -50,10 +52,7 @@ const Spacer = (level: number) => {
|
|||||||
* Render all the rows of the file explorer in linear layout in the DOM.
|
* Render all the rows of the file explorer in linear layout in the DOM.
|
||||||
* each row is rendered one after another in the same parent DOM element
|
* each row is rendered one after another in the same parent DOM element
|
||||||
* rows will have aria support to understand the linear div soup layout
|
* rows will have aria support to understand the linear div soup layout
|
||||||
*
|
* Pure functional renderer, state is stored outside this component.
|
||||||
|
|
||||||
* what is opened and selected outside of this logic level.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
export const FileExplorer = ({
|
export const FileExplorer = ({
|
||||||
rowsToRender,
|
rowsToRender,
|
||||||
@ -66,8 +65,6 @@ export const FileExplorer = ({
|
|||||||
contextMenuRow: FileExplorerRow | null
|
contextMenuRow: FileExplorerRow | null
|
||||||
isRenaming: boolean
|
isRenaming: boolean
|
||||||
}) => {
|
}) => {
|
||||||
// Local state for selection and what is opened
|
|
||||||
// diff this against new Project value that comes in
|
|
||||||
return (
|
return (
|
||||||
<div role="presentation" className="relative">
|
<div role="presentation" className="relative">
|
||||||
{rowsToRender.map((row, index, original) => {
|
{rowsToRender.map((row, index, original) => {
|
||||||
@ -91,11 +88,17 @@ export const FileExplorer = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Support more context menu callback functions
|
||||||
|
* cut
|
||||||
|
* paste
|
||||||
|
* copy
|
||||||
|
*
|
||||||
|
*/
|
||||||
function FileExplorerRowContextMenu({
|
function FileExplorerRowContextMenu({
|
||||||
itemRef,
|
itemRef,
|
||||||
onRename,
|
onRename,
|
||||||
onDelete,
|
onDelete,
|
||||||
onClone,
|
|
||||||
onOpenInNewWindow,
|
onOpenInNewWindow,
|
||||||
callback,
|
callback,
|
||||||
}: FileExplorerRowContextMenuProps) {
|
}: FileExplorerRowContextMenuProps) {
|
||||||
@ -134,10 +137,6 @@ function RenameForm({
|
|||||||
if (e.key !== 'Enter') {
|
if (e.key !== 'Enter') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Do the renaming
|
|
||||||
// newName: inputRef.current?.value || fileOrDir.name || '',
|
|
||||||
|
|
||||||
// To get out of the renaming state, without this the current file is still in renaming mode
|
// To get out of the renaming state, without this the current file is still in renaming mode
|
||||||
onSubmit(e)
|
onSubmit(e)
|
||||||
}
|
}
|
||||||
@ -158,12 +157,7 @@ function RenameForm({
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const formattedPlaceHolder = isRowFake(row) ? '' : row.name
|
||||||
const hidePlaceHolderIfFakeRow =
|
|
||||||
row.name === FOLDER_PLACEHOLDER_NAME || row.name === FILE_PLACEHOLDER_NAME
|
|
||||||
? ''
|
|
||||||
: row.name
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onKeyUp={handleRenameSubmit}>
|
<form onKeyUp={handleRenameSubmit}>
|
||||||
<label>
|
<label>
|
||||||
@ -175,7 +169,7 @@ function RenameForm({
|
|||||||
autoFocus
|
autoFocus
|
||||||
autoCapitalize="off"
|
autoCapitalize="off"
|
||||||
autoCorrect="off"
|
autoCorrect="off"
|
||||||
placeholder={hidePlaceHolderIfFakeRow}
|
placeholder={formattedPlaceHolder}
|
||||||
className="p-1 overflow-hidden whitespace-nowrap text-ellipsis py-1 bg-transparent outline outline-primary -outline-offset-4 text-chalkboard-100 placeholder:text-chalkboard-70 dark:text-chalkboard-10 dark:placeholder:text-chalkboard-50 focus:ring-0"
|
className="p-1 overflow-hidden whitespace-nowrap text-ellipsis py-1 bg-transparent outline outline-primary -outline-offset-4 text-chalkboard-100 placeholder:text-chalkboard-70 dark:text-chalkboard-10 dark:placeholder:text-chalkboard-50 focus:ring-0"
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
onBlur={onSubmit}
|
onBlur={onSubmit}
|
||||||
@ -203,11 +197,10 @@ export const FileExplorerRowElement = ({
|
|||||||
contextMenuRow: FileExplorerEntry | null
|
contextMenuRow: FileExplorerEntry | null
|
||||||
isRenaming: boolean
|
isRenaming: boolean
|
||||||
}) => {
|
}) => {
|
||||||
|
const rowElementRef = useRef(null)
|
||||||
const isSelected =
|
const isSelected =
|
||||||
row.name === selectedRow?.name && row.parentPath === selectedRow?.parentPath
|
row.name === selectedRow?.name && row.parentPath === selectedRow?.parentPath
|
||||||
const isIndexActive = row.domIndex === row.activeIndex
|
const isIndexActive = row.domIndex === row.activeIndex
|
||||||
|
|
||||||
const rowElementRef = useRef(null)
|
|
||||||
const isContextMenuRow = contextMenuRow?.key === row.key
|
const isContextMenuRow = contextMenuRow?.key === row.key
|
||||||
const isMyRowRenaming = isContextMenuRow && isRenaming
|
const isMyRowRenaming = isContextMenuRow && isRenaming
|
||||||
|
|
||||||
@ -236,17 +229,18 @@ export const FileExplorerRowElement = ({
|
|||||||
}}
|
}}
|
||||||
draggable="true"
|
draggable="true"
|
||||||
onDragOver={(event) => {
|
onDragOver={(event) => {
|
||||||
if (!row.isOpen && row.isFolder) {
|
// TODO
|
||||||
// on drag over, open!
|
// if (!row.isOpen && row.isFolder) {
|
||||||
row.onOpen()
|
// // on drag over, open!
|
||||||
}
|
// row.onOpen()
|
||||||
event.preventDefault()
|
// }
|
||||||
|
// event.preventDefault()
|
||||||
}}
|
}}
|
||||||
onDragStart={(event) => {
|
onDragStart={(event) => {
|
||||||
// console.log(event.target.innerText, 'onDragStart')
|
// TODO console.log(event.target.innerText, 'onDragStart')
|
||||||
}}
|
}}
|
||||||
onDrop={(event) => {
|
onDrop={(event) => {
|
||||||
// console.log(event.target.innerText, 'onDrop')
|
// TODO console.log(event.target.innerText, 'onDrop')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ width: '0.5rem' }}></div>
|
<div style={{ width: '0.5rem' }}></div>
|
||||||
@ -277,7 +271,6 @@ export const FileExplorerRowElement = ({
|
|||||||
onDelete={() => {
|
onDelete={() => {
|
||||||
row.onDelete()
|
row.onDelete()
|
||||||
}}
|
}}
|
||||||
onClone={() => {}}
|
|
||||||
onOpenInNewWindow={() => {
|
onOpenInNewWindow={() => {
|
||||||
row.onOpenInNewWindow()
|
row.onOpenInNewWindow()
|
||||||
}}
|
}}
|
||||||
|
@ -4,6 +4,10 @@ import { sortFilesAndDirectories } from '@src/lib/desktopFS'
|
|||||||
import type { FileEntry } from '@src/lib/project'
|
import type { FileEntry } from '@src/lib/project'
|
||||||
import { desktopSafePathJoin, joinOSPaths } from '@src/lib/paths'
|
import { desktopSafePathJoin, joinOSPaths } from '@src/lib/paths'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remap FileEntry data into another data structure for the Project Explorer
|
||||||
|
* This will be transformed into a DOM one called FileExplorerRow
|
||||||
|
*/
|
||||||
export interface FileExplorerEntry extends FileEntry {
|
export interface FileExplorerEntry extends FileEntry {
|
||||||
parentPath: string
|
parentPath: string
|
||||||
level: number
|
level: number
|
||||||
@ -11,6 +15,9 @@ export interface FileExplorerEntry extends FileEntry {
|
|||||||
key: string
|
key: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass this to the FileExplorer to render
|
||||||
|
*/
|
||||||
export interface FileExplorerRow extends FileExplorerEntry {
|
export interface FileExplorerRow extends FileExplorerEntry {
|
||||||
icon: CustomIconName
|
icon: CustomIconName
|
||||||
name: string
|
name: string
|
||||||
@ -36,6 +43,9 @@ export interface FileExplorerRow extends FileExplorerEntry {
|
|||||||
onRenameEnd: (e: React.KeyboardEvent<HTMLElement> | null) => void
|
onRenameEnd: (e: React.KeyboardEvent<HTMLElement> | null) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last conversion for linear rendering of DOM elements, we need the index.
|
||||||
|
*/
|
||||||
export interface FileExplorerRender extends FileExplorerRow {
|
export interface FileExplorerRender extends FileExplorerRow {
|
||||||
domIndex: number
|
domIndex: number
|
||||||
domLength: number
|
domLength: number
|
||||||
@ -45,11 +55,14 @@ export interface FileExplorerRowContextMenuProps {
|
|||||||
itemRef: React.RefObject<HTMLElement>
|
itemRef: React.RefObject<HTMLElement>
|
||||||
onRename: () => void
|
onRename: () => void
|
||||||
onDelete: () => void
|
onDelete: () => void
|
||||||
onClone: () => void
|
|
||||||
onOpenInNewWindow: () => void
|
onOpenInNewWindow: () => void
|
||||||
callback: () => void
|
callback: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a key that can be used for a hash table for opened rows
|
||||||
|
* this is also used for key={} in React.
|
||||||
|
*/
|
||||||
export const constructPath = ({
|
export const constructPath = ({
|
||||||
parentPath,
|
parentPath,
|
||||||
name,
|
name,
|
||||||
@ -162,6 +175,14 @@ export const addPlaceHoldersForNewFileAndFolder = (
|
|||||||
children.push(placeHolderFileEntry)
|
children.push(placeHolderFileEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const isRowFake = (
|
||||||
|
row: FileExplorerRender | FileExplorerRow | FileExplorerEntry
|
||||||
|
): boolean => {
|
||||||
|
return (
|
||||||
|
row.name === FOLDER_PLACEHOLDER_NAME || row.name === FILE_PLACEHOLDER_NAME
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Used for focused which is different from the selection when you mouse click.
|
// Used for focused which is different from the selection when you mouse click.
|
||||||
export const NOTHING_IS_SELECTED: number = -2
|
export const NOTHING_IS_SELECTED: number = -2
|
||||||
export const CONTAINER_IS_SELECTED: number = -1
|
export const CONTAINER_IS_SELECTED: number = -1
|
||||||
|
@ -4,6 +4,7 @@ import {
|
|||||||
useEffect,
|
useEffect,
|
||||||
type MouseEventHandler,
|
type MouseEventHandler,
|
||||||
type ReactNode,
|
type ReactNode,
|
||||||
|
useRef,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import type { ContextFrom } from 'xstate'
|
import type { ContextFrom } from 'xstate'
|
||||||
|
|
||||||
@ -145,10 +146,13 @@ export const sidebarPanes: SidebarPane[] = [
|
|||||||
Content: (props: { id: SidebarType; onClose: () => void }) => {
|
Content: (props: { id: SidebarType; onClose: () => void }) => {
|
||||||
const projects = useFolders()
|
const projects = useFolders()
|
||||||
const loaderData = useRouteLoaderData(PATHS.FILE) as IndexLoaderData
|
const loaderData = useRouteLoaderData(PATHS.FILE) as IndexLoaderData
|
||||||
|
const projectNameRef = useRef(loaderData.project?.name)
|
||||||
const [theProject, setTheProject] = useState<Project | null>(null)
|
const [theProject, setTheProject] = useState<Project | null>(null)
|
||||||
const { project, file } = loaderData
|
const { project, file } = loaderData
|
||||||
const settings = useSettings()
|
const settings = useSettings()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
projectNameRef.current = loaderData?.project?.name
|
||||||
|
|
||||||
// Have no idea why the project loader data doesn't have the children from the ls on disk
|
// Have no idea why the project loader data doesn't have the children from the ls on disk
|
||||||
// That means it is a different object or cached incorrectly?
|
// That means it is a different object or cached incorrectly?
|
||||||
if (!project || !file) {
|
if (!project || !file) {
|
||||||
@ -186,14 +190,15 @@ export const sidebarPanes: SidebarPane[] = [
|
|||||||
|
|
||||||
// Only open the file if it is a kcl file.
|
// Only open the file if it is a kcl file.
|
||||||
if (
|
if (
|
||||||
loaderData?.project?.name &&
|
projectNameRef.current &&
|
||||||
entry.children == null &&
|
entry.children == null &&
|
||||||
entry.path.endsWith(FILE_EXT)
|
entry.path.endsWith(FILE_EXT)
|
||||||
) {
|
) {
|
||||||
|
|
||||||
systemIOActor.send({
|
systemIOActor.send({
|
||||||
type: SystemIOMachineEvents.navigateToFile,
|
type: SystemIOMachineEvents.navigateToFile,
|
||||||
data: {
|
data: {
|
||||||
requestedProjectName: loaderData?.project?.name,
|
requestedProjectName: projectNameRef.current,
|
||||||
requestedFileName: requestedFileName,
|
requestedFileName: requestedFileName,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user