Skip to content
Draft
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
1 change: 1 addition & 0 deletions app/__plugin__init__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ import "../lib/pages/code/__plugin";
import "@app/data-mapper/__plugin";
import "@app/design-lint/__plugin";
import "@app/design-text-code-syntax-highlight/__plugin";
import "@app/mdx-processor/__plugn";
3 changes: 3 additions & 0 deletions app/lib/main/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { IconsScreen } from "@app/icons-loader";
import { MetaEditorScreen, BatchMetaEditor } from "@app/meta-editor";
import { ExporterScreen } from "@app/export-scene-as-json";
import { DataMapperScreen } from "@app/data-mapper";
import { MdxProcessorScreen } from "@app/mdx-processor";
import { GlobalizationScreen } from "@app/i18n";
import { ToolboxScreen } from "../pages/tool-box";
import { FontReplacerScreen } from "@toolbox/font-replacer";
Expand Down Expand Up @@ -63,6 +64,8 @@ function Screen(props: { screen: WorkScreen }) {
return <ComponentViewScreen />;
case WorkScreen.layout:
return <LayoutViewScreen />;
case WorkScreen.code_mdx:
return <MdxProcessorScreen />;
case WorkScreen.icon:
return <IconsScreen />;
case WorkScreen.lint:
Expand Down
3 changes: 3 additions & 0 deletions app/lib/navigation/layout-preference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function getWorkmodeTabLayout(workspaceMode: WorkMode): TabLayout {
WorkScreen.component,
WorkScreen.layout,
WorkScreen.lint,
WorkScreen.code_mdx,
];
case WorkMode.design:
return [
Expand Down Expand Up @@ -49,6 +50,8 @@ export function workScreenToName(appMode: WorkScreen): string {
return "flutter";
case WorkScreen.code_react:
return "react";
case WorkScreen.code_mdx:
return "mdx";
case WorkScreen.component:
return "component";
case WorkScreen.layout:
Expand Down
7 changes: 7 additions & 0 deletions app/lib/navigation/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ const page_code_component: PageConfig = {
path: "/code/component",
};

const page_code_mdx: PageConfig = {
id: WorkScreen.code_mdx,
title: "MDX",
path: "/code/mdx",
};

const page_code_lint: PageConfig = {
id: WorkScreen.lint,
title: "Lint",
Expand Down Expand Up @@ -130,6 +136,7 @@ const all_pages: PageConfig[] = [
page_code_preview,
page_code_component,
page_code_lint,
page_code_mdx,
page_toolbox_code_syntax_highlight /** temporarily under design workmode */,
// standalones
page_signup,
Expand Down
1 change: 1 addition & 0 deletions app/lib/navigation/release-visibility-preference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const SCREEN_VISIBILITY_PREFERENCE: Map<WorkScreen, ReleaseChannel> = new Map([
[WorkScreen.layout, "beta"],
[WorkScreen.icon, "release"],
[WorkScreen.lint, "release"],
[WorkScreen.code_mdx, "beta"],
[WorkScreen.g11n, "beta"],
[WorkScreen.exporter, "beta"],
[WorkScreen.dev, "beta"],
Expand Down
1 change: 1 addition & 0 deletions app/lib/navigation/work-screen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum WorkScreen {
code_flutter = "code/flutter",
/** @deprecated only used for sendig event */
code_react = "code/react",
code_mdx = "code_mdx",
component = "component",
layout = "layout",
icon = "icon",
Expand Down
5 changes: 2 additions & 3 deletions figma-core/code-thread/runon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
EK_IMAGE_ASSET_REPOSITORY_MAP,
EK_VANILLA_TRANSPORT,
} from "@core/constant/ek.constant";
import { vanilla } from "@design-sdk/core";
import * as vanilla from "@design-sdk/vanilla";
import { ReflectFrameNode, ReflectSceneNode } from "@design-sdk/core/nodes";
import { user_interest } from "./user-interest";
import { broadcastSelectionPreview } from "./broadcast-selection-preview";
Expand Down Expand Up @@ -37,8 +37,7 @@ export async function runon(rnode: ReflectSceneNode) {
// region make vanilla
if (user_interest == "g11n" || user_interest == "exporter") {
const globalizatoinScreen = vanilla.makeVanilla(rnode as ReflectFrameNode);
const vanillaTransportableImageRepository =
await globalizatoinScreen.repository.makeTransportable();
const vanillaTransportableImageRepository = await globalizatoinScreen.repository.makeTransportable();
figma.ui.postMessage({
type: EK_IMAGE_ASSET_REPOSITORY_MAP,
data: vanillaTransportableImageRepository,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"packages/base-sdk/_firstparty/*",
"packages/reflect-core/packages/*",
"packages/design-to-code/packages/designto-*",
"packages/design-to-code/packages/builder-config",
"packages/design-to-code/packages/builder-*",
"packages/design-to-code/packages/coli/packages/*",
"packages/design-to-code/packages/coli-web-builder/*",
"packages/design-to-code/packages/reflect-detection"
Expand Down
7 changes: 4 additions & 3 deletions packages/app-data-mapper/__plugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Figma } from "@design-sdk/figma";
import { PluginSdk } from "@plugin-sdk/app";
import { extractDataFromDataSourceNode } from "../data-source-node";
import { onService, _Event_DataMapper_GoodUserInputTransfer } from "./events";
import { FigmaEnum } from "@design-sdk/figma/features/variant";

export const TEMPLATE_NODE_PATTERN = "@//template-for-manipulation/*";

Expand Down Expand Up @@ -183,18 +184,18 @@ function mapVariant_try(
const set = variant.extractTypeFromVariantNames_Figma(_names);

for (const s of set) {
const value = data[s.name];
const value = data[s.key];
const _isConpat =
value && typeof s.type == "string"
? s.type == value
: s.type.includes(value);
: (s.type as FigmaEnum).values.includes(value);

if (_isConpat) {
// 4. map the variant

const swappingName = variant.buildVariantNameIncluding_Figma({
including: {
swapPropertyName: s.name,
swapPropertyName: s.key,
swapPropertyValue: value,
thisOriginName: thisVariantName,
},
Expand Down
39 changes: 39 additions & 0 deletions packages/app-mdx-processor/__plugn/event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { PluginSdk } from "@plugin-sdk/app";
import { PluginSdkService } from "@plugin-sdk/service";

const _KEY = "@app/mdx-processor";

export type Requests = ParseMdxRequest;
export interface ParseMdxRequest {
type: "request-parse-mdx-from-frame";
/**
* target frame id to parse
*/
frame: string;
/**
* @deprecated - wip
*/
options?: {
customComponents?: {}[];
};
}

export interface MdxParsedResponse {
/**
* full mdx code
*/
mdx: string;
/**
* @deprecated - not implemented
* mdx value mapped by node id
*/
map?: { [node: string]: string };
}

export function fromApp(req: Requests) {
PluginSdk.appEvent(_KEY, req);
}

export function onService(cb: (data: Requests) => void) {
PluginSdkService.onAppReqquest(_KEY, cb);
}
158 changes: 158 additions & 0 deletions packages/app-mdx-processor/__plugn/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { mapGrandchildren } from "@design-sdk/core/utils";
import { getTextStyleById } from "@design-sdk/figma";
import { Minimatch } from "minimatch";
import {
MdxParsedResponse,
onService,
ParseMdxRequest,
Requests,
} from "./event";
import * as make from "./make";

///
/// register
onService(main_cb);
/// register
///

function main_cb(data: Requests) {
switch (data.type) {
case "request-parse-mdx-from-frame": {
const frame = figma.getNodeById(data.frame);
const res = frameToMdx(frame as FrameNode);
console.log("handling with res - ", res);
if (res) {
figma.ui.postMessage({
type: "parse-mdx-from-frame-result", // TODO: make this constant shared key
data: res,
});
} else {
console.log(
`tried to make mdx from frame ${frame.name}, but failed. no parsable content.`
);
}
break;
}
}
}

function frameToMdx(frame: FrameNode): MdxParsedResponse | false {
if (!isMdxFrame(frame)) {
console.log(`${frame.name} is not a mdx frame. skipping.`);
return false;
}

// currently we only loop trhough 1 depth under frame. TODO: this needs to be fixed.
const lines = Array.from(frame.children)
.sort(sort_by_x)
.map((child) => {
switch (child.type) {
case "TEXT": {
const text = child as TextNode;
if (isTextMixed(text)) {
// TODO: additional mixed style handling is required.
return text.characters;
} else {
// since no style is mixed, we can return the value as is.
const mdx_textstyle = isMdxTextStyle(
text.textStyleId
? getTextStyleById(text.textStyleId as string).name
: ""
);
switch (mdx_textstyle) {
case false:
return make.paragraph(text.characters);
case "h1":
return make.h1(text.characters);
case "h2":
return make.h2(text.characters);
case "h3":
return make.h3(text.characters);
case "h4":
return make.h4(text.characters);
case "h5":
return make.h5(text.characters);
case "h6":
return make.h6(text.characters);
}
return make.unknown(text.characters);
}
break;
}
}
});

return {
mdx: lines.join("\n"),
};
}

const sort_by_x = (a: { x: number }, b: { x: number }) => {
return a.x - b.x;
};

/**
* returns if text contains mixed content. e.g.
*
* ```mdx
* this is a __mixed__ content example. also with **bold** texts.
* ```
* @returns
*/
function isTextMixed(text: TextNode): boolean {
if (
text.textStyleId === figma.mixed ||
text.fontName === figma.mixed ||
text.fontSize === figma.mixed ||
text.fills === figma.mixed
// add more validation here
) {
return true;
}
return false;
}

/**
* returns all text style that is included under target frame. (including grandchilds)
* @param frame
* @returns
*/
function readTextStyles(frame: FrameNode): string[] {
const all_text: TextNode[] = mapGrandchildren(frame, null, undefined, (d) => {
return d.type == "TEXT";
});
return [...new Set(all_text.map((t) => t.textStyleId))].map((id) => {
return figma.getLocalTextStyles().find((ts) => ts.id === id).name;
});
}

/**
* validates if acceptable mdx textsyle by its name
* @param textstyle
*/
function isMdxTextStyle(
textstyle: string
): "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | false {
const heading_pattern = `**/!(mdx-*, *-mdx, mdx)/heading[1-6]`;
const mm = new Minimatch(heading_pattern);
if (mm.match(textstyle)) {
// assuming heading textstyle always ends with `heading[1-6]` based on above pattern.
const level = textstyle.match(/[1-6]/g).pop();
return (`h` + level) as "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
}
return false;
}

function isMdxFrame(frame: FrameNode): boolean {
// 1. must be frame
if (frame.type == "FRAME") {
// must match path
// const glob_pattern = `(+(document|doc|docs|mdx|md|content))*/**/*.+(md|mdx)`;
const glob_pattern = `*/**/*.+(md|mdx)`;
const mm = new Minimatch(glob_pattern);
if (mm.match(frame.name)) {
return true;
}
}
return false;
}
43 changes: 43 additions & 0 deletions packages/app-mdx-processor/__plugn/make.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export function paragraph(t: string) {
return t;
}

export function quote(t: string) {
return `<blockquote>${t}</blockquote>`;
}

export function inlineCode(t: string) {
return `<code>${t}</code>`;
}

export function h1(t: string) {
return `<h1>${t}</h1>`;
}

export function h2(t: string) {
return `<h2>${t}</h2>`;
}

export function h3(t: string) {
return `<h3>${t}</h3>`;
}

export function h4(t: string) {
return `<h4>${t}</h4>`;
}

export function h5(t: string) {
return `<h5>${t}</h5>`;
}

export function h6(t: string) {
return `<h6>${t}</h6>`;
}

export function unknown(t: string) {
return comment(`unknown text provided >>> ` + t);
}

export function comment(t: string) {
return `<!-- ${t} -->`;
}
15 changes: 15 additions & 0 deletions packages/app-mdx-processor/__plugn/tokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
abstract class MdxToken {}
abstract class TextToken extends MdxToken {}
abstract class HeadingToken extends TextToken {}

export class Heading1Token extends HeadingToken {}
export class Heading2Token extends HeadingToken {}
export class Heading3Token extends HeadingToken {}
export class Heading4Token extends HeadingToken {}
export class Heading5Token extends HeadingToken {}
export class Heading6Token extends HeadingToken {}

export class ParagraphToken extends MdxToken {}
export class CodeToken extends MdxToken {}
export class LineBreakToken extends MdxToken {}
export class CustomTagToken extends MdxToken {}
1 change: 1 addition & 0 deletions packages/app-mdx-processor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { MdxProcessorScreen } from "./mdx-processor-screen";
3 changes: 3 additions & 0 deletions packages/app-mdx-processor/lint/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Custom linter for MDX on Design

> This is a custom linter extending `@reflect-ui/lint` designed specifically only for mdx document frames.
Loading