import * as React from "react"; import { BaseInstancePaneProps } from "./instance.pc"; import { Dispatch } from "redux"; import * as cx from "classnames"; import { DependencyGraph, PCVariant, InspectorNode, PCSourceTagNames, extendsComponent, getInspectorSourceNode, inspectorNodeInShadow, getTopMostInspectorInstance, PCVisibleNode, PCOverride, PCComponent, getPCNodeContentNode, getPCNodeModule, ComputedStyleInfo, getInstanceVariantInfo } from "paperclip"; import { dropdownMenuOptionFromValue } from "../../../../../../inputs/dropdown/controller"; import { cssResetPropertyOptionClicked, instanceVariantToggled } from "../../../../../../../actions"; import { getParentTreeNode, containsNestedTreeNodeById, EMPTY_ARRAY } from "tandem-common"; import { VariantOption } from "../../variants/option.pc"; export type Props = { selectedInspectorNodes: InspectorNode[]; rootInspectorNode: InspectorNode; dispatch: Dispatch; graph: DependencyGraph; selectedVariant: PCVariant; computedStyleInfo: ComputedStyleInfo; }; export default (Base: React.ComponentClass) => class InstancePaneController extends React.PureComponent { onResetStyle = (property: string) => { this.props.dispatch(cssResetPropertyOptionClicked(property)); }; onVariantToggle = (variant: PCVariant) => { this.props.dispatch(instanceVariantToggled(variant)); }; render() { const { onResetStyle, onVariantToggle } = this; const { selectedInspectorNodes, computedStyleInfo, rootInspectorNode, selectedVariant, dispatch, graph, ...rest } = this.props; const selectedInspectorNode = selectedInspectorNodes[0]; if (!selectedInspectorNode) { return null; } const sourceNode = getInspectorSourceNode( selectedInspectorNode, rootInspectorNode, graph ) as PCVisibleNode | PCComponent | null; // may not exist for things like plugs if (!sourceNode) { return null; } const contentNode = getPCNodeContentNode( sourceNode.id, getPCNodeModule(sourceNode.id, graph) ); if (!contentNode) { return null; } if ( sourceNode.name !== PCSourceTagNames.COMPONENT_INSTANCE && (sourceNode.name !== PCSourceTagNames.COMPONENT || !extendsComponent(sourceNode)) ) { if (!inspectorNodeInShadow(selectedInspectorNode, rootInspectorNode)) { // needs to show up within components particularly for variants if (contentNode.name !== PCSourceTagNames.COMPONENT) { return null; } } } const instance = getTopMostInspectorInstance( selectedInspectorNode, rootInspectorNode ); const instanceSourceNode = getInspectorSourceNode( instance, rootInspectorNode, graph ) as PCVisibleNode | PCComponent; // if top most source node is not component or instance, then the target node is _not_ in a shadow const topMostSourceNode = instanceSourceNode.name === PCSourceTagNames.COMPONENT_INSTANCE || instanceSourceNode.name === PCSourceTagNames.COMPONENT ? instanceSourceNode : contentNode; const overrideKeys = [ ...Object.keys(computedStyleInfo.style).filter(key => { const overrides = computedStyleInfo.styleOverridesMap[key] || EMPTY_ARRAY; const inCurrentInstance = overrides.some((override: PCOverride) => { return ( containsNestedTreeNodeById(override.id, topMostSourceNode) && override.variantId == (selectedVariant && selectedVariant.id) ); }); // if variant is selected, then override must be present return ( inCurrentInstance || (!selectedVariant && instanceSourceNode.style && Boolean(instanceSourceNode.style[key])) ); }) ]; if ( sourceNode.name !== PCSourceTagNames.COMPONENT_INSTANCE && (sourceNode.name !== PCSourceTagNames.COMPONENT || !extendsComponent(sourceNode)) ) { return null; } const variantInfo = getInstanceVariantInfo( selectedInspectorNode, rootInspectorNode, graph, selectedVariant && selectedVariant.id ); const options = variantInfo.map(({ variant, component, enabled }, i) => { return ( ); }); return ( 0 })} resetDropdownProps={{ options: overrideKeys.map(dropdownMenuOptionFromValue), onChangeComplete: onResetStyle }} content={options} /> ); } };