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

Commit

Permalink
feat: add synthetic conditional component
Browse files Browse the repository at this point in the history
  • Loading branch information
marionebl committed Sep 10, 2018
1 parent 1b4f49f commit e7cf6ba
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 58 deletions.
70 changes: 70 additions & 0 deletions src/model/pattern-library/builtins/conditional.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Pattern, PatternSlot } from '../../pattern';
import { BuiltInContext, BuiltInResult } from '../pattern-library';
import * as PatternProperty from '../../pattern-property';
import * as Types from '../../../types';

const PATTERN_CONTEXT_ID = 'synthetic:conditional';
const CONDITION_CONTEXT_ID = 'condition';
const TRUTHY_SLOT_CONTEXT_ID = 'truthy';
const FALSY_SLOT_CONTEXT_ID = 'falsy';

export const Conditional = (context: BuiltInContext): BuiltInResult => {
const patternId = context.options.getGlobalPatternId(PATTERN_CONTEXT_ID);

const properties = [
new PatternProperty.PatternBooleanProperty({
contextId: CONDITION_CONTEXT_ID,
description: 'Show the "True" slot, disable to show the "False" slot',
defaultValue: true,
hidden: false,
id: context.options.getGlobalPropertyId(patternId, CONDITION_CONTEXT_ID),
label: 'Condition',
origin: Types.PatternPropertyOrigin.BuiltIn,
propertyName: 'condition',
required: true
})
];

const slots = [
new PatternSlot({
contextId: TRUTHY_SLOT_CONTEXT_ID,
displayName: 'If True',
description: '',
example: '',
hidden: false,
propertyName: 'ifTrue',
id: context.options.getGlobalSlotId(patternId, TRUTHY_SLOT_CONTEXT_ID),
required: false,
type: Types.SlotType.Property
}),
new PatternSlot({
contextId: FALSY_SLOT_CONTEXT_ID,
displayName: 'If False',
description: '',
example: '',
hidden: false,
propertyName: 'ifFalse',
id: context.options.getGlobalSlotId(patternId, FALSY_SLOT_CONTEXT_ID),
required: false,
type: Types.SlotType.Property
})
];

return {
pattern: new Pattern(
{
contextId: PATTERN_CONTEXT_ID,
description: 'for conditional rendering',
exportName: 'default',
id: patternId,
name: 'Conditional',
origin: Types.PatternOrigin.BuiltIn,
propertyIds: properties.map(p => p.getId()),
slots,
type: Types.PatternType.SyntheticConditional
},
context
),
properties
};
};
1 change: 1 addition & 0 deletions src/model/pattern-library/builtins/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './box';
export * from './conditional';
export * from './link';
export * from './page';
export * from './image';
Expand Down
67 changes: 40 additions & 27 deletions src/model/pattern-library/pattern-library.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { computeDifference } from '../../alva-util';
import { Box, Image, Link, Page, Text } from './builtins';
import * as Fuse from 'fuse.js';
import { Box, Conditional, Image, Link, Page, Text } from './builtins';
import { isEqual } from 'lodash';
import * as Mobx from 'mobx';
import { Pattern, PatternSlot } from '../pattern';
Expand Down Expand Up @@ -42,14 +41,18 @@ export class PatternLibrary {
@Mobx.observable private bundleId: string;
@Mobx.observable private bundle: string;
@Mobx.observable private description: string;
@Mobx.observable private fuse: Fuse;
@Mobx.observable private id: string;
@Mobx.observable private name: string;
@Mobx.observable private patternProperties: Map<string, AnyPatternProperty> = new Map();
@Mobx.observable private patterns: Map<string, Pattern> = new Map();
@Mobx.observable private origin: Types.PatternLibraryOrigin;
@Mobx.observable private state: Types.PatternLibraryState;

@Mobx.computed
private get slots(): PatternSlot[] {
return this.getPatterns().reduce((acc, pattern) => [...acc, ...pattern.getSlots()], []);
}

public constructor(init: PatternLibraryInit) {
this.bundleId = init.bundleId;
this.bundle = init.bundle;
Expand All @@ -60,12 +63,14 @@ export class PatternLibrary {
init.patterns.forEach(pattern => this.patterns.set(pattern.getId(), pattern));
init.patternProperties.forEach(prop => this.patternProperties.set(prop.getId(), prop));
this.state = init.state;
this.updateSearch();
}

public static create(init: PatternLibraryInit): PatternLibrary {
const options = {
getGloablEnumOptionId: () => uuid.v4(),
public static create(
init: PatternLibraryInit,
opts?: PatternLibraryCreateOptions
): PatternLibrary {
const options = opts || {
getGlobalEnumOptionId: () => uuid.v4(),
getGlobalPatternId: () => uuid.v4(),
getGlobalPropertyId: () => uuid.v4(),
getGlobalSlotId: () => uuid.v4()
Expand All @@ -79,8 +84,16 @@ export class PatternLibrary {
const image = Image({ options, patternLibrary });
const text = Text({ options, patternLibrary });
const box = Box({ options, patternLibrary });
const conditional = Conditional({ options, patternLibrary });

[page.pattern, text.pattern, box.pattern, image.pattern, link.pattern].forEach(pattern => {
[
page.pattern,
text.pattern,
box.pattern,
conditional.pattern,
image.pattern,
link.pattern
].forEach(pattern => {
patternLibrary.addPattern(pattern);
});

Expand All @@ -89,6 +102,7 @@ export class PatternLibrary {
...image.properties,
...text.properties,
...box.properties,
...conditional.properties,
...link.properties
].forEach(property => {
patternLibrary.addProperty(property);
Expand Down Expand Up @@ -177,7 +191,6 @@ export class PatternLibrary {
propChanges.changed.map(change => change.before.update(change.after));

this.setState(Types.PatternLibraryState.Connected);
this.updateSearch();

this.setBundle(analysis.bundle);
this.setBundleId(analysis.id);
Expand All @@ -188,7 +201,6 @@ export class PatternLibrary {

public addPattern(pattern: Pattern): void {
this.patterns.set(pattern.getId(), pattern);
this.updateSearch();
}

public addProperty(property: AnyPatternProperty): void {
Expand Down Expand Up @@ -307,21 +319,13 @@ export class PatternLibrary {
}

public getSlots(): PatternSlot[] {
return this.getPatterns().reduce((acc, pattern) => [...acc, ...pattern.getSlots()], []);
return this.slots;
}

public getState(): Types.PatternLibraryState {
return this.state;
}

public query(term: string): string[] {
if (term.trim().length === 0) {
return this.getPatterns().map(p => p.getId());
}

return this.fuse.search<Types.SerializedPattern>(term).map(match => match.id);
}

@Mobx.action
public removePattern(pattern: Pattern): void {
this.patterns.delete(pattern.getId());
Expand Down Expand Up @@ -379,18 +383,27 @@ export class PatternLibrary {
this.id = b.id;
this.name = b.name;
this.origin = b.origin;
this.patterns = b.patterns;
this.patternProperties = b.patternProperties;
this.state = this.state;
}

@Mobx.action
public updateSearch(): void {
const registry = this.getPatterns().map(item => item.toJSON());
const patternChanges = computeDifference<Pattern>({
before: this.getPatterns(),
after: b.getPatterns()
});

this.fuse = new Fuse(registry, {
keys: ['name']
patternChanges.added.forEach(change => this.addPattern(change.after));
patternChanges.changed.forEach(change =>
change.before.update(change.after, { patternLibrary: this })
);
patternChanges.removed.forEach(change => this.removePattern(change.before));

const propertyChanges = computeDifference<AnyPatternProperty>({
before: this.getPatternProperties(),
after: b.getPatternProperties()
});

propertyChanges.added.forEach(change => this.addProperty(change.after));
propertyChanges.changed.forEach(change => change.before.update(change.after));
propertyChanges.removed.forEach(change => this.removeProperty(change.before));
}
}

Expand Down
16 changes: 16 additions & 0 deletions src/model/pattern/pattern-slot.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as Types from '../../types';
import * as _ from 'lodash';

export interface PatternSlotInit {
contextId: string;
Expand Down Expand Up @@ -50,6 +51,10 @@ export class PatternSlot {
});
}

public equals(b: PatternSlot): boolean {
return _.isEqual(this.toJSON(), b.toJSON());
}

public getContextId(): string {
return this.contextId;
}
Expand Down Expand Up @@ -87,6 +92,17 @@ export class PatternSlot {
type: this.type
};
}

public update(b: this): void {
this.contextId = b.contextId;
this.description = b.description;
this.example = b.example;
this.hidden = b.hidden;
this.displayName = b.displayName;
this.propertyName = b.propertyName;
this.required = b.required;
this.type = b.type;
}
}

function toSlotType(type: string): Types.SlotType {
Expand Down
29 changes: 23 additions & 6 deletions src/model/pattern/pattern.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class Pattern {
@Mobx.observable private origin: Types.PatternOrigin;
@Mobx.observable private patternLibrary: PatternLibrary;
@Mobx.observable private propertyIds: Set<string> = new Set();
@Mobx.observable private slots: PatternSlot[];
@Mobx.observable private slots: Map<string, PatternSlot> = new Map();
@Mobx.observable private type: Types.PatternType;

public constructor(init: PatternInit, context: PatternContext) {
Expand All @@ -44,8 +44,9 @@ export class Pattern {
this.origin = init.origin;
this.patternLibrary = context.patternLibrary;
this.propertyIds = new Set(init.propertyIds);
this.slots = init.slots;
this.type = init.type;

init.slots.forEach(slot => this.slots.set(slot.getId(), slot));
}

public static from(serialized: Types.SerializedPattern, context: PatternContext): Pattern {
Expand All @@ -70,7 +71,7 @@ export class Pattern {
}

public addSlot(slot: PatternSlot): void {
this.slots.push(slot);
this.slots.set(slot.getId(), slot);
}

public equals(b: Pattern): boolean {
Expand Down Expand Up @@ -118,7 +119,7 @@ export class Pattern {
}

public getSlots(): PatternSlot[] {
return this.slots;
return [...this.slots.values()];
}

public getType(): Types.PatternType {
Expand All @@ -129,6 +130,10 @@ export class Pattern {
this.propertyIds.delete(property.getId());
}

public removeSlot(slot: PatternSlot): void {
this.slots.delete(slot.getId());
}

public toJSON(): Types.SerializedPattern {
return {
contextId: this.contextId,
Expand All @@ -138,7 +143,7 @@ export class Pattern {
name: this.name,
origin: serializeOrigin(this.origin),
propertyIds: Array.from(this.propertyIds),
slots: this.slots.map(slot => slot.toJSON()),
slots: this.getSlots().map(slot => slot.toJSON()),
type: serializeType(this.type)
};
}
Expand All @@ -151,8 +156,16 @@ export class Pattern {
this.origin = pattern.getOrigin();
this.patternLibrary = context.patternLibrary;
this.propertyIds = pattern.propertyIds;
this.slots = pattern.getSlots();
this.type = pattern.getType();

const slotChanges = AlvaUtil.computeDifference<PatternSlot>({
before: this.getSlots(),
after: pattern.getSlots()
});

slotChanges.added.forEach(change => this.addSlot(change.after));
slotChanges.changed.forEach(change => change.before.update(change.after));
slotChanges.removed.forEach(change => this.removeSlot(change.before));
}
}

Expand All @@ -178,6 +191,8 @@ function deserializeType(input: Types.SerializedPatternType): Types.PatternType
return Types.PatternType.SyntheticText;
case 'synthetic:link':
return Types.PatternType.SyntheticLink;
case 'synthetic:conditional':
return Types.PatternType.SyntheticConditional;
case 'pattern':
return Types.PatternType.Pattern;
}
Expand All @@ -202,6 +217,8 @@ function serializeType(input: Types.PatternType): Types.SerializedPatternType {
return 'synthetic:box';
case Types.PatternType.SyntheticImage:
return 'synthetic:image';
case Types.PatternType.SyntheticConditional:
return 'synthetic:conditional';
case Types.PatternType.SyntheticText:
return 'synthetic:text';
case Types.PatternType.SyntheticLink:
Expand Down
Loading

0 comments on commit e7cf6ba

Please sign in to comment.