Skip to content
This repository has been archived by the owner on Jun 24, 2023. It is now read-only.

Commit

Permalink
refactor: insert custom element
Browse files Browse the repository at this point in the history
  • Loading branch information
dineshsalunke committed Dec 25, 2022
1 parent 4a74a9c commit 1c05da2
Show file tree
Hide file tree
Showing 14 changed files with 226 additions and 165 deletions.
4 changes: 3 additions & 1 deletion examples/kitchen-sink/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Canvas } from "@react-three/fiber"
import { FC } from "react"

export type ApplicationProps = {}

export const Application: FC<ApplicationProps> = () => {
Expand Down Expand Up @@ -29,6 +28,9 @@ export const Application: FC<ApplicationProps> = () => {
<meshPhongMaterial />
</mesh>
</group>
<group name="Empty group" position={[0, 0, -5]}>
{}
</group>
</Canvas>
)
}
14 changes: 14 additions & 0 deletions examples/kitchen-sink/src/__reactThreeEditor/Box.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { FC } from "react"

export type BoxMeshProps = {}

export const BoxMesh: FC<BoxMeshProps> = () => {
return (
<group>
<mesh>
<boxGeometry />
<meshStandardMaterial color={"magenta"} />
</mesh>
</group>
)
}
56 changes: 40 additions & 16 deletions packages/editor/src/commandbar/CommandManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,46 +7,70 @@ export class CommandManager {
*/
store: CommandStoreType = createCommandBarStore()

toggleCommandBar(flag?: boolean) {
registerCommands(commands: CommandType[]) {
if (!Array.isArray(commands)) {
commands = [commands]
}

this.store.setState((state) => {
if (typeof flag !== "boolean") {
flag = !state.open
}
commands.forEach((command) => {
if (command.parentId && state.commands[command.parentId]) {
if (!Array.isArray(state.commands[command.parentId].subcommands)) {
state.commands[command.parentId].subcommands = []
}
state.commands[command.parentId].subcommands?.push(command.name)
state.commands[command.name] = command
} else {
state.commands[command.name] = command
}
})
return {
...state,
filter: !flag ? "" : state.filter,
activeCommandChain: !flag ? [] : state.activeCommandChain,
open: flag
...state
}
})
//
}

registerCommands(commands: CommandType[]) {
unregisterCommands(commands: CommandType[]) {
if (!Array.isArray(commands)) {
commands = [commands]
}

this.store.setState((state) => {
commands.forEach(({ name }) => {
delete state.commands[name]
})
return {
...state,
commands: [...state.commands, ...commands]
...state
}
})
//
}

unregisterCommands(commands: CommandType[]) {
toggleCommandBar(flag?: boolean) {
this.store.setState((state) => {
if (typeof flag !== "boolean") {
flag = !state.open
}
return {
...state,
commands: state.commands.filter(
(c) => !commands.some((tc) => tc.name === c.name)
)
filter: !flag ? "" : state.filter,
activeCommandChain: !flag ? [] : state.activeCommandChain,
open: flag
}
})
}

openCommandGroup(name: string) {
this.store.setState((state) => {
let activeCommandChain = [...state.activeCommandChain]
if (state.commands[name]) {
activeCommandChain.push(name)
}
return {
...state,
filter: "",
activeCommandChain: [...state.activeCommandChain, name]
activeCommandChain
}
})
}
Expand Down
128 changes: 46 additions & 82 deletions packages/editor/src/commandbar/EditorCommand.tsx
Original file line number Diff line number Diff line change
@@ -1,114 +1,73 @@
import { Icon } from "@iconify/react"
import { Command } from "cmdk"
import { FC, useCallback, useEffect, useRef } from "react"
import { Editor, useEditor } from "../editable"
import { useEditor } from "../editable"
import { selectActiveCommands } from "./store"
import { commandBarTunnel } from "./tunnel"
import { CommandGroup, ExecutableCommand } from "./types"
import { CommandType } from "./types"

export function EditorCommand() {
const inputRef = useRef<HTMLInputElement | null>(null)
const listRef = useRef(null)
export const CommandChain: FC = () => {
const editor = useEditor()

useEffect(() => {
inputRef?.current?.focus()
}, [])

const activeCommandChain = editor.commands.store(
({ activeCommandChain }) => activeCommandChain
)
const commands = editor.commands.store(selectActiveCommands)
return (
<div>
<div cmdk-vercel-badge="">Home</div>
{activeCommandChain.map((n) => {
return (
<div key={n} cmdk-vercel-badge="">
{n}
</div>
)
})}
</div>
)
}

export const CommandInput: FC = () => {
const editor = useEditor()
const filter = editor.commands.store((state) => state.filter)
const onInputValueChange = useCallback(
(filter: string) => {
editor.commands.store.setState({ filter })
},
[editor.commands.store]
)
return (
<Command.Input
autoFocus
placeholder="Search for apps and commands..."
value={filter}
onValueChange={onInputValueChange}
/>
)
}

export function EditorCommand() {
const editor = useEditor()
const commands = editor.commands.store(selectActiveCommands)

return (
<commandBarTunnel.In>
<div cmdk-raycast-top-shine="" />
<div>
<div cmdk-vercel-badge="">Home</div>
{activeCommandChain.map((n) => {
return (
<div key={n} cmdk-vercel-badge="">
{n}
</div>
)
})}
</div>
<Command.Input
ref={inputRef}
autoFocus
placeholder="Search for apps and commands..."
value={filter}
onValueChange={onInputValueChange}
/>
<CommandChain />
<CommandInput />
<hr cmdk-raycast-loader="" />
<Command.List ref={listRef}>
<Command.List>
<Command.Empty>No results found.</Command.Empty>
{(commands ?? []).map((command) => {
if (command.render && !command.render(editor)) return null
if (Array.isArray((command as CommandGroup).children)) {
return (
<CommandGroupItem
key={command.name}
command={command as CommandGroup}
/>
)
} else {
return (
<CommandItem
key={command.name}
command={command as ExecutableCommand}
/>
)
}
return <CommandItem key={command.name} command={command} />
})}
</Command.List>
</commandBarTunnel.In>
)
}

export type CommandGroupItemProps = {
command: CommandGroup
onSelect?(command: CommandGroup): void
}
export const CommandGroupItem: FC<CommandGroupItemProps> = ({
command,
onSelect: _onSelect
}) => {
const editor = useEditor()
const { icon, description, render } = command
const _editor = useEditor()

const onSelect = useCallback(() => {
editor.commands.openCommandGroup(command.name)
_onSelect?.(command)
}, [_onSelect, command, editor])

if (render && !render(_editor)) return null

return (
<Command.Item value={command.name} onSelect={onSelect}>
{typeof icon === "function" ? (
icon(_editor)
) : typeof icon == "string" ? (
<Icon icon={icon} />
) : null}
{typeof description === "function"
? description(_editor)
: description || command.name}
</Command.Item>
)
}

export type CommandProps = {
command: ExecutableCommand
onSelect?(command: ExecutableCommand): void
command: CommandType
onSelect?(command: CommandType): void
}
export const CommandItem: FC<CommandProps> = ({
command,
Expand All @@ -118,9 +77,14 @@ export const CommandItem: FC<CommandProps> = ({
const editor = useEditor()

const onSelect = useCallback(() => {
editor.commands.toggleCommandBar(false)
_onSelect?.(command)
;(command as ExecutableCommand).execute?.(editor)
if (Array.isArray(command.subcommands) && command.subcommands.length) {
editor.commands.openCommandGroup(command.name)
_onSelect?.(command)
} else {
editor.commands.toggleCommandBar(false)
_onSelect?.(command)
command.execute?.(editor)
}
}, [_onSelect, command, editor])

if (render && !render(editor)) return null
Expand Down
12 changes: 5 additions & 7 deletions packages/editor/src/commandbar/KeyboardCommand.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import toast from "react-hot-toast"
import { useHotkeys } from "react-hotkeys-hook"
import { useEditor } from "../editable"
import { ExecutableCommand } from "./types"
import { isCommand } from "./utils"

export function KeyboardCommands() {
const editor = useEditor()
const commands = editor.commands.store((state) => state.commands)

// const [{ shortcuts: debug }] = editor.useSettings("debug", {
// shortcuts: false
// })
const commands = editor.commands.store((state) =>
Object.values(state.commands)
)

return (
<>
{commands
.filter((c) => typeof (c as ExecutableCommand).execute === "function")
.filter((c) => isCommand(c))
.map((command: any) => {
if (!command.shortcut) return null
return (
Expand Down
29 changes: 8 additions & 21 deletions packages/editor/src/commandbar/commands/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,16 @@
import { FC, useEffect } from "react"
import * as THREE from "three"
import { BufferGeometry, Group, Material, Mesh, Object3D } from "three"
import { Group, Mesh } from "three"
import { EditableElement, useEditor } from "../../editable"
import { ThreeEditor } from "../../fiber/ThreeEditor"
import { CommandType } from "../types"

function isClass(v: any) {
return typeof v === "function" && /^\s*class\s+/.test(v.toString())
}

const possibleItemsToAdd = Object.values(THREE)
.filter(isClass)
.filter(
(c: any) =>
c.prototype instanceof Object3D ||
c.prototype instanceof Material ||
c.prototype instanceof BufferGeometry
)

export const EditorCommands: FC = () => {
const editor = useEditor()
useEffect(() => {
const commands: CommandType[] = [
{
name: "toggle-play-mode",
type: "command",
description(editor) {
const mode = editor.useMode("editor")
return `Go to ${mode ? "Play" : "Editor"} mode`
Expand All @@ -41,6 +28,7 @@ export const EditorCommands: FC = () => {
{
name: "isolate",
description: "Isolate element",
type: "command",
shortcut: ["meta", "f"],
execute(editor) {
let el = editor.root
Expand Down Expand Up @@ -90,29 +78,28 @@ export const EditorCommands: FC = () => {
{
name: "save-selected-element",
description: "Save selected element",
type: "command",
execute(editor) {
editor.selectedElement?.save()
}
},
{
name: "clear-local-storage",
description: "Clear local storage",
type: "command",
execute(editor) {
localStorage.clear()
}
},
{
name: "insert-element",
description: "Insert element into the scene",
children: possibleItemsToAdd.map((klass: any) => {
return {
name: `${klass.name}`
}
})
type: "command"
},
{
name: "remove-element",
description: "Remove element from the scene"
description: "Remove element from the scene",
type: "command"
}
]
editor.commands.registerCommands(commands)
Expand Down
Loading

0 comments on commit 1c05da2

Please sign in to comment.