Skip to content

Commit

Permalink
feat: allow to use slot in primary inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
KermanX committed Nov 12, 2023
1 parent 6ced687 commit c1d61e3
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 64 deletions.
10 changes: 10 additions & 0 deletions packages/compiler/src/types/componentBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ export type ComponentBlockPlugins = Record<string, string>;
*/
export type ComponentBlockChildren = Record<string, string | number[]>;

export type ComponentBlockPrimaryInput = {
name: string;
value: string;
slots: Record<string, ConnectTo>;
} | null;

export interface ComponentBlockOutput {
type: "component";
id: number;
Expand Down Expand Up @@ -43,4 +49,8 @@ export interface ComponentBlockOutput {
* 子元素的block的id
*/
children: ComponentBlockChildren;
/**
* Primary input的信息
*/
primaryInput: ComponentBlockPrimaryInput;
}
15 changes: 1 addition & 14 deletions packages/compiler/src/types/specialBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,7 @@ export interface FuncBlockOutput {
type: Exclude<FuncBlockTypes, "imp" | "validator" | "state" | "state-setter">;
id: number;
value: string;
inputs: {
/**
* slot name. i.e. function parameter name
*/
slot: string;
/**
* connected block id
*/
blockId: number;
/**
* connected line start end socket name
*/
socketName: string;
}[];
slots: Record<string, ConnectTo>;
output: ConnectTo[];
}

Expand Down
33 changes: 22 additions & 11 deletions packages/compiler/src/viewCompiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
ComponentBlockChildren,
ComponentBlockOutput,
ComponentBlockPlugins,
ComponentBlockPrimaryInput,
ComponentBlockProps,
FuncBlockOutput,
IfBlockOutput,
Expand Down Expand Up @@ -103,25 +104,27 @@ const ${this.view.name}_view = ${
`;
}

compileStringBlock(block: FuncBlockOutput): string {
compileStringBlock(
block: FuncBlockOutput | Exclude<ComponentBlockPrimaryInput, null>,
): string {
return `\`${block.value.replace(/\{([a-zA-Z0-9]+)\}/g, (_, name) => {
const input = block.inputs.find((i) => i.slot === name);
if (!input) {
throw new Error(`Cannot find input ${name} in block ${block.id}`);
const slot = Object.entries(block.slots).find(([k]) => k === name);
if (!slot) {
throw new Error(`Cannot find input ${name}`);
}
return `\${${this.compileDataLineEnd(input)}}`;
return `\${${this.compileDataLineEnd(slot[1])}}`;
})}\``;
}

compileExprBlock(
block: FuncBlockOutput | StateBlockOutput | StateSetterBlockOutput,
): string {
return block.value.replace(/\$([a-zA-Z0-9]+)/g, (_, name) => {
const input = block.inputs.find((i) => i.slot === name);
if (!input) {
const slot = Object.entries(block.slots).find(([k]) => k === name);
if (!slot) {
throw new Error(`Cannot find input ${name} in block ${block.id}`);
}
return `(${this.compileDataLineEnd(input)})`;
return `(${this.compileDataLineEnd(slot[1])})`;
});
}

Expand Down Expand Up @@ -198,11 +201,11 @@ const ${this.view.name}_view = ${
const result = (() => {${block.value.replace(
/\$([a-zA-Z0-9]+)/g,
(_, name) => {
const input = block.inputs.find((i) => i.slot === name);
if (!input) {
const slot = Object.entries(block.slots).find(([k]) => k === name);
if (!slot) {
throw new Error(`Cannot find input ${name} in block ${block.id}`);
}
return `(${this.compileDataLineEnd(input)})`;
return `(${this.compileDataLineEnd(slot[1])})`;
},
)}})();
${this.compileEventLineStart(block.then)};
Expand Down Expand Up @@ -331,6 +334,13 @@ const ${this.view.name}_view = ${
return modelId;
}

compileComponentPrimaryInput(
primaryInput: ComponentBlockPrimaryInput,
): Record<string, string> {
if (!primaryInput) return {};
return { [primaryInput.name]: this.compileStringBlock(primaryInput) };
}

compileComponentProps(props: ComponentBlockProps): Record<string, string> {
return Object.fromEntries(
Object.entries(props).map(([k, v]) => {
Expand Down Expand Up @@ -395,6 +405,7 @@ const ${this.view.name}_view = ${
: ""
}{
${Object.entries({
...this.compileComponentPrimaryInput(block.primaryInput),
...this.compileComponentProps(block.props),
...this.compileComponentCallbacks(block.callbacks),
...this.compileComponentPlugins(block.plugins),
Expand Down
38 changes: 38 additions & 0 deletions packages/northstar/src/blocks/component/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,37 @@ export class ComponentBlock extends RectBlock {
info: ComponentInfo;
props: Record<string, string | boolean> = {};

get primaryInputInfo() {
return (
this.info.inputs.find(
(input) =>
input.kind === "as-primary" || input.kind === "as-primary-and-socket",
) ??
this.info.contents.find(
(content) =>
content.kind === "as-primary" ||
content.kind === "as-primary-and-socket",
)
);
}

primaryValue = d("");
get primaryFilled() {
return this.primaryValue.value !== "";
}
getPrimaryDisabled = () => false;

slotsDirection = Direction.TOP;
get slots() {
const template = this.primaryValue.value;
const matches = template.matchAll(/\{[a-zA-Z0-9_]+\}/g);
return [...matches].map((match) => match[0].slice(1, -1));
}

get slotSockets() {
return this.getSocketsByPrefix("slot") as SingleInSocket[];
}

socketUpdater(useSocket: UseSocket): void {
const { contents, events, inputs, outputs, methods } = this.info;

Expand All @@ -67,6 +92,17 @@ export class ComponentBlock extends RectBlock {
direction: Direction.LEFT,
});

if (this.primaryInputInfo) {
for (const slot of this.slots) {
useSocket(`slot-${slot}`, SingleInSocket, {
label: slot,
type: "D",
path: PATH_IN_ELIPSE,
direction: this.slotsDirection,
});
}
}

const shouldHideSocket = (socketInfo: { kind: string; name: string }) => {
const prop = this.props[`[${socketInfo.name}]`];
return (
Expand Down Expand Up @@ -145,6 +181,7 @@ export class ComponentBlock extends RectBlock {
componentType: this.componentType,
props: this.props,
primaryValue: this.primaryValue.value,
slotsDirection: this.slotsDirection,
};
}
protected importData(data: any, sockets: Record<number, Socket>): void {
Expand All @@ -153,6 +190,7 @@ export class ComponentBlock extends RectBlock {
this.info = blocksObj[data.componentType as keyof typeof blocksObj];
this.props = data.props;
this.primaryValue.value = data.primaryValue;
this.slotsDirection = data.slotsDirection;
this.content = getContent(this);
}
}
Expand Down
16 changes: 4 additions & 12 deletions packages/northstar/src/blocks/component/getContent.r.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,13 @@ import { currentGraph } from "../../store";
import { ComponentBlock } from "./block";

export function getContent(block: ComponentBlock) {
const {
info: { inputs, contents, name },
props,
} = block;

const info =
inputs.find(input => input.kind === "as-primary" || input.kind === "as-primary-and-socket") ??
contents.find(content => content.kind === "as-primary" || content.kind === "as-primary-and-socket");

const title = (_: Context) => {
_.$cls`mx-2 text-sm`;
_.span(name(props));
_.span(block.info.name(block.props));
};
const primaryInputInfo = block.primaryInputInfo;

if (!info) return title;
if (!primaryInputInfo) return title;
return (_: Context) => {
_.$cls`text-gray-600`;
title(_);
Expand All @@ -35,7 +27,7 @@ export function getContent(block: ComponentBlock) {
_ => {
const inputRef = ref<FUnderlineTextInput>();
_.$css`font-family: Consolas; max-width: 108px; padding-left:4px`;
_.$ref(inputRef) && _.fUnderlineTextInput(block.primaryValue, false, info.name);
_.$ref(inputRef) && _.fUnderlineTextInput(block.primaryValue, false, primaryInputInfo.name);
inputRef.current!.inputRef.current!.node.onchange = () => {
currentGraph.pushRecord();
};
Expand Down
21 changes: 19 additions & 2 deletions packages/northstar/src/blocks/component/getProps.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
import { directionNameMap, directionMap } from "@quasi-dev/visual-flow";
import { PropData, PropsData } from "../../utils/props";
import { ComponentBlock } from "./block";

export function getProps(block: ComponentBlock): PropsData {
const { info } = block;

const slotPos: PropData[] = [];
const primaryInputInfo = block.primaryInputInfo;
if (primaryInputInfo) {
slotPos.push({
name: "slots pos",
type: "dropdown",
options: ["TOP", "BOTTOM"],
getVal: () => {
return directionNameMap[block.slotsDirection];
},
setVal: (val) => {
block.slotsDirection = directionMap[val];
},
});
}

return [
...slotPos,
...info.props.map(
(v) =>
({
Expand Down Expand Up @@ -37,8 +55,7 @@ export function getProps(block: ComponentBlock): PropsData {
type: "switch",
getVal: () => {
return (
block.props[`[${v.name}]`] ??
v.kind === "as-hidable-socket"
block.props[`[${v.name}]`] ?? v.kind === "as-hidable-socket"
);
},
setVal: (val: any) => {
Expand Down
56 changes: 36 additions & 20 deletions packages/northstar/src/blocks/component/toBlockOutput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import type {
ComponentBlockChildren,
ComponentBlockOutput,
ComponentBlockPlugins,
ComponentBlockPrimaryInput,
ComponentBlockProps,
ConnectTo,
} from "@quasi-dev/compiler";
import { Block, SingleOutSocket, Socket } from "@quasi-dev/visual-flow";
import { singleOutSocketToOutput } from "../../utils/toOutpus";
import {
singleInSocketToOutput,
singleOutSocketToOutput,
} from "../../utils/toOutpus";
import { ValidatorBlock } from "../special/validator";
import { ComponentBlock } from "./block";

Expand All @@ -28,32 +33,28 @@ export function toBlockOutput(block: ComponentBlock) {
if (
input.kind === "as-primary" ||
(input.kind === "as-primary-and-socket" && block.primaryFilled)
) {
props[input.name] = block.primaryValue.value;
} else {
const socket = block.getSocketByName(input.name)?.allConnectedLines[0]?.a;
props[input.name] = {
blockId: socket?.block.id ?? NaN,
socketName: socket?.label ?? "",
};
}
)
continue;
const socket = block.getSocketByName(input.name)?.allConnectedLines[0]?.a;
props[input.name] = {
blockId: socket?.block.id ?? NaN,
socketName: socket?.label ?? "",
};
}

let children = {} as ComponentBlockChildren;
for (const content of block.info.contents) {
if (
content.kind === "as-primary" ||
(content.kind === "as-primary-and-socket" && block.primaryFilled)
) {
children[content.name] = block.primaryValue.value;
} else {
children[content.name] =
block
.getSocketByName(content.name)
?.allConnectedLines.map((l) => (l.b as Socket).block)
.sort((a, b) => a.boardY - b.boardY)
.map((b) => b.id) ?? [];
}
)
continue;
children[content.name] =
block
.getSocketByName(content.name)
?.allConnectedLines.map((l) => (l.b as Socket).block)
.sort((a, b) => a.boardY - b.boardY)
.map((b) => b.id) ?? [];
}

let plugins = {} as ComponentBlockPlugins;
Expand Down Expand Up @@ -88,6 +89,20 @@ export function toBlockOutput(block: ComponentBlock) {
}`;
}

let primaryInput: ComponentBlockPrimaryInput = null;
const primaryInputInfo = block.primaryInputInfo;
if (primaryInputInfo) {
const slots: Record<string, ConnectTo> = {};
for (const socket of block.slotSockets) {
slots[socket.label] = singleInSocketToOutput(socket);
}
primaryInput = {
name: primaryInputInfo.name,
value: block.primaryValue.value,
slots,
};
}

return {
type: "component",
func: block.componentType,
Expand All @@ -98,5 +113,6 @@ export function toBlockOutput(block: ComponentBlock) {
props,
plugins,
children,
primaryInput,
} satisfies ComponentBlockOutput;
}
10 changes: 5 additions & 5 deletions packages/northstar/src/blocks/special/FuncBlockBase.r.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {
ConnectTo,
FuncBlockOutput,
FuncBlockTypes,
ImpBlockOutput,
Expand Down Expand Up @@ -149,20 +150,19 @@ export abstract class FuncBlockBase extends RectBlock implements SpecialBlock {
}

toOutput(): FuncBlockOutput | ValidatorBlockOutput | ImpBlockOutput | StateBlockOutput | StateSetterBlockOutput {
const inputs = [];
const slots: Record<string, ConnectTo> = {};
for (const socket of this.inputSockets) {
inputs.push({
slot: socket.label,
slots[socket.label] = {
blockId: socket.connectedLine?.a.block.id ?? NaN,
socketName: socket.connectedLine?.a.label ?? "",
});
};
}

return {
type: this.type as any,
id: this.id,
value: this.inputValue.value,
inputs,
slots,
output: multiOutSocketToOutput(this.outputSocket),
};
}
Expand Down

0 comments on commit c1d61e3

Please sign in to comment.