Feat/studio extension dropdowns (#379)
This commit is contained in:
parent
8470b67d4b
commit
3d343cc59e
5 changed files with 137 additions and 8 deletions
|
@ -40,6 +40,32 @@ studio.extend({
|
|||
studio.createPane('example')
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'Downdown',
|
||||
svgSource: '🫠',
|
||||
onChange: (value: any) => {
|
||||
console.log('Change:', value)
|
||||
},
|
||||
selectable: false,
|
||||
options: [
|
||||
{
|
||||
label: 'Option 1',
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: 'Option 2',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: 'Option 3',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: 'Option 4',
|
||||
value: 3,
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
|
||||
updateToolset()
|
||||
|
|
|
@ -89,18 +89,34 @@ export type ToolConfigIcon = {
|
|||
onClick: () => void
|
||||
}
|
||||
|
||||
export type ToolConfigOption = {
|
||||
value: string
|
||||
label: string
|
||||
svgSource: string
|
||||
}
|
||||
|
||||
export type ToolConfigSwitch = {
|
||||
type: 'Switch'
|
||||
value: string
|
||||
onChange: (value: string) => void
|
||||
options: {
|
||||
value: string
|
||||
label: string
|
||||
svgSource: string
|
||||
}[]
|
||||
options: ToolConfigOption[]
|
||||
}
|
||||
|
||||
export type ToolConfig = ToolConfigIcon | ToolConfigSwitch
|
||||
export type ToolConfigDowndownOption = {
|
||||
label: string
|
||||
value: any
|
||||
}
|
||||
|
||||
export type ToolConfigDowndown = {
|
||||
type: 'Downdown'
|
||||
index?: number
|
||||
svgSource: string
|
||||
selectable: boolean
|
||||
onChange: (option: ToolConfigDowndownOption | null) => void
|
||||
options: ToolConfigDowndownOption[]
|
||||
}
|
||||
|
||||
export type ToolConfig = ToolConfigIcon | ToolConfigSwitch | ToolConfigDowndown
|
||||
|
||||
export type ToolsetConfig = Array<ToolConfig>
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import type {ToolConfig, ToolsetConfig} from '@theatre/studio/TheatreStudio'
|
|||
import React from 'react'
|
||||
import IconButton from './tools/IconButton'
|
||||
import Switch from './tools/Switch'
|
||||
import Downdown from './tools/Downdown'
|
||||
|
||||
const Toolset: React.FC<{
|
||||
config: ToolsetConfig
|
||||
|
@ -25,6 +26,7 @@ const toolByType: {
|
|||
} = {
|
||||
Icon: IconButton,
|
||||
Switch: Switch,
|
||||
Downdown: Downdown,
|
||||
}
|
||||
|
||||
function getToolByType<Type extends ToolConfig['type']>(
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
import React, {useState} from 'react'
|
||||
import styled from 'styled-components'
|
||||
import {pointerEventsAutoInNormalMode} from '@theatre/studio/css'
|
||||
import type {
|
||||
ToolConfigDowndown,
|
||||
ToolConfigDowndownOption,
|
||||
} from '@theatre/studio/TheatreStudio'
|
||||
import ToolbarIconButton from '@theatre/studio/uiComponents/toolbar/ToolbarIconButton'
|
||||
|
||||
const Container = styled.div`
|
||||
${pointerEventsAutoInNormalMode};
|
||||
& > svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
pointer-events: none;
|
||||
}
|
||||
`
|
||||
|
||||
const DropdownItem = styled.li`
|
||||
width: max-content;
|
||||
& > button {
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
padding: 0 9px;
|
||||
width: fit-content;
|
||||
}
|
||||
& > .selected {
|
||||
border-color: white;
|
||||
}
|
||||
`
|
||||
|
||||
const Downdown: React.FC<{
|
||||
config: ToolConfigDowndown
|
||||
}> = ({config}) => {
|
||||
const [currentIndex, setCurrentIndex] = useState(
|
||||
config.index !== undefined ? config.index : -1,
|
||||
)
|
||||
const [showOptions, setShowOptions] = useState(false)
|
||||
|
||||
const toggleOptions = () => {
|
||||
setShowOptions(!showOptions)
|
||||
}
|
||||
|
||||
const selectOption = (index: number, option: ToolConfigDowndownOption) => {
|
||||
if (config.selectable) {
|
||||
if (index !== currentIndex) {
|
||||
config.onChange(option.value)
|
||||
setCurrentIndex(index)
|
||||
} else {
|
||||
config.onChange(null)
|
||||
setCurrentIndex(-1)
|
||||
}
|
||||
} else {
|
||||
config.onChange(option.value)
|
||||
}
|
||||
setShowOptions(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<ToolbarIconButton onClick={toggleOptions}>
|
||||
{config.svgSource}
|
||||
</ToolbarIconButton>
|
||||
{showOptions && (
|
||||
<ul>
|
||||
{config.options.map(
|
||||
(option: ToolConfigDowndownOption, index: number) => (
|
||||
<DropdownItem key={index}>
|
||||
<ToolbarIconButton
|
||||
onClick={() => selectOption(index, option)}
|
||||
className={index === currentIndex ? 'selected' : ''}
|
||||
>
|
||||
{option.label}
|
||||
</ToolbarIconButton>
|
||||
</DropdownItem>
|
||||
),
|
||||
)}
|
||||
</ul>
|
||||
)}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default Downdown
|
|
@ -13,7 +13,7 @@ const IconContainer = styled.div`
|
|||
}
|
||||
`
|
||||
|
||||
const IconButton: React.FC<{
|
||||
const Switch: React.FC<{
|
||||
config: ToolConfigSwitch
|
||||
}> = ({config}) => {
|
||||
return (
|
||||
|
@ -29,4 +29,4 @@ const IconButton: React.FC<{
|
|||
)
|
||||
}
|
||||
|
||||
export default IconButton
|
||||
export default Switch
|
||||
|
|
Loading…
Reference in a new issue