Skip to content
This repository has been archived by the owner on Oct 23, 2023. It is now read-only.

Commit

Permalink
fix: restore slot contents
Browse files Browse the repository at this point in the history
  • Loading branch information
marionebl committed May 24, 2018
1 parent c84bf04 commit 23c4c2c
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 46 deletions.
3 changes: 2 additions & 1 deletion src/components/element/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import styled from 'styled-components';
import { tag } from '../tag';

export const ElementAnchors = {
element: 'data-element-id',
element: 'data-id',
content: 'data-id',
icon: 'data-icon',
label: 'data-element-label',
placeholder: 'data-element-placeholder'
Expand Down
95 changes: 66 additions & 29 deletions src/container/element-list/element-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import * as MobxReact from 'mobx-react';
import * as React from 'react';
import * as Store from '../../store';
import * as Types from '../../store/types';
import * as uuid from 'uuid';

export interface ElementListState {
dragging: boolean;
Expand Down Expand Up @@ -57,40 +56,46 @@ export class ElementList extends React.Component<{}, ElementListState> {

if (!pattern) {
return {
title: '(invalid)',
id: uuid.v4(),
active: store.getSelectedElement() === element,
children: [],
draggable: false,
dragging: this.state.dragging
dragging: this.state.dragging,
editable: false,
id: element.getId(),
title: `Invalid: ${element.getName()}`
};
}

const createSlot = slot => this.createItemFromSlot(slot, element);

const [[defaultSlotData], slotsData] = partition(
pattern.getSlots(),
slot => slot.getType() === Types.SlotType.Children
);

const children = createSlot(defaultSlotData).children as ElementNodeProps[];
const children = defaultSlotData
? (createSlot(defaultSlotData).children as ElementNodeProps[])
: [];

const slots = slotsData.map(createSlot);

return {
title: element.getName(),
active: store.getSelectedElement() === element,
children: [...slots, ...children],
draggable: !element.isNameEditable(),
dragging: this.state.dragging,
editable: element.isNameEditable(),
id: element.getId(),
children: [...slots, ...children],
active: store.getSelectedElement() === element
title: element.getName()
};
}

public createItemFromSlot(slot: Store.PatternSlot, element: Store.Element): ElementNodeProps {
const slotContent = element.getContentBySlot(slot) as Store.ElementContent;

const slotListItem: ElementNodeProps = {
id: slot.getId(),
title: `\uD83D\uDD18 ${slot.getName()}`,
id: slotContent.getId(),
title: slot.getName(),
editable: false,
draggable: false,
dragging: this.state.dragging,
Expand Down Expand Up @@ -186,26 +191,14 @@ export class ElementList extends React.Component<{}, ElementListState> {

const isSiblingDrop =
(e.target as HTMLElement).getAttribute(ElementAnchors.placeholder) === 'true';

const targetElement = elementFromTarget(e.target);
const targetContent = contentFromTarget(e.target);

if (!targetElement) {
if (!targetElement && !targetContent) {
return;
}

const getDropParent = (el: Store.Element): Store.Element => {
if (!isSiblingDrop) {
return el;
}

if (el.isRoot()) {
return el;
}

return el.getParent() as Store.Element;
};

const dropParent = getDropParent(targetElement);

// prettier-ignore
const draggedElement = pattern
? // drag from pattern list, create new element
Expand All @@ -222,16 +215,43 @@ export class ElementList extends React.Component<{}, ElementListState> {
return;
}

const dropContainer = dropParent.getContentBySlotType(
Types.SlotType.Children
) as Store.ElementContent;
const getDropParent = (el?: Store.Element): Store.Element | undefined => {
if (!el && targetContent) {
return store.getElementById(targetContent.getElementId()) as Store.Element;
}

if (!el) {
return;
}

if (!isSiblingDrop) {
return el;
}

if (el.isRoot()) {
return el;
}

return el.getParent() as Store.Element;
};

const dropParent = getDropParent(targetElement) as Store.Element;
const dropContainer =
targetContent || dropParent.getContentBySlotType(Types.SlotType.Children);

if (!dropContainer) {
return;
}

const command = Store.ElementLocationCommand.addChild({
parent: dropParent,
child: draggedElement,
slotId: dropContainer.getSlotId(),
index: isSiblingDrop
? calculateDropIndex({ target: targetElement, dragged: draggedElement })
? calculateDropIndex({
target: targetElement as Store.Element,
dragged: draggedElement
})
: dropContainer.getElements().length
});

Expand Down Expand Up @@ -367,6 +387,23 @@ function above(node: EventTarget, selector: string): HTMLElement | null {
return ended ? null : el;
}

function contentFromTarget(target: EventTarget): Store.ElementContent | undefined {
const el = above(target, `[${ElementAnchors.content}]`);

if (!el) {
return;
}

const id = el.getAttribute(ElementAnchors.element);

if (typeof id !== 'string') {
return;
}

const store = Store.ViewStore.getInstance();
return store.getContentById(id);
}

function elementFromTarget(target: EventTarget): Store.Element | undefined {
const el = above(target, `[${ElementAnchors.element}]`);

Expand Down
19 changes: 10 additions & 9 deletions src/preview/preview-renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export interface RenderInit {
getComponent(props: any, synthetics: any): React.Component | React.SFC | undefined;
// tslint:disable-next-line:no-any
getProperties(props: any): any;
// tslint:disable-next-line:no-any
getSlots(slots: any, render: (props: any) => any): any;
}

export interface InjectedPreviewHighlightProps {
Expand All @@ -33,6 +35,7 @@ export interface InjectedPreviewApplicationProps {
interface InjectedPreviewComponentProps extends Types.SerializedElement {
getComponent: RenderInit['getComponent'];
getProperties: RenderInit['getProperties'];
getSlots: RenderInit['getSlots'];
highlight: HighlightArea;
store: PreviewStore;
// tslint:disable-next-line:no-any
Expand All @@ -59,6 +62,7 @@ const Page: React.SFC = (props: any) => (
{props.viewport && <meta name="viewport" content="width=device-width, initial-scale=1" />}
{props.head}
</Helmet>
{props.content}
{props.children}
</>
);
Expand All @@ -74,6 +78,7 @@ export function render(init: RenderInit): void {
<MobXReact.Provider
getComponent={init.getComponent}
getProperties={init.getProperties}
getSlots={init.getSlots}
store={init.store}
highlight={init.highlight}
>
Expand Down Expand Up @@ -130,7 +135,7 @@ class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundarySta
}
}

@MobXReact.inject('getComponent', 'getProperties', 'store', 'highlight')
@MobXReact.inject('getComponent', 'getProperties', 'getSlots', 'store', 'highlight')
@MobXReact.observer
class PreviewComponent extends React.Component<Types.SerializedElement> {
public componentWillUpdate(): void {
Expand All @@ -153,14 +158,10 @@ class PreviewComponent extends React.Component<Types.SerializedElement> {
const defaultContent = props.contents.find(content => content.slotType === 'children');
const children = defaultContent ? defaultContent.elements : [];

const slots = props.contents.filter(content => content.slotType !== 'children').reduce(
(acc, slot) => ({
...acc,
[slot.id]: slot.elements.map(child => <PreviewComponent key={child.id} {...child} />)
}),
{}
);

const slotsContents = props.contents.filter(content => content.slotType !== 'children');
const slots = props.getSlots(slotsContents, child => (
<PreviewComponent key={child.id} {...child} />
));
const properties = props.getProperties(props.properties);

// tslint:disable-next-line:no-any
Expand Down
20 changes: 20 additions & 0 deletions src/preview/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ function main(): void {
// tslint:disable-next-line:no-any
getComponent: createComponentGetter(store),
getProperties: createPropertiesGetter(store),
getSlots: createSlotGetter(store),
highlight,
store
});
Expand Down Expand Up @@ -314,4 +315,23 @@ function createPropertiesGetter(
}, {});
}

// tslint:disable:no-any
function createSlotGetter(
store: PreviewStore
): (contents: Types.SerializedPageElementContent[], render: any) => any {
return (contents, render) => {
const slots = store.components.reduce((acc, component) => [...acc, ...component.slots], []);

return contents.reduce((acc, content) => {
const slot = slots.find(s => s.id === content.slotId);

if (slot) {
acc[slot.propertyName] = content.elements.map(render);
}

return acc;
}, {});
};
}

main();
4 changes: 4 additions & 0 deletions src/store/element/element-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ export class ElementContent {
return this.elements;
}

public getId(): string {
return this.id;
}

public getSlotId(): string {
return this.slotId;
}
Expand Down
25 changes: 25 additions & 0 deletions src/store/element/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,31 @@ export class Element {
return this.container.getSlotType();
}

public getContentById(contentId: string): ElementContent | undefined {
let result;

for (const content of this.contents) {
if (content.getId() === contentId) {
result = content;
break;
}

for (const element of content.getElements()) {
result = element.getContentById(contentId);

if (result) {
break;
}
}

if (result) {
break;
}
}

return result;
}

public getContentBySlot(slot: PatternSlot): ElementContent | undefined {
return this.getContentBySlotId(slot.getId());
}
Expand Down
6 changes: 5 additions & 1 deletion src/store/page/page.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Element } from '../element';
import { Element, ElementContent } from '../element';
import * as Mobx from 'mobx';
import { SyntheticPatternType } from '../pattern';
import { Styleguide } from '../styleguide';
Expand Down Expand Up @@ -115,6 +115,10 @@ export class Page {
throw new Error(`Page ${this.getId()} needs to store context in order to be cloned`);
}

public getContentById(id: string): ElementContent | undefined {
return this.root.getContentById(id);
}

/**
* Get the current edited value of the page name
*/
Expand Down
1 change: 1 addition & 0 deletions src/store/pattern/pattern-slot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class PatternSlot {
this.id = init.id;
this.displayName = init.displayName;
this.type = init.type;
this.propertyName = init.propertyName;
}

public static from(serialized: Types.SerializedPatternSlot): PatternSlot {
Expand Down
28 changes: 22 additions & 6 deletions src/store/view-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
PageRemoveCommand
} from './command';

import { Element } from './element';
import { Element, ElementContent } from './element';
import * as Mobx from 'mobx';
import * as Os from 'os';
import { Page } from './page';
Expand Down Expand Up @@ -343,6 +343,19 @@ export class ViewStore {
return item.item.clone();
}

public getContentById(id: string): ElementContent | undefined {
const project = this.getCurrentProject();

let result;

project.getPages().some(page => {
result = page.getContentById(id);
return result;
});

return result;
}

/**
* Returns the page content that is currently being displayed in the preview,
* and edited in the elements and properties panes. May be undefined if there is none.
Expand Down Expand Up @@ -373,13 +386,16 @@ export class ViewStore {
}

public getElementById(id: string): Element | undefined {
const page = this.getCurrentPage();
const project = this.getCurrentProject();

if (!page) {
return;
}
let result;

project.getPages().some(page => {
result = page.getElementById(id);
return result;
});

return page.getElementById(id);
return result;
}

public getHighlightedElement(): Element | undefined {
Expand Down

0 comments on commit 23c4c2c

Please sign in to comment.