@agent-native/core 0.80.0 → 0.80.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +28 -0
- package/corpus/core/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +14 -1
- package/corpus/core/docs/content/locales/de-DE/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +15 -1
- package/corpus/core/docs/content/locales/es-ES/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +15 -1
- package/corpus/core/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +15 -1
- package/corpus/core/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +15 -1
- package/corpus/core/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +16 -1
- package/corpus/core/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +14 -1
- package/corpus/core/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +14 -1
- package/corpus/core/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +14 -1
- package/corpus/core/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +14 -1
- package/corpus/core/docs/content/skills-guide.mdx +5 -0
- package/corpus/core/docs/content/template-design.mdx +14 -1
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/application-state/handlers.ts +1 -1
- package/corpus/core/src/brand-kit/index.ts +1 -1
- package/corpus/core/src/cli/skills.ts +18 -0
- package/corpus/core/src/client/AgentPanel.tsx +1 -1
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +1 -1
- package/corpus/core/src/client/extensions/portable-extension.ts +1 -1
- package/corpus/core/src/code-agents/transcript-normalizer.ts +1 -1
- package/corpus/core/src/extensions/path.ts +1 -4
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +1 -1
- package/corpus/core/src/mcp/build-server.ts +2 -2
- package/corpus/core/src/mcp/embed-app.ts +35 -1
- package/corpus/core/src/org/handlers.ts +5 -5
- package/corpus/core/src/org/plugin.ts +2 -2
- package/corpus/core/src/scripts/call-agent.ts +1 -1
- package/corpus/core/src/scripts/db/safety.ts +1 -1
- package/corpus/core/src/server/auth.ts +3 -0
- package/corpus/core/src/server/builder-design-systems.ts +308 -0
- package/corpus/core/src/server/core-routes-plugin.ts +29 -3
- package/corpus/core/src/server/index.ts +8 -0
- package/corpus/core/src/styles/agent-native.css +14 -7
- package/corpus/core/src/usage/store.ts +2 -2
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +298 -15
- package/corpus/templates/analytics/actions/get-sql-dashboard.ts +9 -4
- package/corpus/templates/analytics/actions/mutate-dashboard.ts +18 -2
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +12 -2
- package/corpus/templates/analytics/app/hooks/use-replay-storage-status.ts +66 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +37 -0
- package/corpus/templates/analytics/app/i18n-data.ts +404 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +333 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +2 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +121 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +49 -26
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +137 -36
- package/corpus/templates/analytics/changelog/2026-06-29-analytics-agents-can-now-place-new-charts-into-requested-das.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-analytics-queries-now-report-failed-source-query-errors-inst.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-charts-can-now-be-dropped-between-full-dashboard-rows-to-cre.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-dashboard-email-reports-include-the-full-dashboard-image-wit.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-main-surface-border-reaches-the-top.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-session-replay-now-records-playable-sessions-in-production-a.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-29-set-up-session-replay-storage-from-settings-connect-builder-.md +6 -0
- package/corpus/templates/analytics/scripts/cleanup-empty-session-recordings.ts +102 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +49 -26
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +81 -20
- package/corpus/templates/analytics/server/lib/replay-storage.ts +79 -0
- package/corpus/templates/analytics/server/lib/s3-upload-provider.ts +255 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +29 -8
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +11 -2
- package/corpus/templates/analytics/server/plugins/onboarding.ts +97 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +24 -0
- package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +105 -5
- package/corpus/templates/content/actions/set-image-alt-text.ts +1 -1
- package/corpus/templates/content/shared/document-export.ts +1 -1
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +8 -18
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +17 -0
- package/corpus/templates/design/actions/add-localhost-screens.ts +32 -5
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +259 -0
- package/corpus/templates/design/actions/update-file.ts +9 -2
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +33 -75
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +72 -9
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +41 -39
- package/corpus/templates/design/app/components/design/EditPanel.tsx +1029 -249
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +450 -101
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +978 -154
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +7 -9
- package/corpus/templates/design/app/components/design/inspector/AlignmentMatrix.tsx +133 -66
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +1234 -344
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +144 -94
- package/corpus/templates/design/app/components/design/inspector/ExportSettingsPanel.tsx +301 -72
- package/corpus/templates/design/app/components/design/inspector/FigmaColorPicker.tsx +876 -286
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +601 -0
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +242 -0
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +30 -7
- package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +212 -155
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +423 -0
- package/corpus/templates/design/app/components/design/inspector/figma-icons.tsx +487 -107
- package/corpus/templates/design/app/components/design/inspector/index.ts +27 -0
- package/corpus/templates/design/app/global.css +29 -3
- package/corpus/templates/design/app/i18n/zh-TW.ts +13 -0
- package/corpus/templates/design/app/i18n-data.ts +239 -1
- package/corpus/templates/design/app/pages/DesignEditor.tsx +1023 -353
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +57 -221
- package/corpus/templates/design/changelog/2026-06-29-canvas-selection-no-longer-flashes-broken-prototype-html-whe.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-command-menu-selections-are-clearer-in-dark-mode.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-design-mode-top-chrome-now-groups-collaborators-preview-shar.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-element-selection-now-stays-on-the-intended-layer-after-sele.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-full-view-controls-now-sit-above-frames-inst.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-screen-overview-tools-can-draw-shapes-create-screens-and-kee.md +6 -0
- package/corpus/templates/design/changelog/2026-06-29-the-pen-tool-now-creates-anchor-based-bezier-vectors-with-ha.md +6 -0
- package/corpus/templates/design/server/handlers/import-figma-system.ts +38 -85
- package/corpus/templates/design/server/lib/design-snapshot.ts +9 -1
- package/corpus/templates/design/shared/code-layer.ts +209 -9
- package/corpus/templates/design/shared/html-content.ts +21 -0
- package/corpus/templates/design/shared/pen-path.ts +207 -0
- package/corpus/templates/mail/app/lib/utils.ts +2 -2
- package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +9 -10
- package/corpus/templates/slides/AGENTS.md +3 -2
- package/corpus/templates/slides/actions/import-file.ts +26 -17
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +259 -0
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +35 -167
- package/corpus/templates/slides/app/components/design-system/fig-import-response.ts +9 -13
- package/corpus/templates/slides/app/context/DeckContext.tsx +1 -1
- package/corpus/templates/slides/app/i18n/ar-SA.ts +9 -37
- package/corpus/templates/slides/app/i18n/de-DE.ts +10 -25
- package/corpus/templates/slides/app/i18n/en-US.ts +9 -26
- package/corpus/templates/slides/app/i18n/es-ES.ts +10 -28
- package/corpus/templates/slides/app/i18n/fr-FR.ts +10 -28
- package/corpus/templates/slides/app/i18n/hi-IN.ts +9 -26
- package/corpus/templates/slides/app/i18n/ja-JP.ts +10 -22
- package/corpus/templates/slides/app/i18n/ko-KR.ts +9 -23
- package/corpus/templates/slides/app/i18n/pt-BR.ts +10 -28
- package/corpus/templates/slides/app/i18n/zh-CN.ts +9 -22
- package/corpus/templates/slides/app/i18n/zh-TW.ts +9 -22
- package/corpus/templates/slides/server/handlers/import-figma-system.ts +44 -12
- package/corpus/templates/slides/server/lib/chat-attachments.ts +1 -1
- package/corpus/templates/videos/app/components/NewCompositionPopover.tsx +1 -1
- package/dist/application-state/handlers.js +1 -1
- package/dist/application-state/handlers.js.map +1 -1
- package/dist/brand-kit/index.d.ts +1 -1
- package/dist/brand-kit/index.js +1 -1
- package/dist/brand-kit/index.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +18 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AgentPanel.js +1 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/extensions/portable-extension.d.ts +1 -1
- package/dist/client/extensions/portable-extension.d.ts.map +1 -1
- package/dist/client/extensions/portable-extension.js.map +1 -1
- package/dist/code-agents/transcript-normalizer.js +1 -1
- package/dist/code-agents/transcript-normalizer.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/extensions/path.d.ts +1 -1
- package/dist/extensions/path.d.ts.map +1 -1
- package/dist/extensions/path.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/integrations/a2a-continuation-processor.js +1 -1
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/mcp/build-server.d.ts +1 -1
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +1 -1
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +35 -1
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +8 -8
- package/dist/org/handlers.js +5 -5
- package/dist/org/handlers.js.map +1 -1
- package/dist/org/plugin.js +2 -2
- package/dist/org/plugin.js.map +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/call-agent.js +1 -1
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/scripts/db/safety.js +1 -1
- package/dist/scripts/db/safety.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +3 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/builder-design-systems.d.ts +28 -0
- package/dist/server/builder-design-systems.d.ts.map +1 -0
- package/dist/server/builder-design-systems.js +217 -0
- package/dist/server/builder-design-systems.js.map +1 -0
- package/dist/server/core-routes-plugin.d.ts +1 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +20 -3
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/styles/agent-native.css +14 -7
- package/dist/usage/store.js +2 -2
- package/dist/usage/store.js.map +1 -1
- package/docs/content/locales/ar-SA/skills-guide.mdx +5 -0
- package/docs/content/locales/ar-SA/template-design.mdx +14 -1
- package/docs/content/locales/de-DE/skills-guide.mdx +5 -0
- package/docs/content/locales/de-DE/template-design.mdx +15 -1
- package/docs/content/locales/es-ES/skills-guide.mdx +5 -0
- package/docs/content/locales/es-ES/template-design.mdx +15 -1
- package/docs/content/locales/fr-FR/skills-guide.mdx +5 -0
- package/docs/content/locales/fr-FR/template-design.mdx +15 -1
- package/docs/content/locales/hi-IN/skills-guide.mdx +5 -0
- package/docs/content/locales/hi-IN/template-design.mdx +15 -1
- package/docs/content/locales/ja-JP/skills-guide.mdx +5 -0
- package/docs/content/locales/ja-JP/template-design.mdx +16 -1
- package/docs/content/locales/ko-KR/skills-guide.mdx +5 -0
- package/docs/content/locales/ko-KR/template-design.mdx +14 -1
- package/docs/content/locales/pt-BR/skills-guide.mdx +5 -0
- package/docs/content/locales/pt-BR/template-design.mdx +14 -1
- package/docs/content/locales/zh-CN/skills-guide.mdx +5 -0
- package/docs/content/locales/zh-CN/template-design.mdx +14 -1
- package/docs/content/locales/zh-TW/skills-guide.mdx +5 -0
- package/docs/content/locales/zh-TW/template-design.mdx +14 -1
- package/docs/content/skills-guide.mdx +5 -0
- package/docs/content/template-design.mdx +14 -1
- package/package.json +1 -1
- package/corpus/templates/design/actions/import-figma-file.ts +0 -166
- package/corpus/templates/slides/server/lib/fig-design-system.ts +0 -110
|
@@ -153,6 +153,8 @@ export interface LayoutContext {
|
|
|
153
153
|
width?: string;
|
|
154
154
|
height?: string;
|
|
155
155
|
flexDirection?: string;
|
|
156
|
+
alignItems?: string;
|
|
157
|
+
justifyContent?: string;
|
|
156
158
|
gap?: string;
|
|
157
159
|
padding?: string;
|
|
158
160
|
parentDisplay?: string;
|
|
@@ -243,6 +245,15 @@ export interface CodeLayerTreeNode {
|
|
|
243
245
|
tag: string;
|
|
244
246
|
selector: string;
|
|
245
247
|
detail: string;
|
|
248
|
+
layout?: Pick<
|
|
249
|
+
LayoutContext,
|
|
250
|
+
| "display"
|
|
251
|
+
| "flexDirection"
|
|
252
|
+
| "alignItems"
|
|
253
|
+
| "justifyContent"
|
|
254
|
+
| "isFlexContainer"
|
|
255
|
+
| "isGridContainer"
|
|
256
|
+
>;
|
|
246
257
|
badge?: string;
|
|
247
258
|
renamable: boolean;
|
|
248
259
|
children: CodeLayerTreeNode[];
|
|
@@ -544,6 +555,8 @@ const NON_VISUAL_TAGS = new Set([
|
|
|
544
555
|
"noscript",
|
|
545
556
|
]);
|
|
546
557
|
|
|
558
|
+
const RAW_TEXT_VISUAL_TAGS = new Set(["textarea"]);
|
|
559
|
+
|
|
547
560
|
const DATA_SELECTOR_PRIORITY = [
|
|
548
561
|
"data-agent-native-node-id",
|
|
549
562
|
"data-code-layer-id",
|
|
@@ -967,6 +980,21 @@ function findHtmlTagEnd(html: string, start: number): number {
|
|
|
967
980
|
return html.length;
|
|
968
981
|
}
|
|
969
982
|
|
|
983
|
+
function findClosingTag(
|
|
984
|
+
html: string,
|
|
985
|
+
tag: string,
|
|
986
|
+
from: number,
|
|
987
|
+
): { closeStart: number; closeEnd: number } | null {
|
|
988
|
+
const closeRe = new RegExp(`<\\/\\s*${tag}\\s*>`, "gi");
|
|
989
|
+
closeRe.lastIndex = from;
|
|
990
|
+
const match = closeRe.exec(html);
|
|
991
|
+
if (!match) return null;
|
|
992
|
+
return {
|
|
993
|
+
closeStart: match.index,
|
|
994
|
+
closeEnd: match.index + match[0].length,
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
|
|
970
998
|
function parseHtmlElements(html: string): ParsedElement[] {
|
|
971
999
|
const elements: ParsedElement[] = [];
|
|
972
1000
|
const stack: number[] = [];
|
|
@@ -1003,15 +1031,36 @@ function parseHtmlElements(html: string): ParsedElement[] {
|
|
|
1003
1031
|
const nthOfType = (sameTypeCounts.get(parentKey) ?? 0) + 1;
|
|
1004
1032
|
sameTypeCounts.set(parentKey, nthOfType);
|
|
1005
1033
|
const selfClosing = raw.endsWith("/>") || VOID_TAGS.has(tag);
|
|
1034
|
+
|
|
1035
|
+
if (NON_VISUAL_TAGS.has(tag)) {
|
|
1036
|
+
if (!selfClosing) {
|
|
1037
|
+
const close = findClosingTag(html, tag, match.index + raw.length);
|
|
1038
|
+
tagRe.lastIndex = close ? close.closeEnd : html.length;
|
|
1039
|
+
}
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1006
1043
|
const index = elements.length;
|
|
1044
|
+
const rawTextClose =
|
|
1045
|
+
!selfClosing && RAW_TEXT_VISUAL_TAGS.has(tag)
|
|
1046
|
+
? findClosingTag(html, tag, match.index + raw.length)
|
|
1047
|
+
: null;
|
|
1007
1048
|
const element: ParsedElement = {
|
|
1008
1049
|
index,
|
|
1009
1050
|
tag,
|
|
1010
1051
|
start: match.index,
|
|
1011
1052
|
openEnd: match.index + raw.length,
|
|
1012
|
-
end:
|
|
1053
|
+
end: rawTextClose
|
|
1054
|
+
? rawTextClose.closeEnd
|
|
1055
|
+
: selfClosing
|
|
1056
|
+
? match.index + raw.length
|
|
1057
|
+
: html.length,
|
|
1013
1058
|
contentStart: match.index + raw.length,
|
|
1014
|
-
contentEnd:
|
|
1059
|
+
contentEnd: rawTextClose
|
|
1060
|
+
? rawTextClose.closeStart
|
|
1061
|
+
: selfClosing
|
|
1062
|
+
? match.index + raw.length
|
|
1063
|
+
: html.length,
|
|
1015
1064
|
selfClosing,
|
|
1016
1065
|
attributes: parseAttributes(raw, match.index),
|
|
1017
1066
|
parentIndex,
|
|
@@ -1026,6 +1075,12 @@ function parseHtmlElements(html: string): ParsedElement[] {
|
|
|
1026
1075
|
if (parentIndex !== undefined) {
|
|
1027
1076
|
elements[parentIndex]?.childIndexes.push(index);
|
|
1028
1077
|
}
|
|
1078
|
+
if (rawTextClose) {
|
|
1079
|
+
element.closeStart = rawTextClose.closeStart;
|
|
1080
|
+
element.closeEnd = rawTextClose.closeEnd;
|
|
1081
|
+
tagRe.lastIndex = rawTextClose.closeEnd;
|
|
1082
|
+
continue;
|
|
1083
|
+
}
|
|
1029
1084
|
if (!selfClosing) stack.push(index);
|
|
1030
1085
|
}
|
|
1031
1086
|
|
|
@@ -1284,6 +1339,34 @@ function layoutFor(
|
|
|
1284
1339
|
: classes.has("flex-row")
|
|
1285
1340
|
? "row"
|
|
1286
1341
|
: undefined);
|
|
1342
|
+
const alignItems =
|
|
1343
|
+
style["align-items"] ??
|
|
1344
|
+
(classes.has("items-start")
|
|
1345
|
+
? "flex-start"
|
|
1346
|
+
: classes.has("items-center")
|
|
1347
|
+
? "center"
|
|
1348
|
+
: classes.has("items-end")
|
|
1349
|
+
? "flex-end"
|
|
1350
|
+
: classes.has("items-stretch")
|
|
1351
|
+
? "stretch"
|
|
1352
|
+
: classes.has("items-baseline")
|
|
1353
|
+
? "baseline"
|
|
1354
|
+
: undefined);
|
|
1355
|
+
const justifyContent =
|
|
1356
|
+
style["justify-content"] ??
|
|
1357
|
+
(classes.has("justify-start")
|
|
1358
|
+
? "flex-start"
|
|
1359
|
+
: classes.has("justify-center")
|
|
1360
|
+
? "center"
|
|
1361
|
+
: classes.has("justify-end")
|
|
1362
|
+
? "flex-end"
|
|
1363
|
+
: classes.has("justify-between")
|
|
1364
|
+
? "space-between"
|
|
1365
|
+
: classes.has("justify-around")
|
|
1366
|
+
? "space-around"
|
|
1367
|
+
: classes.has("justify-evenly")
|
|
1368
|
+
? "space-evenly"
|
|
1369
|
+
: undefined);
|
|
1287
1370
|
const parentFlexDirection =
|
|
1288
1371
|
parentStyle?.["flex-direction"] ??
|
|
1289
1372
|
(parentClasses?.has("flex-col")
|
|
@@ -1300,6 +1383,8 @@ function layoutFor(
|
|
|
1300
1383
|
width: style.width,
|
|
1301
1384
|
height: style.height,
|
|
1302
1385
|
flexDirection,
|
|
1386
|
+
alignItems,
|
|
1387
|
+
justifyContent,
|
|
1303
1388
|
gap: style.gap,
|
|
1304
1389
|
padding: style.padding,
|
|
1305
1390
|
parentDisplay,
|
|
@@ -1620,6 +1705,14 @@ export function buildCodeLayerTree(
|
|
|
1620
1705
|
tag: node.tag,
|
|
1621
1706
|
selector: node.selector,
|
|
1622
1707
|
detail: `<${node.tag}>`,
|
|
1708
|
+
layout: {
|
|
1709
|
+
display: node.layout.display,
|
|
1710
|
+
flexDirection: node.layout.flexDirection,
|
|
1711
|
+
alignItems: node.layout.alignItems,
|
|
1712
|
+
justifyContent: node.layout.justifyContent,
|
|
1713
|
+
isFlexContainer: node.layout.isFlexContainer,
|
|
1714
|
+
isGridContainer: node.layout.isGridContainer,
|
|
1715
|
+
},
|
|
1623
1716
|
badge:
|
|
1624
1717
|
node.layerNameSource === "attribute" && node.layerNameAttribute
|
|
1625
1718
|
? node.layerNameAttribute
|
|
@@ -1719,6 +1812,87 @@ function simpleSelectorMatches(node: CodeLayerNode, selector: string): boolean {
|
|
|
1719
1812
|
return node.tag === selector.toLowerCase();
|
|
1720
1813
|
}
|
|
1721
1814
|
|
|
1815
|
+
function unescapeCssAttributeValue(value: string): string {
|
|
1816
|
+
return value.replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
function simpleSelectorMatchesElement(
|
|
1820
|
+
element: ParsedElement,
|
|
1821
|
+
selector: string,
|
|
1822
|
+
): boolean {
|
|
1823
|
+
let remaining = selector.trim();
|
|
1824
|
+
if (!remaining) return false;
|
|
1825
|
+
|
|
1826
|
+
const nthMatch = remaining.match(/:nth-of-type\((\d+)\)$/);
|
|
1827
|
+
if (nthMatch?.[1]) {
|
|
1828
|
+
if (element.nthOfType !== Number(nthMatch[1])) return false;
|
|
1829
|
+
remaining = remaining.slice(0, nthMatch.index).trim();
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
const tagMatch = remaining.match(/^([A-Za-z][A-Za-z0-9:-]*)/);
|
|
1833
|
+
if (tagMatch?.[1] && element.tag !== tagMatch[1].toLowerCase()) {
|
|
1834
|
+
return false;
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
const idMatch = remaining.match(/#([A-Za-z_][A-Za-z0-9_-]*)/);
|
|
1838
|
+
if (idMatch?.[1] && attributeValue(element, "id") !== idMatch[1]) {
|
|
1839
|
+
return false;
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
const attributes = Array.from(
|
|
1843
|
+
remaining.matchAll(
|
|
1844
|
+
/\[([A-Za-z_][A-Za-z0-9_:.-]*)=(?:"((?:\\"|[^"])*)"|'((?:\\'|[^'])*)')\]/g,
|
|
1845
|
+
),
|
|
1846
|
+
);
|
|
1847
|
+
for (const match of attributes) {
|
|
1848
|
+
const name = match[1];
|
|
1849
|
+
if (!name) return false;
|
|
1850
|
+
const expected = unescapeCssAttributeValue(match[2] ?? match[3] ?? "");
|
|
1851
|
+
if (attributeValue(element, name) !== expected) return false;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
const classes = classList(element);
|
|
1855
|
+
const requiredClasses = Array.from(
|
|
1856
|
+
remaining.matchAll(/\.([A-Za-z_][A-Za-z0-9_-]*)/g),
|
|
1857
|
+
(match) => match[1],
|
|
1858
|
+
).filter((value): value is string => Boolean(value));
|
|
1859
|
+
if (requiredClasses.some((className) => !classes.includes(className))) {
|
|
1860
|
+
return false;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
return Boolean(
|
|
1864
|
+
tagMatch ||
|
|
1865
|
+
idMatch ||
|
|
1866
|
+
attributes.length > 0 ||
|
|
1867
|
+
requiredClasses.length > 0 ||
|
|
1868
|
+
nthMatch,
|
|
1869
|
+
);
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
function selectorPathMatchesElement(
|
|
1873
|
+
element: ParsedElement | undefined,
|
|
1874
|
+
selector: string,
|
|
1875
|
+
elementByIndex: Map<number, ParsedElement>,
|
|
1876
|
+
): boolean {
|
|
1877
|
+
const parts = normalizeSelectorForMatch(selector)
|
|
1878
|
+
.split(" > ")
|
|
1879
|
+
.map((part) => part.trim())
|
|
1880
|
+
.filter(Boolean);
|
|
1881
|
+
if (parts.length <= 1) return false;
|
|
1882
|
+
|
|
1883
|
+
let current: ParsedElement | undefined = element;
|
|
1884
|
+
for (let index = parts.length - 1; index >= 0; index -= 1) {
|
|
1885
|
+
const selectorPart = parts[index];
|
|
1886
|
+
if (!current || !selectorPart) return false;
|
|
1887
|
+
if (!simpleSelectorMatchesElement(current, selectorPart)) return false;
|
|
1888
|
+
current =
|
|
1889
|
+
current.parentIndex === undefined
|
|
1890
|
+
? undefined
|
|
1891
|
+
: elementByIndex.get(current.parentIndex);
|
|
1892
|
+
}
|
|
1893
|
+
return true;
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1722
1896
|
function nodeMatchesStableSourceId(
|
|
1723
1897
|
node: CodeLayerNode,
|
|
1724
1898
|
sourceId: string,
|
|
@@ -1731,7 +1905,12 @@ function nodeMatchesStableSourceId(
|
|
|
1731
1905
|
return node.attributes.id === sourceId;
|
|
1732
1906
|
}
|
|
1733
1907
|
|
|
1734
|
-
function selectorMatches(
|
|
1908
|
+
function selectorMatches(
|
|
1909
|
+
node: CodeLayerNode,
|
|
1910
|
+
selector: string,
|
|
1911
|
+
element: ParsedElement | undefined,
|
|
1912
|
+
elementByIndex: Map<number, ParsedElement>,
|
|
1913
|
+
): boolean {
|
|
1735
1914
|
const normalizedSelector = normalizeSelectorForMatch(selector);
|
|
1736
1915
|
const normalizedNodeSelectors = [
|
|
1737
1916
|
node.selector,
|
|
@@ -1739,16 +1918,25 @@ function selectorMatches(node: CodeLayerNode, selector: string): boolean {
|
|
|
1739
1918
|
...node.selectors,
|
|
1740
1919
|
].map(normalizeSelectorForMatch);
|
|
1741
1920
|
if (normalizedNodeSelectors.includes(normalizedSelector)) return true;
|
|
1921
|
+
const selectorHasDirectPath = normalizedSelector.includes(" > ");
|
|
1742
1922
|
if (
|
|
1743
|
-
|
|
1923
|
+
selectorHasDirectPath &&
|
|
1744
1924
|
normalizedNodeSelectors.some(
|
|
1745
1925
|
(candidate) =>
|
|
1746
1926
|
candidate.endsWith(` > ${normalizedSelector}`) ||
|
|
1747
|
-
|
|
1927
|
+
(candidate.includes(" > ") &&
|
|
1928
|
+
normalizedSelector.endsWith(` > ${candidate}`)),
|
|
1748
1929
|
)
|
|
1749
1930
|
) {
|
|
1750
1931
|
return true;
|
|
1751
1932
|
}
|
|
1933
|
+
if (
|
|
1934
|
+
selectorHasDirectPath &&
|
|
1935
|
+
selectorPathMatchesElement(element, normalizedSelector, elementByIndex)
|
|
1936
|
+
) {
|
|
1937
|
+
return true;
|
|
1938
|
+
}
|
|
1939
|
+
if (selectorHasDirectPath) return false;
|
|
1752
1940
|
if (simpleSelectorMatches(node, normalizedSelector)) return true;
|
|
1753
1941
|
const lastPart = lastSelectorPart(normalizedSelector);
|
|
1754
1942
|
return (
|
|
@@ -1757,9 +1945,16 @@ function selectorMatches(node: CodeLayerNode, selector: string): boolean {
|
|
|
1757
1945
|
}
|
|
1758
1946
|
|
|
1759
1947
|
function resolveTarget(
|
|
1760
|
-
|
|
1948
|
+
build: ProjectionBuild,
|
|
1761
1949
|
target: EditIntentTarget,
|
|
1762
1950
|
): EditIntentResolution {
|
|
1951
|
+
const { projection, elementByNodeId } = build;
|
|
1952
|
+
const elementByIndex = new Map(
|
|
1953
|
+
Array.from(elementByNodeId.values()).map((element) => [
|
|
1954
|
+
element.index,
|
|
1955
|
+
element,
|
|
1956
|
+
]),
|
|
1957
|
+
);
|
|
1763
1958
|
if (target.nodeId) {
|
|
1764
1959
|
const matches = projection.nodes.filter((candidate) =>
|
|
1765
1960
|
nodeMatchesStableSourceId(candidate, target.nodeId ?? ""),
|
|
@@ -1790,7 +1985,12 @@ function resolveTarget(
|
|
|
1790
1985
|
}
|
|
1791
1986
|
|
|
1792
1987
|
const matches = projection.nodes.filter((node) =>
|
|
1793
|
-
selectorMatches(
|
|
1988
|
+
selectorMatches(
|
|
1989
|
+
node,
|
|
1990
|
+
target.selector ?? "",
|
|
1991
|
+
elementByNodeId.get(node.id),
|
|
1992
|
+
elementByIndex,
|
|
1993
|
+
),
|
|
1794
1994
|
);
|
|
1795
1995
|
if (matches.length === 1 && matches[0]) {
|
|
1796
1996
|
return { status: "resolved", node: matches[0] };
|
|
@@ -2086,7 +2286,7 @@ export function applyVisualEdit(
|
|
|
2086
2286
|
}
|
|
2087
2287
|
|
|
2088
2288
|
const initial = buildProjection(html, source);
|
|
2089
|
-
const resolution = resolveTarget(initial
|
|
2289
|
+
const resolution = resolveTarget(initial, intent.target);
|
|
2090
2290
|
if (resolution.status !== "resolved" || !resolution.node) {
|
|
2091
2291
|
return {
|
|
2092
2292
|
content: html,
|
|
@@ -2129,7 +2329,7 @@ export function applyVisualEdit(
|
|
|
2129
2329
|
} else if (intent.kind === "textContent") {
|
|
2130
2330
|
edit = applyTextEdit(html, element, intent);
|
|
2131
2331
|
} else {
|
|
2132
|
-
const anchorResolution = resolveTarget(initial
|
|
2332
|
+
const anchorResolution = resolveTarget(initial, intent.anchor);
|
|
2133
2333
|
if (anchorResolution.status !== "resolved" || !anchorResolution.node) {
|
|
2134
2334
|
return {
|
|
2135
2335
|
content: html,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function isProbablyHtmlDocumentContent(content: string): boolean {
|
|
2
|
+
const trimmed = content.trimStart();
|
|
3
|
+
if (!trimmed) return true;
|
|
4
|
+
if (trimmed.startsWith("<")) return true;
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function shouldUseLiveFileContent({
|
|
9
|
+
liveContent,
|
|
10
|
+
storedContent,
|
|
11
|
+
fileType,
|
|
12
|
+
}: {
|
|
13
|
+
liveContent: string;
|
|
14
|
+
storedContent: string;
|
|
15
|
+
fileType: string;
|
|
16
|
+
}): boolean {
|
|
17
|
+
if (liveContent === storedContent) return true;
|
|
18
|
+
if (fileType.toLowerCase() !== "html") return true;
|
|
19
|
+
if (!isProbablyHtmlDocumentContent(storedContent)) return true;
|
|
20
|
+
return isProbablyHtmlDocumentContent(liveContent);
|
|
21
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
export interface PenPoint {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface PenNode {
|
|
7
|
+
point: PenPoint;
|
|
8
|
+
handleIn?: PenPoint;
|
|
9
|
+
handleOut?: PenPoint;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PenPath {
|
|
13
|
+
nodes: PenNode[];
|
|
14
|
+
closed: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface PenGeometry {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const MIN_PATH_SIZE = 12;
|
|
25
|
+
|
|
26
|
+
export function createCornerNode(point: PenPoint): PenNode {
|
|
27
|
+
return { point: { ...point } };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function createSmoothNode(anchor: PenPoint, handleOut: PenPoint) {
|
|
31
|
+
return {
|
|
32
|
+
point: { ...anchor },
|
|
33
|
+
handleIn: mirrorPoint(anchor, handleOut),
|
|
34
|
+
handleOut: { ...handleOut },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function appendPenNode(path: PenPath | null, node: PenNode): PenPath {
|
|
39
|
+
return {
|
|
40
|
+
nodes: [...(path?.nodes ?? []), clonePenNode(node)],
|
|
41
|
+
closed: false,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function clonePenPath(path: PenPath): PenPath {
|
|
46
|
+
return {
|
|
47
|
+
nodes: path.nodes.map(clonePenNode),
|
|
48
|
+
closed: path.closed,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function closePenPath(path: PenPath): PenPath {
|
|
53
|
+
return {
|
|
54
|
+
nodes: path.nodes.map(clonePenNode),
|
|
55
|
+
closed: path.nodes.length > 1,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function constrainPointTo45Degrees(
|
|
60
|
+
origin: PenPoint,
|
|
61
|
+
point: PenPoint,
|
|
62
|
+
): PenPoint {
|
|
63
|
+
const dx = point.x - origin.x;
|
|
64
|
+
const dy = point.y - origin.y;
|
|
65
|
+
const distance = Math.hypot(dx, dy);
|
|
66
|
+
if (distance === 0) return { ...point };
|
|
67
|
+
|
|
68
|
+
const angle = Math.atan2(dy, dx);
|
|
69
|
+
const snappedAngle = Math.round(angle / (Math.PI / 4)) * (Math.PI / 4);
|
|
70
|
+
return {
|
|
71
|
+
x: origin.x + Math.cos(snappedAngle) * distance,
|
|
72
|
+
y: origin.y + Math.sin(snappedAngle) * distance,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function isPenCloseTarget(
|
|
77
|
+
path: PenPath | null,
|
|
78
|
+
point: PenPoint,
|
|
79
|
+
hitRadius: number,
|
|
80
|
+
) {
|
|
81
|
+
const start = path?.nodes[0]?.point;
|
|
82
|
+
if (!start || (path?.nodes.length ?? 0) < 2) return false;
|
|
83
|
+
return Math.hypot(point.x - start.x, point.y - start.y) <= hitRadius;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function getPenPathGeometry(path: PenPath): PenGeometry {
|
|
87
|
+
const points = path.nodes.flatMap((node) =>
|
|
88
|
+
[node.point, node.handleIn, node.handleOut].filter(isPenPoint),
|
|
89
|
+
);
|
|
90
|
+
if (points.length === 0) {
|
|
91
|
+
return { x: 0, y: 0, width: MIN_PATH_SIZE, height: MIN_PATH_SIZE };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const left = Math.min(...points.map((point) => point.x));
|
|
95
|
+
const top = Math.min(...points.map((point) => point.y));
|
|
96
|
+
const right = Math.max(...points.map((point) => point.x));
|
|
97
|
+
const bottom = Math.max(...points.map((point) => point.y));
|
|
98
|
+
return {
|
|
99
|
+
x: left,
|
|
100
|
+
y: top,
|
|
101
|
+
width: Math.max(MIN_PATH_SIZE, right - left),
|
|
102
|
+
height: Math.max(MIN_PATH_SIZE, bottom - top),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function serializePenPath(path: PenPath): string {
|
|
107
|
+
const [first, ...rest] = path.nodes;
|
|
108
|
+
if (!first) return "";
|
|
109
|
+
|
|
110
|
+
const commands = [`M ${formatPoint(first.point)}`];
|
|
111
|
+
rest.forEach((node, index) => {
|
|
112
|
+
const previous = path.nodes[index];
|
|
113
|
+
commands.push(serializeSegment(previous, node));
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
if (path.closed && path.nodes.length > 1) {
|
|
117
|
+
commands.push(serializeSegment(path.nodes[path.nodes.length - 1], first));
|
|
118
|
+
commands.push("Z");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return commands.join(" ");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function offsetPenPath(path: PenPath, offset: PenPoint): PenPath {
|
|
125
|
+
return transformPenPath(path, (point) => ({
|
|
126
|
+
x: point.x - offset.x,
|
|
127
|
+
y: point.y - offset.y,
|
|
128
|
+
}));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function translatePenPath(
|
|
132
|
+
path: PenPath,
|
|
133
|
+
dx: number,
|
|
134
|
+
dy: number,
|
|
135
|
+
): PenPath {
|
|
136
|
+
return transformPenPath(path, (point) => ({
|
|
137
|
+
x: point.x + dx,
|
|
138
|
+
y: point.y + dy,
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function scalePenPathToGeometry(
|
|
143
|
+
path: PenPath,
|
|
144
|
+
origin: PenGeometry,
|
|
145
|
+
next: PenGeometry,
|
|
146
|
+
): PenPath {
|
|
147
|
+
const scaleX = next.width / Math.max(1, origin.width);
|
|
148
|
+
const scaleY = next.height / Math.max(1, origin.height);
|
|
149
|
+
return transformPenPath(path, (point) => ({
|
|
150
|
+
x: next.x + (point.x - origin.x) * scaleX,
|
|
151
|
+
y: next.y + (point.y - origin.y) * scaleY,
|
|
152
|
+
}));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function serializeSegment(from: PenNode, to: PenNode) {
|
|
156
|
+
const c1 = from.handleOut ?? from.point;
|
|
157
|
+
const c2 = to.handleIn ?? to.point;
|
|
158
|
+
if (samePoint(c1, from.point) && samePoint(c2, to.point)) {
|
|
159
|
+
return `L ${formatPoint(to.point)}`;
|
|
160
|
+
}
|
|
161
|
+
return `C ${formatPoint(c1)} ${formatPoint(c2)} ${formatPoint(to.point)}`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function transformPenPath(
|
|
165
|
+
path: PenPath,
|
|
166
|
+
transform: (point: PenPoint) => PenPoint,
|
|
167
|
+
): PenPath {
|
|
168
|
+
return {
|
|
169
|
+
nodes: path.nodes.map((node) => ({
|
|
170
|
+
point: transform(node.point),
|
|
171
|
+
handleIn: node.handleIn ? transform(node.handleIn) : undefined,
|
|
172
|
+
handleOut: node.handleOut ? transform(node.handleOut) : undefined,
|
|
173
|
+
})),
|
|
174
|
+
closed: path.closed,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function clonePenNode(node: PenNode): PenNode {
|
|
179
|
+
return {
|
|
180
|
+
point: { ...node.point },
|
|
181
|
+
handleIn: node.handleIn ? { ...node.handleIn } : undefined,
|
|
182
|
+
handleOut: node.handleOut ? { ...node.handleOut } : undefined,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function mirrorPoint(anchor: PenPoint, point: PenPoint): PenPoint {
|
|
187
|
+
return {
|
|
188
|
+
x: anchor.x - (point.x - anchor.x),
|
|
189
|
+
y: anchor.y - (point.y - anchor.y),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function formatPoint(point: PenPoint) {
|
|
194
|
+
return `${roundCoord(point.x)} ${roundCoord(point.y)}`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function roundCoord(value: number) {
|
|
198
|
+
return Math.round(value * 10) / 10;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function samePoint(a: PenPoint, b: PenPoint) {
|
|
202
|
+
return a.x === b.x && a.y === b.y;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function isPenPoint(point: PenPoint | undefined): point is PenPoint {
|
|
206
|
+
return !!point;
|
|
207
|
+
}
|
|
@@ -74,12 +74,12 @@ export function markdownToHtml(markdown: string): string {
|
|
|
74
74
|
return `<h${level}>${renderInlineMarkdown(heading[2])}</h${level}>`;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
if (/^(
|
|
77
|
+
if (/^(-|\*|\+)\s+/m.test(block)) {
|
|
78
78
|
const items = block
|
|
79
79
|
.split("\n")
|
|
80
80
|
.map((line) => line.trim())
|
|
81
81
|
.filter(Boolean)
|
|
82
|
-
.map((line) => line.replace(/^(
|
|
82
|
+
.map((line) => line.replace(/^(-|\*|\+)\s+/, ""))
|
|
83
83
|
.map((line) => `<li>${renderInlineMarkdown(line)}</li>`)
|
|
84
84
|
.join("");
|
|
85
85
|
return `<ul>${items}</ul>`;
|
|
@@ -24,22 +24,21 @@ Design systems are stored in the `design_systems` SQL table. Each has a `data` c
|
|
|
24
24
|
|
|
25
25
|
### Source: Figma `.fig` file
|
|
26
26
|
|
|
27
|
-
When the user uploads a raw Figma local copy (`.fig`),
|
|
28
|
-
`import-file` instead of treating it like a
|
|
27
|
+
When the user uploads a raw Figma local copy (`.fig`), start Builder
|
|
28
|
+
design-system indexing with `import-file` instead of treating it like a
|
|
29
|
+
document:
|
|
29
30
|
|
|
30
31
|
```bash
|
|
31
32
|
pnpm action import-file --filePath "data/uploads/brand.fig" --format fig
|
|
32
33
|
```
|
|
33
34
|
|
|
34
|
-
The action
|
|
35
|
-
the
|
|
35
|
+
The action requires Builder to be connected and returns Builder `projectId`,
|
|
36
|
+
`jobId`, `designSystemId`, and `builderUrl`. Builder is the source of truth for
|
|
37
|
+
the indexed brand kit, generated docs, and usage guidance.
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
- `
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
Do not call `import-document` for `.fig` files; it only handles metadata and
|
|
42
|
-
will miss the real design tokens.
|
|
39
|
+
Do not call `create-design-system` locally from `.fig` uploads. Do not call
|
|
40
|
+
`import-document` for `.fig` files; it only handles metadata and will miss the
|
|
41
|
+
Builder indexing flow.
|
|
43
42
|
|
|
44
43
|
## Applying to Slides
|
|
45
44
|
|
|
@@ -19,8 +19,9 @@ Detailed deck, slide-editing, image, design-system, and export workflows live in
|
|
|
19
19
|
- Preserve deck structure and visual consistency. Prefer focused slide edits over
|
|
20
20
|
regenerating whole decks unless requested.
|
|
21
21
|
- Follow linked design-system tokens and custom instructions.
|
|
22
|
-
- For raw Figma `.fig` uploads, call `import-file --format fig
|
|
23
|
-
design
|
|
22
|
+
- For raw Figma `.fig` uploads, call `import-file --format fig` to start
|
|
23
|
+
Builder design-system indexing. Do not create a local design system from raw
|
|
24
|
+
`.fig` output.
|
|
24
25
|
- Treat import/export actions as shortcuts, not capability limits. When the
|
|
25
26
|
exact Google Drive endpoint, file metadata field, export format, pagination
|
|
26
27
|
mode, or API version matters, use `provider-api-catalog`,
|