@agent-native/core 0.80.10 → 0.81.0
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 +1 -1
- package/corpus/core/CHANGELOG.md +53 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +108 -15
- package/corpus/core/src/cli/design-connect.ts +419 -19
- package/corpus/core/src/client/AssistantChat.tsx +123 -26
- package/corpus/core/src/client/ConnectBuilderCard.tsx +1 -0
- package/corpus/core/src/client/chat/index.ts +1 -0
- package/corpus/core/src/client/chat/run-recovery.tsx +9 -7
- package/corpus/core/src/client/chat-view-transition.ts +33 -2
- package/corpus/core/src/client/composer/PromptComposer.tsx +21 -2
- package/corpus/core/src/client/index.ts +1 -0
- package/corpus/core/src/client/org/OrgSwitcher.tsx +26 -4
- package/corpus/core/src/client/sharing/ShareButton.tsx +3 -3
- package/corpus/core/src/client/sse-event-processor.ts +9 -0
- package/corpus/core/src/client/use-agent-chat-home-handoff.ts +31 -3
- package/corpus/core/src/db/client.ts +29 -2
- package/corpus/core/src/provider-api/index.ts +29 -0
- package/corpus/core/src/server/core-routes-plugin.ts +58 -20
- package/corpus/core/src/styles/agent-native.css +54 -0
- package/corpus/core/src/usage/store.ts +2 -2
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +118 -10
- package/corpus/templates/analytics/app/components/layout/layout-route-policy.ts +7 -0
- package/corpus/templates/analytics/app/global.css +8 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +7 -1
- package/corpus/templates/analytics/app/lib/chat-handoff.ts +34 -0
- package/corpus/templates/analytics/app/pages/Ask.tsx +9 -18
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -2
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +109 -21
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +4 -6
- package/corpus/templates/analytics/changelog/2026-06-30-ask-opens-a-fresh-chat-unless-you-were-just-chatting-and-das.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-30-dashboard-email-reports-are-more-reliable-and-use-cleaner.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-30-dashboard-toolbar-controls-use-a-quieter-share-button-and-ve.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-30-session-replay-rows-show-whole-minute-durations-in-the-playl.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-30-session-replays-now-render-captured-styling-and-keep-the-eve.md +6 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +16 -3
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +31 -14
- package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +9 -2
- package/corpus/templates/assets/AGENTS.md +4 -0
- package/corpus/templates/assets/actions/_tool-activity.ts +46 -0
- package/corpus/templates/assets/actions/generate-image-batch.ts +26 -5
- package/corpus/templates/assets/actions/generate-image.ts +118 -67
- package/corpus/templates/assets/actions/list-draft-assets.ts +50 -0
- package/corpus/templates/assets/actions/open-asset-picker.ts +9 -0
- package/corpus/templates/assets/actions/rerun-generation-run.ts +52 -31
- package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +100 -0
- package/corpus/templates/assets/app/global.css +15 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +4 -0
- package/corpus/templates/assets/app/i18n/zh-TW.ts +7 -0
- package/corpus/templates/assets/app/i18n-data.ts +61 -0
- package/corpus/templates/assets/app/routes/_index.tsx +4 -0
- package/corpus/templates/assets/app/routes/library.tsx +233 -52
- package/corpus/templates/assets/changelog/2026-06-29-image-generation-can-now-render-requested-text-and-respect-b.md +6 -0
- package/corpus/templates/assets/changelog/2026-06-30-image-generation-no-longer-looks-stuck-while-the-provider-is-still-working.md +6 -0
- package/corpus/templates/assets/changelog/2026-06-30-tagged-presets-now-control-the-image-aspect-ratio.md +6 -0
- package/corpus/templates/assets/changelog/2026-06-30-the-assets-picker-now-supports-a-vertical-embedded-layout-fo.md +6 -0
- package/corpus/templates/assets/server/lib/generation.ts +135 -11
- package/corpus/templates/assets/shared/api.ts +4 -0
- package/corpus/templates/clips/actions/finalize-recording.ts +1 -12
- package/corpus/templates/clips/actions/list-ai-requests.ts +60 -0
- package/corpus/templates/clips/app/hooks/use-auto-title.ts +24 -25
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +10 -5
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -8
- package/corpus/templates/clips/changelog/2026-06-30-extension-save-recovery-avoids-false-upload-failures.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-30-longer-chrome-extension-recordings-now-keep-saving-reliably-.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/chrome-extension/src/background.ts +19 -10
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +38 -12
- package/corpus/templates/clips/chrome-extension/src/finalize-recovery.ts +224 -0
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +119 -16
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +16 -0
- package/corpus/templates/clips/server/lib/recording-upload-state.ts +48 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +9 -1
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +63 -13
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/status.get.ts +74 -0
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +32 -0
- package/corpus/templates/design/AGENTS.md +27 -0
- package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +1 -1
- package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +5 -5
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +76 -25
- package/corpus/templates/design/actions/apply-design-state.ts +17 -4
- package/corpus/templates/design/actions/apply-motion-edit.ts +76 -115
- package/corpus/templates/design/actions/apply-shader-fill.ts +148 -56
- package/corpus/templates/design/actions/capture-design-state.ts +27 -4
- package/corpus/templates/design/actions/connect-localhost.ts +59 -22
- package/corpus/templates/design/actions/delete-design.ts +20 -0
- package/corpus/templates/design/actions/export-zip.ts +23 -8
- package/corpus/templates/design/actions/generate-design.ts +53 -1
- package/corpus/templates/design/actions/get-component-details.ts +21 -26
- package/corpus/templates/design/actions/get-motion-timeline.ts +135 -10
- package/corpus/templates/design/actions/grant-localhost-write-consent.ts +116 -0
- package/corpus/templates/design/actions/import-design-tokens.ts +521 -0
- package/corpus/templates/design/actions/index-design-tokens.ts +18 -5
- package/corpus/templates/design/actions/insert-design-native-asset.ts +268 -0
- package/corpus/templates/design/actions/insert-figma-library-asset.ts +233 -0
- package/corpus/templates/design/actions/list-design-extensions.ts +32 -10
- package/corpus/templates/design/actions/list-design-native-assets.ts +105 -0
- package/corpus/templates/design/actions/list-design-states.ts +19 -1
- package/corpus/templates/design/actions/list-figma-library-assets.ts +292 -0
- package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +238 -0
- package/corpus/templates/design/actions/navigate.ts +18 -3
- package/corpus/templates/design/actions/open-component-source.ts +7 -2
- package/corpus/templates/design/actions/preview-component-prop-edit.ts +32 -26
- package/corpus/templates/design/actions/preview-shader-fill.ts +9 -11
- package/corpus/templates/design/actions/provider-api-catalog.ts +2 -2
- package/corpus/templates/design/actions/provider-api-docs.ts +1 -1
- package/corpus/templates/design/actions/provider-api-request.ts +3 -3
- package/corpus/templates/design/actions/revoke-localhost-write-consent.ts +48 -0
- package/corpus/templates/design/actions/run-design-audit.ts +74 -10
- package/corpus/templates/design/actions/run-design-extension-action.ts +1 -1
- package/corpus/templates/design/actions/view-screen.ts +1 -1
- package/corpus/templates/design/actions/write-local-file.ts +213 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +244 -3197
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +30 -20
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +795 -289
- package/corpus/templates/design/app/components/design/EditPanel.tsx +635 -234
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +124 -32
- package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +161 -0
- package/corpus/templates/design/app/components/design/MotionDock.tsx +244 -266
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +491 -56
- package/corpus/templates/design/app/components/design/ReviewPanel.tsx +55 -67
- package/corpus/templates/design/app/components/design/StatesPanel.tsx +38 -63
- package/corpus/templates/design/app/components/design/TokensPanel.tsx +264 -8
- package/corpus/templates/design/app/components/design/bridge/codegen.ts +125 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +4037 -0
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +62 -0
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +272 -0
- package/corpus/templates/design/app/components/design/bridge/nav.bridge.ts +116 -0
- package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +24 -0
- package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +78 -0
- package/corpus/templates/design/app/components/design/bridge/tsconfig.json +17 -0
- package/corpus/templates/design/app/components/design/bridge/tweak.bridge.ts +28 -0
- package/corpus/templates/design/app/components/design/bridge/zoom.bridge.ts +43 -0
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +45 -16
- package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +88 -9
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +94 -9
- package/corpus/templates/design/app/components/layout/Layout.tsx +19 -3
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/design/app/global.css +7 -0
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +23 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +22 -0
- package/corpus/templates/design/app/i18n-data.ts +369 -0
- package/corpus/templates/design/app/lib/pending-generation.ts +1 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +3024 -616
- package/corpus/templates/design/app/pages/Index.tsx +5 -1
- package/corpus/templates/design/changelog/2026-06-30-applying-the-one-click-fix-for-a-small-tap-target-accessibil.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-canvas-creation-screen-dragging-undo-redo-and-image-fill-edi.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-component-prop-edits-and-shader-fills-now-preserve-rapid-sam.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-can-browse-figma-library-components-and-insert-them-i.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-now-has-native-components-embedded-media-and-figma-im.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-preview-now-includes-a-publish-app-waitlist-option-fr.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-s-left-rail-now-matches-the-sidebar-chrome-and-uses-t.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-s-tools-create-menu-now-stays-compact-instead-of-rend.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-starter-prompts-now-begin-generating-immediately-and-.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-token-edits-now-stay-visible-in-previews-and-token-li.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-drawing-rectangles-on-the-all-screens-canvas-no-longer-flash.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-fixed-code-native-design-studio-edits-so-component-props-mot.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-fixed-visual-editing-hover-overlays-and-spacing-handles-so-s.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-motion-edits-now-save-automatically-without-a-separate-css-a.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-motion-timelines-now-reopen-as-editable-tracks-after-writing.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-new-design-prompts-with-uploaded-screenshots-work-reliably-o.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-screen-previews-in-all-screens-view-now-keep-rounded-outline.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-selection-outlines-now-sit-flush-on-rectangles-drawn-directl.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-share-options-use-a-tighter-design-editor-popover-with-compa.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-collapsed-motion-panel-now-stays-tucked-under-the-left-s.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-design-inspector-now-shows-states-and-review-in-a-tighte.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-the-sidebar-keeps-the-organization-picker-space-stable-while.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-tokens-can-now-be-imported-from-pasted-notes-code-files-fold.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +94 -2
- package/corpus/templates/design/e2e/helpers.ts +168 -65
- package/corpus/templates/design/package.json +3 -1
- package/corpus/templates/design/server/db/schema.ts +23 -0
- package/corpus/templates/design/server/handlers/uploads.ts +22 -1
- package/corpus/templates/design/server/lib/provider-api.ts +7 -4
- package/corpus/templates/design/server/lib/verify-write-grant.ts +108 -0
- package/corpus/templates/design/server/plugins/db.ts +39 -0
- package/corpus/templates/design/server/register-secrets.ts +38 -0
- package/corpus/templates/design/shared/board-file.ts +228 -0
- package/corpus/templates/design/shared/board-objects.ts +288 -0
- package/corpus/templates/design/shared/code-layer.ts +52 -0
- package/corpus/templates/design/shared/component-model.ts +35 -0
- package/corpus/templates/design/shared/motion-compiler.ts +137 -15
- package/corpus/templates/design/shared/motion-timeline.ts +2 -2
- package/corpus/templates/design/shared/resolve-tweaks.ts +32 -9
- package/corpus/templates/design/tsconfig.json +2 -1
- package/corpus/templates/slides/AGENTS.md +9 -0
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +4 -0
- package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +4 -24
- package/corpus/templates/slides/app/lib/export-pdf-client.ts +29 -20
- package/corpus/templates/slides/app/lib/export-pptx-client.ts +365 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +12 -9
- package/corpus/templates/slides/app/vite-env.d.ts +18 -0
- package/corpus/templates/slides/changelog/2026-06-30-powerpoint-downloads-now-preserve-the-rendered-slide-layout-.md +6 -0
- package/corpus/templates/slides/changelog/2026-06-30-unavailable-decks-open-in-a-cleaner-full-height-centered-sta.md +6 -0
- package/corpus/templates/slides/package.json +1 -0
- package/corpus/templates/slides/vite.config.ts +1 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +94 -10
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/design-connect.d.ts +25 -0
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +357 -18
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +14 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +115 -22
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
- package/dist/client/ConnectBuilderCard.js +1 -0
- package/dist/client/ConnectBuilderCard.js.map +1 -1
- package/dist/client/chat/index.d.ts +1 -1
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +1 -1
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/chat/run-recovery.d.ts.map +1 -1
- package/dist/client/chat/run-recovery.js +5 -5
- package/dist/client/chat/run-recovery.js.map +1 -1
- package/dist/client/chat-view-transition.d.ts +6 -0
- package/dist/client/chat-view-transition.d.ts.map +1 -1
- package/dist/client/chat-view-transition.js +23 -2
- package/dist/client/chat-view-transition.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +3 -2
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +11 -4
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/sharing/ShareButton.js +3 -3
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +10 -0
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.d.ts +8 -2
- package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.js +20 -6
- package/dist/client/use-agent-chat-home-handoff.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 +2 -2
- package/dist/db/client.d.ts +1 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +28 -2
- package/dist/db/client.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/index.d.ts +5 -4
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +28 -0
- package/dist/provider-api/index.js.map +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/core-routes-plugin.d.ts +25 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +43 -18
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/styles/agent-native.css +54 -0
- package/dist/usage/store.js +2 -2
- package/dist/usage/store.js.map +1 -1
- package/package.json +1 -1
|
@@ -25,6 +25,8 @@ import {
|
|
|
25
25
|
IconChevronRight,
|
|
26
26
|
IconCircle,
|
|
27
27
|
IconCode,
|
|
28
|
+
IconFileText,
|
|
29
|
+
IconFolder,
|
|
28
30
|
IconLetterCase,
|
|
29
31
|
IconPalette,
|
|
30
32
|
IconPlus,
|
|
@@ -32,6 +34,7 @@ import {
|
|
|
32
34
|
IconRuler,
|
|
33
35
|
IconSpacingVertical,
|
|
34
36
|
IconShadow,
|
|
37
|
+
IconUpload,
|
|
35
38
|
} from "@tabler/icons-react";
|
|
36
39
|
import { useEffect, useRef, useState } from "react";
|
|
37
40
|
|
|
@@ -43,6 +46,7 @@ import {
|
|
|
43
46
|
PopoverContent,
|
|
44
47
|
PopoverTrigger,
|
|
45
48
|
} from "@/components/ui/popover";
|
|
49
|
+
import { Textarea } from "@/components/ui/textarea";
|
|
46
50
|
import {
|
|
47
51
|
Tooltip,
|
|
48
52
|
TooltipContent,
|
|
@@ -75,6 +79,18 @@ interface IndexDesignTokensResult {
|
|
|
75
79
|
tokens: DesignToken[];
|
|
76
80
|
}
|
|
77
81
|
|
|
82
|
+
interface ImportDesignTokensResult {
|
|
83
|
+
designId: string;
|
|
84
|
+
importedCount: number;
|
|
85
|
+
filesAnalyzed: string[];
|
|
86
|
+
resolvedCssVars?: Record<string, string>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface TokenImportFile {
|
|
90
|
+
filename: string;
|
|
91
|
+
content: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
78
94
|
// ---------------------------------------------------------------------------
|
|
79
95
|
// Props
|
|
80
96
|
// ---------------------------------------------------------------------------
|
|
@@ -182,18 +198,21 @@ function TokenRow({
|
|
|
182
198
|
)}
|
|
183
199
|
|
|
184
200
|
{/* Friendly name */}
|
|
185
|
-
<
|
|
186
|
-
|
|
201
|
+
<button
|
|
202
|
+
type="button"
|
|
203
|
+
className="min-w-0 flex-1 cursor-pointer truncate bg-transparent p-0 text-left text-[11px] text-foreground"
|
|
187
204
|
onClick={onStartEdit}
|
|
205
|
+
aria-label={`Edit ${token.name}`}
|
|
188
206
|
title={token.name}
|
|
189
207
|
>
|
|
190
208
|
{token.name}
|
|
191
|
-
</
|
|
209
|
+
</button>
|
|
192
210
|
|
|
193
211
|
{/* Value / edit input */}
|
|
194
212
|
{editing ? (
|
|
195
213
|
<Input
|
|
196
214
|
ref={inputRef}
|
|
215
|
+
aria-label={`Token value for ${token.name}`}
|
|
197
216
|
value={editDraft}
|
|
198
217
|
onChange={(e) => onDraftChange(e.target.value)}
|
|
199
218
|
onKeyDown={(e) => {
|
|
@@ -204,20 +223,22 @@ function TokenRow({
|
|
|
204
223
|
className="h-5 w-24 px-1 py-0 text-[11px] font-mono"
|
|
205
224
|
/>
|
|
206
225
|
) : (
|
|
207
|
-
<
|
|
208
|
-
|
|
226
|
+
<button
|
|
227
|
+
type="button"
|
|
228
|
+
className="max-w-[6rem] cursor-pointer truncate bg-transparent p-0 text-right font-mono text-[10px] text-muted-foreground hover:text-foreground"
|
|
209
229
|
title={token.value}
|
|
230
|
+
aria-label={`Edit value for ${token.name}`}
|
|
210
231
|
onClick={onStartEdit}
|
|
211
232
|
>
|
|
212
233
|
{token.value}
|
|
213
|
-
</
|
|
234
|
+
</button>
|
|
214
235
|
)}
|
|
215
236
|
|
|
216
237
|
{/* CSS var chip (hidden when editing, visible on hover) */}
|
|
217
238
|
{!editing && (
|
|
218
239
|
<Tooltip>
|
|
219
240
|
<TooltipTrigger asChild>
|
|
220
|
-
<span className="hidden cursor-default select-all rounded bg-muted px-1 py-0 font-mono text-[9px] text-muted-foreground/70 group-hover:inline">
|
|
241
|
+
<span className="pointer-events-none hidden max-w-[5.5rem] shrink-0 cursor-default select-all truncate rounded bg-muted px-1 py-0 font-mono text-[9px] text-muted-foreground/70 group-hover:inline-block">
|
|
221
242
|
{token.cssVar}
|
|
222
243
|
</span>
|
|
223
244
|
</TooltipTrigger>
|
|
@@ -231,7 +252,7 @@ function TokenRow({
|
|
|
231
252
|
{!editing && (
|
|
232
253
|
<Badge
|
|
233
254
|
variant="outline"
|
|
234
|
-
className="hidden h-4 cursor-default px-1 py-0 text-[9px] text-muted-foreground/60 group-hover:flex"
|
|
255
|
+
className="pointer-events-none hidden h-4 shrink-0 cursor-default px-1 py-0 text-[9px] text-muted-foreground/60 group-hover:flex"
|
|
235
256
|
>
|
|
236
257
|
{token.source}
|
|
237
258
|
</Badge>
|
|
@@ -383,6 +404,200 @@ function NewTokenPopover({ onAdd }: NewTokenPopoverProps) {
|
|
|
383
404
|
);
|
|
384
405
|
}
|
|
385
406
|
|
|
407
|
+
// ---------------------------------------------------------------------------
|
|
408
|
+
// Import popover
|
|
409
|
+
// ---------------------------------------------------------------------------
|
|
410
|
+
|
|
411
|
+
const TOKEN_IMPORT_ACCEPT = [
|
|
412
|
+
".css",
|
|
413
|
+
".scss",
|
|
414
|
+
".sass",
|
|
415
|
+
".less",
|
|
416
|
+
".json",
|
|
417
|
+
".ts",
|
|
418
|
+
".tsx",
|
|
419
|
+
".js",
|
|
420
|
+
".jsx",
|
|
421
|
+
".md",
|
|
422
|
+
".mdx",
|
|
423
|
+
".txt",
|
|
424
|
+
].join(",");
|
|
425
|
+
|
|
426
|
+
async function readImportFiles(fileList: FileList): Promise<TokenImportFile[]> {
|
|
427
|
+
const selected = [...fileList].slice(0, 20);
|
|
428
|
+
const files = await Promise.all(
|
|
429
|
+
selected.map(async (file) => ({
|
|
430
|
+
filename:
|
|
431
|
+
(file as File & { webkitRelativePath?: string }).webkitRelativePath ||
|
|
432
|
+
file.name,
|
|
433
|
+
content: await file.text(),
|
|
434
|
+
})),
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
return files.filter((file) => file.content.trim().length > 0);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
interface ImportTokensPopoverProps {
|
|
441
|
+
onImportFiles: (
|
|
442
|
+
files: TokenImportFile[],
|
|
443
|
+
) => Promise<ImportDesignTokensResult>;
|
|
444
|
+
onImportText: (text: string) => Promise<ImportDesignTokensResult>;
|
|
445
|
+
onImportCurrentDesign: () => Promise<ImportDesignTokensResult>;
|
|
446
|
+
isPending: boolean;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function ImportTokensPopover({
|
|
450
|
+
onImportFiles,
|
|
451
|
+
onImportText,
|
|
452
|
+
onImportCurrentDesign,
|
|
453
|
+
isPending,
|
|
454
|
+
}: ImportTokensPopoverProps) {
|
|
455
|
+
const t = useT();
|
|
456
|
+
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
457
|
+
const folderInputRef = useRef<HTMLInputElement>(null);
|
|
458
|
+
const [open, setOpen] = useState(false);
|
|
459
|
+
const [text, setText] = useState("");
|
|
460
|
+
const [status, setStatus] = useState<string | null>(null);
|
|
461
|
+
|
|
462
|
+
const runImport = async (
|
|
463
|
+
importer: () => Promise<ImportDesignTokensResult>,
|
|
464
|
+
) => {
|
|
465
|
+
setStatus(null);
|
|
466
|
+
try {
|
|
467
|
+
const result = await importer();
|
|
468
|
+
setStatus(
|
|
469
|
+
t("designEditor.tokens.importedCount", {
|
|
470
|
+
count: result.importedCount,
|
|
471
|
+
}),
|
|
472
|
+
);
|
|
473
|
+
if (result.importedCount > 0) {
|
|
474
|
+
setText("");
|
|
475
|
+
}
|
|
476
|
+
} catch (error) {
|
|
477
|
+
setStatus(error instanceof Error ? error.message : String(error));
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
482
|
+
const files = event.currentTarget.files;
|
|
483
|
+
event.currentTarget.value = "";
|
|
484
|
+
if (!files?.length) return;
|
|
485
|
+
void runImport(async () => onImportFiles(await readImportFiles(files)));
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
return (
|
|
489
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
490
|
+
<Tooltip>
|
|
491
|
+
<TooltipTrigger asChild>
|
|
492
|
+
<PopoverTrigger asChild>
|
|
493
|
+
<Button
|
|
494
|
+
type="button"
|
|
495
|
+
variant="ghost"
|
|
496
|
+
size="icon"
|
|
497
|
+
className="size-6 cursor-pointer text-muted-foreground/60 hover:text-foreground"
|
|
498
|
+
aria-label={t("designEditor.tokens.import")}
|
|
499
|
+
>
|
|
500
|
+
<IconUpload className="size-3" />
|
|
501
|
+
</Button>
|
|
502
|
+
</PopoverTrigger>
|
|
503
|
+
</TooltipTrigger>
|
|
504
|
+
<TooltipContent>{t("designEditor.tokens.import")}</TooltipContent>
|
|
505
|
+
</Tooltip>
|
|
506
|
+
<PopoverContent align="end" className="w-72 p-3 text-[12px]">
|
|
507
|
+
<div className="space-y-3">
|
|
508
|
+
<div className="space-y-1">
|
|
509
|
+
<p className="text-[11px] font-medium text-foreground">
|
|
510
|
+
{t("designEditor.tokens.importTitle")}
|
|
511
|
+
</p>
|
|
512
|
+
<p className="text-[10px] leading-snug text-muted-foreground">
|
|
513
|
+
{t("designEditor.tokens.importHint")}
|
|
514
|
+
</p>
|
|
515
|
+
</div>
|
|
516
|
+
|
|
517
|
+
<div className="grid grid-cols-3 gap-1.5">
|
|
518
|
+
<Button
|
|
519
|
+
type="button"
|
|
520
|
+
variant="outline"
|
|
521
|
+
size="sm"
|
|
522
|
+
className="h-7 cursor-pointer gap-1 px-2 text-[10px]"
|
|
523
|
+
disabled={isPending}
|
|
524
|
+
onClick={() => fileInputRef.current?.click()}
|
|
525
|
+
>
|
|
526
|
+
<IconFileText className="size-3" />
|
|
527
|
+
{t("designEditor.tokens.files")}
|
|
528
|
+
</Button>
|
|
529
|
+
<Button
|
|
530
|
+
type="button"
|
|
531
|
+
variant="outline"
|
|
532
|
+
size="sm"
|
|
533
|
+
className="h-7 cursor-pointer gap-1 px-2 text-[10px]"
|
|
534
|
+
disabled={isPending}
|
|
535
|
+
onClick={() => folderInputRef.current?.click()}
|
|
536
|
+
>
|
|
537
|
+
<IconFolder className="size-3" />
|
|
538
|
+
{t("designEditor.tokens.folder")}
|
|
539
|
+
</Button>
|
|
540
|
+
<Button
|
|
541
|
+
type="button"
|
|
542
|
+
variant="outline"
|
|
543
|
+
size="sm"
|
|
544
|
+
className="h-7 cursor-pointer px-2 text-[10px]"
|
|
545
|
+
disabled={isPending}
|
|
546
|
+
onClick={() => void runImport(onImportCurrentDesign)}
|
|
547
|
+
>
|
|
548
|
+
{t("designEditor.tokens.current")}
|
|
549
|
+
</Button>
|
|
550
|
+
</div>
|
|
551
|
+
|
|
552
|
+
<input
|
|
553
|
+
ref={fileInputRef}
|
|
554
|
+
type="file"
|
|
555
|
+
multiple
|
|
556
|
+
accept={TOKEN_IMPORT_ACCEPT}
|
|
557
|
+
className="hidden"
|
|
558
|
+
onChange={handleFileChange}
|
|
559
|
+
/>
|
|
560
|
+
<input
|
|
561
|
+
ref={folderInputRef}
|
|
562
|
+
type="file"
|
|
563
|
+
multiple
|
|
564
|
+
accept={TOKEN_IMPORT_ACCEPT}
|
|
565
|
+
className="hidden"
|
|
566
|
+
onChange={handleFileChange}
|
|
567
|
+
{...({ directory: "", webkitdirectory: "" } as Record<
|
|
568
|
+
string,
|
|
569
|
+
string
|
|
570
|
+
>)}
|
|
571
|
+
/>
|
|
572
|
+
|
|
573
|
+
<div className="space-y-1.5">
|
|
574
|
+
<Textarea
|
|
575
|
+
value={text}
|
|
576
|
+
onChange={(event) => setText(event.target.value)}
|
|
577
|
+
placeholder={t("designEditor.tokens.pastePlaceholder")}
|
|
578
|
+
className="min-h-24 resize-none font-mono text-[11px]"
|
|
579
|
+
/>
|
|
580
|
+
<Button
|
|
581
|
+
type="button"
|
|
582
|
+
className="h-7 w-full cursor-pointer text-[11px]"
|
|
583
|
+
disabled={isPending || !text.trim()}
|
|
584
|
+
onClick={() => void runImport(() => onImportText(text))}
|
|
585
|
+
>
|
|
586
|
+
{t("designEditor.tokens.importPasted")}
|
|
587
|
+
</Button>
|
|
588
|
+
</div>
|
|
589
|
+
|
|
590
|
+
{status && (
|
|
591
|
+
<p className="text-[10px] leading-snug text-muted-foreground">
|
|
592
|
+
{status}
|
|
593
|
+
</p>
|
|
594
|
+
)}
|
|
595
|
+
</div>
|
|
596
|
+
</PopoverContent>
|
|
597
|
+
</Popover>
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
|
|
386
601
|
// ---------------------------------------------------------------------------
|
|
387
602
|
// Main panel
|
|
388
603
|
// ---------------------------------------------------------------------------
|
|
@@ -404,6 +619,7 @@ export function TokensPanel({ designId, onTokensApplied }: TokensPanelProps) {
|
|
|
404
619
|
);
|
|
405
620
|
|
|
406
621
|
const applyMutation = useActionMutation("apply-design-token-edit");
|
|
622
|
+
const importMutation = useActionMutation("import-design-tokens");
|
|
407
623
|
|
|
408
624
|
// ------------------------------------------------------------------
|
|
409
625
|
// Local edit state
|
|
@@ -458,6 +674,40 @@ export function TokensPanel({ designId, onTokensApplied }: TokensPanelProps) {
|
|
|
458
674
|
);
|
|
459
675
|
};
|
|
460
676
|
|
|
677
|
+
const handleImportSuccess = (result: ImportDesignTokensResult) => {
|
|
678
|
+
void refetch();
|
|
679
|
+
if (result.resolvedCssVars && onTokensApplied) {
|
|
680
|
+
onTokensApplied(result.resolvedCssVars);
|
|
681
|
+
}
|
|
682
|
+
return result;
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
const importFiles = async (files: TokenImportFile[]) => {
|
|
686
|
+
const result = (await importMutation.mutateAsync({
|
|
687
|
+
designId,
|
|
688
|
+
source: "files",
|
|
689
|
+
files,
|
|
690
|
+
})) as ImportDesignTokensResult;
|
|
691
|
+
return handleImportSuccess(result);
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
const importText = async (text: string) => {
|
|
695
|
+
const result = (await importMutation.mutateAsync({
|
|
696
|
+
designId,
|
|
697
|
+
source: "paste",
|
|
698
|
+
text,
|
|
699
|
+
})) as ImportDesignTokensResult;
|
|
700
|
+
return handleImportSuccess(result);
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
const importCurrentDesign = async () => {
|
|
704
|
+
const result = (await importMutation.mutateAsync({
|
|
705
|
+
designId,
|
|
706
|
+
source: "current-design",
|
|
707
|
+
})) as ImportDesignTokensResult;
|
|
708
|
+
return handleImportSuccess(result);
|
|
709
|
+
};
|
|
710
|
+
|
|
461
711
|
// ------------------------------------------------------------------
|
|
462
712
|
// Render
|
|
463
713
|
// ------------------------------------------------------------------
|
|
@@ -495,6 +745,12 @@ export function TokensPanel({ designId, onTokensApplied }: TokensPanelProps) {
|
|
|
495
745
|
</TooltipTrigger>
|
|
496
746
|
<TooltipContent>{t("designEditor.tokens.refresh")}</TooltipContent>
|
|
497
747
|
</Tooltip>
|
|
748
|
+
<ImportTokensPopover
|
|
749
|
+
onImportFiles={importFiles}
|
|
750
|
+
onImportText={importText}
|
|
751
|
+
onImportCurrentDesign={importCurrentDesign}
|
|
752
|
+
isPending={importMutation.isPending}
|
|
753
|
+
/>
|
|
498
754
|
<NewTokenPopover onAdd={handleNewToken} />
|
|
499
755
|
</div>
|
|
500
756
|
</div>
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge codegen — compiles every *.bridge.ts in this directory to a self-contained
|
|
3
|
+
* injectable string and writes the result as a generated TypeScript module under
|
|
4
|
+
* .generated/bridge/<name>.generated.ts.
|
|
5
|
+
*
|
|
6
|
+
* Usage (from the design template root):
|
|
7
|
+
* pnpm exec tsx app/components/design/bridge/codegen.ts
|
|
8
|
+
*
|
|
9
|
+
* Called automatically by:
|
|
10
|
+
* - The freshness guard test (bridge.guard.spec.ts)
|
|
11
|
+
* - The project build script (see scripts.build in package.json)
|
|
12
|
+
*
|
|
13
|
+
* Mechanism
|
|
14
|
+
* ---------
|
|
15
|
+
* esbuild is invoked with bundle:true, format:'iife', platform:'browser',
|
|
16
|
+
* write:false for each .bridge.ts file. This means:
|
|
17
|
+
* • Any ES import/require that CAN'T be resolved by esbuild causes a build error
|
|
18
|
+
* (self-containment guarantee for non-local deps, e.g. npm packages).
|
|
19
|
+
* • Any ES import that CAN be resolved (e.g. a relative .ts file) gets bundled
|
|
20
|
+
* inline — the guard test's regex check on source prevents this.
|
|
21
|
+
* • The output is an IIFE-wrapped, browser-runnable JS string.
|
|
22
|
+
*
|
|
23
|
+
* The generated module is a plain committed .ts file that any bundler (Vite, Nitro,
|
|
24
|
+
* Rolldown) handles as a normal module — no Vite plugin, no SSR complications.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { execSync } from "node:child_process";
|
|
28
|
+
import { readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
29
|
+
import { join, resolve } from "node:path";
|
|
30
|
+
import { fileURLToPath } from "node:url";
|
|
31
|
+
|
|
32
|
+
import * as esbuild from "esbuild";
|
|
33
|
+
|
|
34
|
+
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
35
|
+
const designRoot = resolve(__dirname, "../../../..");
|
|
36
|
+
const bridgeDir = __dirname;
|
|
37
|
+
const generatedDir = join(designRoot, ".generated", "bridge");
|
|
38
|
+
|
|
39
|
+
const GENERATED_BANNER = `// AUTO-GENERATED by bridge/codegen.ts — do not edit manually.
|
|
40
|
+
// Run: pnpm exec tsx app/components/design/bridge/codegen.ts
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
async function compileBridge(srcFile: string): Promise<string> {
|
|
44
|
+
const result = await esbuild.build({
|
|
45
|
+
entryPoints: [srcFile],
|
|
46
|
+
bundle: true,
|
|
47
|
+
format: "iife",
|
|
48
|
+
platform: "browser",
|
|
49
|
+
target: "es2020",
|
|
50
|
+
write: false,
|
|
51
|
+
// No external packages — unresolved imports are a hard error.
|
|
52
|
+
// (Relative imports that CAN be resolved get bundled inline, which is also
|
|
53
|
+
// wrong; the guard test prevents those at the source level.)
|
|
54
|
+
external: [],
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (result.errors.length > 0) {
|
|
58
|
+
const msgs = await esbuild.formatMessages(result.errors, { kind: "error" });
|
|
59
|
+
throw new Error(`esbuild error for ${srcFile}:\n${msgs.join("\n")}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const output = result.outputFiles[0];
|
|
63
|
+
if (!output) throw new Error(`No output from esbuild for ${srcFile}`);
|
|
64
|
+
return output.text;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function bridgeName(filename: string): string {
|
|
68
|
+
return filename.replace(/\.bridge\.ts$/, "");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function generatedModuleSrc(name: string, compiled: string): string {
|
|
72
|
+
// Escape backticks and ${} in the compiled string so it embeds safely.
|
|
73
|
+
const escaped = compiled
|
|
74
|
+
.replace(/\\/g, "\\\\")
|
|
75
|
+
.replace(/`/g, "\\`")
|
|
76
|
+
.replace(/\$\{/g, "\\${");
|
|
77
|
+
return `${GENERATED_BANNER}
|
|
78
|
+
/** Compiled IIFE string for ${name}.bridge.ts — inject into an iframe via srcdoc or a <script> tag. */
|
|
79
|
+
export const ${camelCase(name)}BridgeScript: string = \`${escaped}\`;
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function camelCase(name: string): string {
|
|
84
|
+
return name.replace(/[-_]([a-z])/g, (_, c: string) => c.toUpperCase());
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function runCodegen(): Promise<void> {
|
|
88
|
+
const bridgeFiles = readdirSync(bridgeDir).filter((f) =>
|
|
89
|
+
f.endsWith(".bridge.ts"),
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (bridgeFiles.length === 0) {
|
|
93
|
+
console.log("[bridge/codegen] No *.bridge.ts files found.");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
for (const filename of bridgeFiles) {
|
|
98
|
+
const srcPath = join(bridgeDir, filename);
|
|
99
|
+
const name = bridgeName(filename);
|
|
100
|
+
const outPath = join(generatedDir, `${name}.generated.ts`);
|
|
101
|
+
|
|
102
|
+
console.log(`[bridge/codegen] Compiling ${filename} ...`);
|
|
103
|
+
const compiled = await compileBridge(srcPath);
|
|
104
|
+
const src = generatedModuleSrc(name, compiled);
|
|
105
|
+
writeFileSync(outPath, src, "utf-8");
|
|
106
|
+
console.log(`[bridge/codegen] → .generated/bridge/${name}.generated.ts`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Run oxfmt on generated files so they pass the formatter check.
|
|
110
|
+
try {
|
|
111
|
+
execSync(`pnpm exec oxfmt .generated/bridge/`, {
|
|
112
|
+
cwd: designRoot,
|
|
113
|
+
stdio: "pipe",
|
|
114
|
+
});
|
|
115
|
+
} catch {
|
|
116
|
+
// oxfmt not critical — formatting mismatches caught by CI linter, not here.
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log("[bridge/codegen] Done.");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
runCodegen().catch((err) => {
|
|
123
|
+
console.error("[bridge/codegen] FAILED:", err);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
});
|