Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Designer: Added feature to create interactive component states #156

Merged
merged 3 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/adaptive-ui-figma-designer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"@csstools/css-calc": "^1.1.1",
"@csstools/css-parser-algorithms": "^2.2.0",
"@csstools/css-tokenizer": "^2.1.1",
"@figma/plugin-typings": "^1.58.0",
"@figma/plugin-typings": "^1.80.0",
"concurrently": "^7.6.0",
"esbuild": "^0.17.10",
"rimraf": "^3.0.2",
Expand Down
39 changes: 35 additions & 4 deletions packages/adaptive-ui-figma-designer/src/core/model.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
import { ValuesOf } from "@microsoft/fast-foundation";
import { StyleProperty } from "@adaptive-web/adaptive-ui";
import { PluginNode } from "./node.js";
import { SerializableNodeData } from "./serialization.js";

/**
* A key for passing the fill color from the tool to the plugin. Keeping it out of main design tokens to avoid a lot more special handling.
*/
export const TOOL_PARENT_FILL_COLOR = "tool-parent-fill-color";
export const AdditionalDataKeys = {
/**
* A key for passing the fill color from the tool to the plugin.
*
* @remarks
* Keeping it out of main design tokens to avoid a lot more special handling.
*/
toolParentFillColor: "tool-parent-fill-color",

/**
* The state of interactive state configuration. Applies to component sets.
*/
states: "states",

/**
* The interactive state of the node. Applies to all nodes.
*/
state: "state",
} as const;

export type AdditionalDataKeys = ValuesOf<typeof AdditionalDataKeys>;

/**
* A design token value.
Expand Down Expand Up @@ -269,3 +288,15 @@ export const pluginNodesToUINodes = (

return convertedNodes;
}

export interface CreateStatesMessage {
readonly type: 'CREATE_STATES';
id: string;
}

export interface NodeDataMessage {
readonly type: 'NODE_DATA';
nodes: SerializableNodeData[];
}

export type PluginMessage = CreateStatesMessage | NodeDataMessage;
36 changes: 32 additions & 4 deletions packages/adaptive-ui-figma-designer/src/core/node.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { ColorRGBA64 } from "@microsoft/fast-colors";
import { ValuesOf } from "@microsoft/fast-foundation";
import { StyleProperty } from "@adaptive-web/adaptive-ui";
import {
AdditionalData,
AdditionalDataKeys,
AppliedDesignTokens,
AppliedStyleModules,
AppliedStyleValues,
Expand All @@ -10,11 +12,20 @@ import {
ReadonlyAppliedDesignTokens,
ReadonlyAppliedStyleModules,
ReadonlyDesignTokenValues,
TOOL_PARENT_FILL_COLOR,
} from "./model.js";

const DesignTokenCache: Map<string, ReadonlyDesignTokenValues> = new Map();

export const StatesState = {
notAvailable: "notAvailable",
available: "available",
configured: "configured",
} as const;

export type StatesState = ValuesOf<typeof StatesState>;

export type State = "Rest" | "Hover" | "Active" | "Focus" | "Disabled";

/**
* The abstract class the plugin Controller interacts with.
* Acts as a basic intermediary for node structure and data storage only.
Expand Down Expand Up @@ -147,6 +158,16 @@ export abstract class PluginNode {
*/
public abstract readonly fillColor: ColorRGBA64 | null;

/**
* The state of stateful component capabilities for this node.
*/
public abstract readonly states: StatesState;

/**
* The interactive state of the node.
*/
public abstract get state(): string | null;

/**
* Gets whether this type of node can have children or not.
*/
Expand Down Expand Up @@ -229,10 +250,17 @@ export abstract class PluginNode {
* Gets additional data associated with this node.
*/
public get additionalData(): AdditionalData {
if (!this._additionalData.has(TOOL_PARENT_FILL_COLOR) && this.parent?.fillColor) {
// console.log("PluginNode.get_additionalData - adding:", TOOL_PARENT_FILL_COLOR, this.debugInfo, this.parent?.fillColor.toStringHexARGB());
this._additionalData.set(TOOL_PARENT_FILL_COLOR, this.parent.fillColor.toStringHexARGB());
this._additionalData.set(AdditionalDataKeys.states, this.states);

if (this.state) {
this._additionalData.set(AdditionalDataKeys.state, this.state);
}

if (!this._additionalData.has(AdditionalDataKeys.toolParentFillColor) && this.parent?.fillColor) {
// console.log("PluginNode.get_additionalData - adding:", AdditionalDataKeys.toolParentFillColor, this.debugInfo, this.parent?.fillColor.toStringHexARGB());
this._additionalData.set(AdditionalDataKeys.toolParentFillColor, this.parent.fillColor.toStringHexARGB());
}

return this._additionalData;
}

Expand Down
23 changes: 17 additions & 6 deletions packages/adaptive-ui-figma-designer/src/figma/controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Controller, PluginUIState } from "../core/controller.js";
import type { PluginMessage } from "../core/model.js";
import { deserializeUINodes, SerializableUIState, serializeUINodes } from "../core/serialization.js";
import { FigmaPluginNode } from "./node.js";

Expand All @@ -12,20 +13,30 @@ export class FigmaController extends Controller {
}
}

public handleMessage(state: SerializableUIState): void {
const pluginNodes = deserializeUINodes(state.selectedNodes);
super.receiveStateFromUI({
selectedNodes: pluginNodes
})
public handleMessage(message: PluginMessage): void {
if (message.type === "NODE_DATA") {
const pluginNodes = deserializeUINodes(message.nodes);
super.receiveStateFromUI({
selectedNodes: pluginNodes
});

FigmaPluginNode.clearCache();
FigmaPluginNode.clearCache();
} else if (message.type === "CREATE_STATES") {
const node = this.getNode(message.id);
// Create the interactive state components
node?.createStates();
// Resend the nodes to the plugin UI
FigmaPluginNode.clearCache();
this.setSelectedNodes([message.id]);
}
}

public sendStateToUI(state: PluginUIState): void {
const message: SerializableUIState = {
selectedNodes: serializeUINodes(state.selectedNodes),
};

// Goes to ../ui/index.ts window.onmessage
figma.ui.postMessage(message);
}
}
5 changes: 3 additions & 2 deletions packages/adaptive-ui-figma-designer/src/figma/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SerializableUIState } from "../core/serialization.js";
import { PluginMessage } from "../core/model.js";
import { FigmaController } from "./controller.js";

const controller = new FigmaController();
Expand Down Expand Up @@ -62,7 +62,8 @@ function debounceSelection() {

figma.on("selectionchange", debounceSelection);

figma.ui.onmessage = (message: SerializableUIState): void => {
// Comes from ../ui/index.ts parent.postMessage
figma.ui.onmessage = (message: PluginMessage): void => {
notifyProcessing(() => {
controller.handleMessage(message);
});
Expand Down
Loading
Loading