import { FieldSchema, StructureSchema, ValueType } from '@ephox/boulder'; import type { Optional, Result } from '@ephox/katamari'; import type { ToolbarMenuButton, ToolbarMenuButtonSpec } from '../../api/Toolbar'; import * as ComponentSchema from '../../core/ComponentSchema'; import { MenuButtonSchema } from '../toolbar/ToolbarMenuButton'; type Id = string; export interface TreeSpec { type: 'tree'; items: TreeItemSpec[]; onLeafAction?: (id: Id) => void; defaultExpandedIds?: Id[]; onToggleExpand?: ( expandedIds: Id[], { expanded, node }: { expanded: boolean; node: Id } ) => void; defaultSelectedId?: Id; } export interface Tree { type: 'tree'; items: TreeItem[]; defaultExpandedIds: Id[]; onLeafAction: Optional<(id: Id) => void>; onToggleExpand: Optional<( expandedIds: Id[], { expanded, node }: { expanded: boolean; node: Id } ) => void >; defaultSelectedId: Optional; } interface BaseTreeItemSpec { title: string; id: Id; menu?: ToolbarMenuButtonSpec; customStateIcon?: string; customStateIconTooltip?: string; } interface BaseTreeItem { title: string; id: string; menu: Optional; customStateIcon: Optional; customStateIconTooltip: Optional; } export interface DirectorySpec extends BaseTreeItemSpec { type: 'directory'; children: TreeItemSpec[]; } export interface Directory extends BaseTreeItem { type: 'directory'; children: TreeItem[]; } export interface LeafSpec extends BaseTreeItemSpec { type: 'leaf'; } export interface Leaf extends BaseTreeItem { type: 'leaf'; } export type TreeItemSpec = DirectorySpec | LeafSpec; export type TreeItem = Directory | Leaf; const baseTreeItemFields = [ FieldSchema.requiredStringEnum('type', [ 'directory', 'leaf' ]), ComponentSchema.title, FieldSchema.requiredString('id'), FieldSchema.optionOf('menu', MenuButtonSchema), FieldSchema.optionString('customStateIcon'), FieldSchema.optionString('customStateIconTooltip'), ]; const treeItemLeafFields = baseTreeItemFields; const treeItemLeafSchema = StructureSchema.objOf(treeItemLeafFields); const treeItemDirectoryFields = baseTreeItemFields.concat([ FieldSchema.requiredArrayOf('children', StructureSchema.thunkOf('children', () => { return StructureSchema.chooseProcessor('type', { directory: treeItemDirectorySchema, leaf: treeItemLeafSchema, }); })), ]); const treeItemDirectorySchema = StructureSchema.objOf(treeItemDirectoryFields); const treeItemSchema = StructureSchema.chooseProcessor('type', { directory: treeItemDirectorySchema, leaf: treeItemLeafSchema, }); const treeFields = [ ComponentSchema.type, FieldSchema.requiredArrayOf('items', treeItemSchema), FieldSchema.optionFunction('onLeafAction'), FieldSchema.optionFunction('onToggleExpand'), FieldSchema.defaultedArrayOf('defaultExpandedIds', [], ValueType.string), FieldSchema.optionString('defaultSelectedId'), ]; export const treeSchema = StructureSchema.objOf(treeFields); export const createTree = (spec: TreeSpec): Result> => StructureSchema.asRaw('tree', treeSchema, spec);