import * as React from "react"; import * as cx from "classnames"; import { PCSourceTagNames, SyntheticVisibleNode, SyntheticElement, DependencyGraph, getAllPCComponents, PCComponent, PCNode, PCComponentInstanceElement, PCElement, getNativeComponentName, PCTextNode } from "paperclip"; import { elementTypeChanged, attributeChanged } from "../../../../../actions"; import { DropdownMenuOption, dropdownMenuOptionFromValue } from "../../../../inputs/dropdown/controller"; import { BaseElementPropertiesProps, ElementProps } from "./view.pc"; import { Dispatch } from "redux"; import { memoize } from "tandem-common"; const TYPE_MENU_OPTIONS: DropdownMenuOption[] = [ "a", "abbr", "acronym", "address", "b", "base", "blockquote", "br", "button", "canvas", "caption", "cite", "code", "col", "colgroup", "div", "dl", "dt", "em", "embed", "fieldset", "figcaption", "figure", "font", "footer", "form", "frame", "frameset", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hr", "html", "i", "iframe", "img", "input", "ins", "kbd", "label", "legend", "li", "link", "main", "map", "mark", "menu", "menuitem", "meta", "meter", "nav", "noframes", "noscript", "object", "ol", "optgroup", "option", "output", "p", "param", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "script", "section", "select", "small", "source", "span", "strike", "strong", "style", "sub", "summary", "sup", "svg", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "tt", "u", "ul", "var", "video", "wbr" ].map(dropdownMenuOptionFromValue); const getComponentDropdownOptions = memoize( (components: PCComponent[]): DropdownMenuOption[] => { return components.map(component => ({ label: component.label, value: component.id })); } ); const getTypeMenuOptions = memoize( (components: PCComponent[], targetSourceNode: PCNode) => { return [ ...TYPE_MENU_OPTIONS, ...getComponentDropdownOptions(components).filter( component => component.value !== targetSourceNode.id ) ].sort( (a, b) => String(a.label).toLowerCase() < String(b.label).toLowerCase() ? -1 : 1 ); } ); export type Props = { sourceNode: PCElement | PCComponent | PCComponentInstanceElement | PCTextNode; dispatch: Dispatch; graph: DependencyGraph; } & ElementProps; export default (Base: React.ComponentClass) => { return class ElementController extends React.PureComponent { onAttributeChangeComplete = (name: string, value: string) => { this.props.dispatch(attributeChanged(name, value)); }; onTypeChange = (value: any) => { this.props.dispatch(elementTypeChanged(value)); }; render() { const { onTypeChange, onAttributeChangeComplete } = this; const { dispatch, sourceNode, graph, ...rest } = this.props; if ( !sourceNode || (sourceNode.name !== PCSourceTagNames.COMPONENT && sourceNode.name !== PCSourceTagNames.ELEMENT && sourceNode.name !== PCSourceTagNames.COMPONENT_INSTANCE) ) { return null; } const components = getAllPCComponents(graph); const baseName = getNativeComponentName(sourceNode, graph); return ( ); } }; }; const attributeChangeCallback = memoize((name: string, listener) => value => listener(name, value) );