Files
supabase/packages/ui-patterns/CommandMenu/internal/state/commandsState.ts
T
Charis 84732ff44c feat: add new command menu to studio (#28432)
Add new command menu to studio. Ports over commands from old menu (with some minor reorganization), then adds:
- Branch switcher
- Project switcher
2024-08-08 16:42:07 -04:00

86 lines
2.7 KiB
TypeScript

import { proxy } from 'valtio'
import { type ICommand } from '../Command'
import { type ICommandSection, section$new } from '../CommandSection'
type OrderSectionInstruction = (sections: ICommandSection[], idx: number) => ICommandSection[]
type OrderCommandsInstruction = (
commands: ICommand[],
commandsToInsert: ICommand[]
) => Array<ICommand>
type CommandOptions = {
deps?: any[]
enabled?: boolean
forceMountSection?: boolean
sectionMeta?: any
orderSection?: OrderSectionInstruction
orderCommands?: OrderCommandsInstruction
}
type ICommandsState = {
commandSections: ICommandSection[]
registerSection: (
sectionName: string,
commands: ICommand[],
options?: CommandOptions
) => () => void
}
const initCommandsState = () => {
const state: ICommandsState = proxy({
commandSections: [],
registerSection: (sectionName, commands, options) => {
let editIndex = state.commandSections.findIndex((section) => section.name === sectionName)
if (editIndex === -1) editIndex = state.commandSections.length
state.commandSections[editIndex] ??= section$new(sectionName)
if (options?.sectionMeta) {
const oldMeta = state.commandSections[editIndex].meta
if (!!oldMeta && typeof oldMeta === 'object' && typeof options.sectionMeta === 'object') {
state.commandSections[editIndex].meta = { ...oldMeta, ...options.sectionMeta }
} else {
state.commandSections[editIndex].meta = options.sectionMeta
}
}
if (options?.forceMountSection) state.commandSections[editIndex].forceMount = true
if (options?.orderCommands) {
state.commandSections[editIndex].commands = options.orderCommands(
state.commandSections[editIndex].commands,
commands
)
} else {
state.commandSections[editIndex].commands.push(...commands)
}
state.commandSections =
options?.orderSection?.(state.commandSections, editIndex) ?? state.commandSections
return () => {
const idx = state.commandSections.findIndex((section) => section.name === sectionName)
if (idx !== -1) {
const filteredCommands = state.commandSections[idx].commands.filter(
(command) => !commands.map((cmd) => cmd.id).includes(command.id)
)
if (!filteredCommands.length) {
state.commandSections.splice(idx, 1)
} else {
state.commandSections[idx].commands = filteredCommands
}
}
}
},
})
return state
}
const orderSectionFirst = (sections: ICommandSection[], idx: number) => [
sections[idx],
...sections.slice(0, idx),
...sections.slice(idx + 1),
]
export { initCommandsState, orderSectionFirst }
export type { ICommandsState, CommandOptions }