@agent-native/core 0.90.1 → 0.90.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 +1 -1
- package/corpus/core/CHANGELOG.md +14 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/AgentPanel.tsx +1 -1
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +11 -6
- package/corpus/core/src/client/use-action.ts +39 -2
- package/corpus/core/src/client/use-db-sync.ts +44 -18
- package/corpus/core/src/db/create-get-db.ts +32 -2
- package/corpus/core/src/server/framework-request-handler.ts +52 -4
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +5 -0
- package/corpus/templates/assets/.agents/skills/logo-composite/SKILL.md +34 -6
- package/corpus/templates/assets/AGENTS.md +23 -4
- package/corpus/templates/assets/actions/_generation-preset-settings.ts +48 -0
- package/corpus/templates/assets/actions/_helpers.ts +8 -1
- package/corpus/templates/assets/actions/_preset-skeleton-validation.ts +64 -0
- package/corpus/templates/assets/actions/create-generation-preset.ts +11 -3
- package/corpus/templates/assets/actions/generate-image-batch.ts +7 -2
- package/corpus/templates/assets/actions/generate-image.ts +342 -25
- package/corpus/templates/assets/actions/get-library.ts +4 -3
- package/corpus/templates/assets/actions/navigate.ts +2 -1
- package/corpus/templates/assets/actions/refresh-generation-run.ts +5 -1
- package/corpus/templates/assets/actions/update-asset.ts +1 -0
- package/corpus/templates/assets/actions/update-generation-preset.ts +8 -1
- package/corpus/templates/assets/actions/view-screen.ts +8 -1
- package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +9 -1
- package/corpus/templates/assets/app/hooks/use-image-model-menu.ts +1 -0
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +11 -0
- package/corpus/templates/assets/app/i18n/zh-TW.ts +64 -0
- package/corpus/templates/assets/app/i18n-data.ts +650 -0
- package/corpus/templates/assets/app/routes/asset.$id.tsx +2 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +44 -33
- package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1474 -0
- package/corpus/templates/assets/app/routes/library.tsx +43 -1
- package/corpus/templates/assets/server/lib/generation.ts +366 -44
- package/corpus/templates/assets/server/lib/image-processing.ts +252 -0
- package/corpus/templates/assets/server/lib/preset-skeleton.ts +137 -0
- package/corpus/templates/assets/shared/api.ts +47 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -2
- package/corpus/templates/clips/app/components/library/sort-menu.tsx +1 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +114 -33
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +27 -1
- package/corpus/templates/clips/app/routes/record.tsx +157 -68
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +5 -5
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +20 -3
- package/corpus/templates/clips/shared/finalize-recovery.ts +23 -3
- package/corpus/templates/content/AGENTS.md +52 -52
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +188 -8
- package/corpus/templates/content/actions/_builder-docs-client.ts +41 -3
- package/corpus/templates/content/actions/_database-source-utils.ts +998 -160
- package/corpus/templates/content/actions/_database-utils.ts +44 -4
- package/corpus/templates/content/actions/_notion-action-utils.ts +6 -2
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +23 -1
- package/corpus/templates/content/actions/attach-content-database-source.ts +85 -12
- package/corpus/templates/content/actions/change-content-database-source-role.ts +9 -1
- package/corpus/templates/content/actions/delete-content-database.ts +1 -0
- package/corpus/templates/content/actions/get-document.ts +11 -2
- package/corpus/templates/content/actions/list-content-databases.ts +57 -9
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +23 -6
- package/corpus/templates/content/actions/refresh-content-database-source.ts +26 -3
- package/corpus/templates/content/actions/restore-content-database.ts +1 -0
- package/corpus/templates/content/actions/update-document.ts +43 -0
- package/corpus/templates/content/app/components/editor/BuilderBodySyncingNotice.tsx +21 -0
- package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +0 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +70 -28
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +69 -17
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +4 -4
- package/corpus/templates/content/app/components/editor/body-hydration.ts +112 -0
- package/corpus/templates/content/app/components/editor/builder-body-hydration-pump.ts +52 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +9076 -2876
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +41 -1
- package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +36 -11
- package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +21 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +11 -1
- package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +11 -8
- package/corpus/templates/content/app/global.css +41 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +346 -42
- package/corpus/templates/content/app/hooks/use-db-sync.ts +9 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +47 -0
- package/corpus/templates/content/app/hooks/use-notion.ts +12 -10
- package/corpus/templates/content/app/i18n/zh-TW.ts +35 -0
- package/corpus/templates/content/app/i18n-data.ts +355 -0
- package/corpus/templates/content/app/root.tsx +22 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-database-sources-keep-loading-rows-in-the-background.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-attach-starts-with-usable-rows.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-attachment-now-stays-connected-after-large.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-builder-source-refreshes-now-show-progress-for-large-docs-blog.md +6 -0
- package/corpus/templates/content/changelog/2026-07-01-database-pages-now-delete-to-trash-without-route-errors.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-builder-source-refreshes-recover-from-stalled-background-row.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-builder-sourced-rows-open-with-sync-protection.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-database-rows-and-pages-open-faster-from-recently-loaded-dat.md +6 -0
- package/corpus/templates/content/changelog/2026-07-02-preview-panels-close-reliably-narrow-sidebar-row-actions-sta.md +6 -0
- package/corpus/templates/content/changelog/2026-07-06-builder-sync-progress-no-longer-shows-continue.md +6 -0
- package/corpus/templates/content/shared/api.ts +13 -0
- package/corpus/templates/content/shared/builder-mdx.ts +16 -3
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +23 -13
- package/corpus/templates/design/.agents/skills/responsive-breakpoints/SKILL.md +98 -0
- package/corpus/templates/design/.agents/skills/shader-fills/SKILL.md +162 -0
- package/corpus/templates/design/AGENTS.md +9 -2
- package/corpus/templates/design/actions/add-breakpoint.ts +6 -3
- package/corpus/templates/design/actions/apply-a11y-fix.ts +57 -37
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +41 -20
- package/corpus/templates/design/actions/apply-motion-edit.ts +251 -38
- package/corpus/templates/design/actions/apply-shader-fill.ts +90 -66
- package/corpus/templates/design/actions/apply-visual-edit.ts +282 -55
- package/corpus/templates/design/actions/create-component.ts +29 -60
- package/corpus/templates/design/actions/create-file.ts +9 -2
- package/corpus/templates/design/actions/duplicate-design.ts +31 -2
- package/corpus/templates/design/actions/edit-design.ts +36 -38
- package/corpus/templates/design/actions/generate-design-title.ts +87 -0
- package/corpus/templates/design/actions/generate-design.ts +53 -18
- package/corpus/templates/design/actions/generate-screens.ts +108 -4
- package/corpus/templates/design/actions/get-motion-timeline.ts +35 -7
- package/corpus/templates/design/actions/insert-asset.ts +34 -29
- package/corpus/templates/design/actions/insert-design-native-asset.ts +129 -32
- package/corpus/templates/design/actions/insert-figma-library-asset.ts +35 -30
- package/corpus/templates/design/actions/present-design-variants.ts +7 -2
- package/corpus/templates/design/actions/remove-motion-timeline.ts +31 -36
- package/corpus/templates/design/actions/update-file.ts +190 -75
- package/corpus/templates/design/app/components/design/BreakpointBar.tsx +403 -0
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +469 -222
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +708 -53
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +83 -3
- package/corpus/templates/design/app/components/design/EditPanel.tsx +1091 -6948
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +419 -85
- package/corpus/templates/design/app/components/design/MotionDock.tsx +1124 -103
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +2610 -1398
- package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +22 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2182 -235
- package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +187 -11
- package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +376 -1
- package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +746 -0
- package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +17 -0
- package/corpus/templates/design/app/components/design/code-workbench/SideBar.tsx +1 -1
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +1 -3
- package/corpus/templates/design/app/components/design/code-workbench/quickinput/QuickInput.tsx +1 -1
- package/corpus/templates/design/app/components/design/edit-panel/appearance-properties.tsx +518 -0
- package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +562 -0
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +763 -0
- package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +94 -0
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +780 -0
- package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +446 -0
- package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +79 -0
- package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +315 -0
- package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +344 -0
- package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +594 -0
- package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +119 -0
- package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +248 -0
- package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +45 -0
- package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +693 -0
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +724 -0
- package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +207 -0
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +628 -0
- package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +91 -0
- package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +649 -0
- package/corpus/templates/design/app/components/design/edit-panel/style-change-types.ts +118 -0
- package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +88 -0
- package/corpus/templates/design/app/components/design/edit-panel/transform-helpers.ts +100 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +117 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +501 -0
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +91 -40
- package/corpus/templates/design/app/components/design/inspector/BreakpointOverrideIndicator.tsx +82 -0
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +189 -87
- package/corpus/templates/design/app/components/design/inspector/GlslShaderPanel.tsx +1097 -0
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +44 -0
- package/corpus/templates/design/app/components/design/inspector/InteractionStatePanel.tsx +258 -0
- package/corpus/templates/design/app/components/design/inspector/MotionKeyframeDiamond.tsx +144 -0
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +99 -9
- package/corpus/templates/design/app/components/design/inspector/frame-size-presets.ts +116 -0
- package/corpus/templates/design/app/components/design/inspector/index.ts +26 -0
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +29 -0
- package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +171 -0
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +220 -0
- package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +35 -0
- package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +134 -0
- package/corpus/templates/design/app/components/design/multi-screen/culling.ts +185 -0
- package/corpus/templates/design/app/components/design/multi-screen/gradient-overlay-geometry.ts +120 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +892 -0
- package/corpus/templates/design/app/components/design/multi-screen/vector-edit-geometry.ts +21 -0
- package/corpus/templates/design/app/components/design/types.ts +15 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +109 -5
- package/corpus/templates/design/app/global.css +8 -8
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +259 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +163 -9
- package/corpus/templates/design/app/i18n-breakpoints.ts +205 -0
- package/corpus/templates/design/app/i18n-data.ts +1664 -152
- package/corpus/templates/design/app/i18n-motion.ts +563 -0
- package/corpus/templates/design/app/lib/design-import.ts +73 -0
- package/corpus/templates/design/app/pages/Index.tsx +41 -22
- package/corpus/templates/design/changelog/2026-06-29-design-inspector-controls-now-match-figmas-softer-dark-chrome.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-design-now-has-a-figma-style-left-rail-for-file-agent-assets.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-design-tools-now-use-a-quieter-figma-style-list-layout.md +1 -1
- package/corpus/templates/design/changelog/2026-06-30-multi-select-outlines-now-stay-consistent-across-all-screens.md +1 -1
- package/corpus/templates/design/changelog/2026-07-03-canvas-interactions-now-match-figma-rotation-aware-resizing-.md +1 -1
- package/corpus/templates/design/changelog/2026-07-03-layers-panel-matches-figma-top-layer-on-top-drag-with-auto-s.md +1 -1
- package/corpus/templates/design/changelog/2026-07-05-designs-get-ai-generated-names-from-your-prompt.md +6 -0
- package/corpus/templates/design/changelog/2026-07-05-local-code-screens-keep-their-connection-when-duplicated-and.md +6 -0
- package/corpus/templates/design/changelog/2026-07-05-press-a-to-draw-screens-on-the-canvas-inside-a-screen-it-dr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-3d-rotation-and-perspective-controls-on-every-element.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-ai-generated-and-duplicated-screens-now-get-their-editor-sel.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-applying-shaders-and-fills-in-quick-succession-can-no-longer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-frames-in-the-overview-now-support-click-to-selec.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-segments-in-the-inspector-now-show-a-device-icon-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-breakpoint-targeting-now-lives-in-one-compact-control-in-the.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-canvas-edits-can-no-longer-be-overwritten-by-stale-collabora.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-canvas-edits-inside-screens-save-reliably-again.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-cleaner-inspector-removed-the-ask-ai-box-from-the-design-tab.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-clicking-empty-canvas-space-now-deselects-an-element-inside-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dragging-an-element-onto-a-rectangle-now-nests-it-inside-wit.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dragging-screens-and-objects-on-the-canvas-is-now-much-smoot.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-drawing-a-shape-or-text-on-the-canvas-no-longer-flashes-away.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-dropping-an-element-between-two-others-inside-a-screen-now-s.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-duplicating-a-screen-now-places-the-copy-exactly-where-you-d.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-edit-gradients-directly-on-elements-inside-screens-scale-str.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-edits-from-collaborators-and-the-agent-now-update-the-canvas.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-bug-where-most-style-position-and-text-edits-briefly.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-confusing-raw-error-message-when-a-file-upload-fails.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-a-rare-case-where-an-edit-could-be-silently-overwritte.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-inserted-assets-sometimes-disappearing-reappearing-or-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-inspector-value-scrubbing-producing-erratic-numbers-an.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-padding-gap-and-min-max-size-scrubbing-not-updating-th.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-text-stroke-color-turning-black-and-glyphs-disappearin.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-collapsed-effects-and-stroke-inspector-sections-sh.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-new-design-dialog-closing-unexpectedly-when-using-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-fixed-the-typography-section-missing-when-selecting-text-nes.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-full-view-no-longer-flashes-back-to-the-overview-on-entry-no.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-keyframe-animation-timeline-per-property-keyframes-easing-cu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-moving-restyling-and-scrubbing-values-on-elements-in-ai-gene.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-padding-and-corner-radius-value-scrubbing-now-snaps-to-whole.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-padding-handles-now-only-resize-on-the-handle-line-itself-sh.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-preview-and-edit-hover-focus-and-pressed-states-with-real-cs.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-promoting-an-element-to-a-component-now-works-correctly-for-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-reduced-url-history-churn-and-selection-overlay-flicker-whil.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-removed-the-decorative-dot-before-screen-names-in-the-overvi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-responsive-breakpoints-edit-at-any-width-with-cascading-over.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-screen-labels-no-longer-turn-blue-when-you-hover-inside-the-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-scrolling-a-screen-with-an-element-selected-stays-smooth-on-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selecting-multiple-elements-and-dragging-now-moves-the-whole.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selection-borders-handles-and-value-readouts-now-stay-the-sa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-selection-handles-and-editing-chrome-now-stay-a-constant-siz.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-shader-fills-and-effects-ai-authored-or-preset-glsl-shaders-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-text-drawn-on-the-canvas-now-defaults-to-white-and-inter-in-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-text-dropped-into-a-shape-now-stays-readable-instead-of-disa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-add-tweak-controls-prompt-no-longer-jumps-to-the-corner-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-padding-value-readout-now-stays-visible-while-you-hover-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-selected-element-attachment-now-clears-from-the-chat-com.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-the-zoom-menu-is-more-compact-with-tight-rows-and-right-alig.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-undo-and-redo-no-longer-flash-the-screen-changes-now-apply-i.md +6 -0
- package/corpus/templates/design/changelog/2026-07-06-zoom-presets-like-zoom-to-50-now-stay-on-the-focused-screen-.md +6 -0
- package/corpus/templates/design/server/lib/import-design-files.ts +11 -2
- package/corpus/templates/design/server/source-workspace.ts +139 -59
- package/corpus/templates/design/shared/board-file.ts +11 -2
- package/corpus/templates/design/shared/breakpoint-media.ts +543 -0
- package/corpus/templates/design/shared/canvas-math.ts +354 -35
- package/corpus/templates/design/shared/code-layer.ts +277 -8
- package/corpus/templates/design/shared/design-state.ts +11 -4
- package/corpus/templates/design/shared/interaction-states.ts +548 -0
- package/corpus/templates/design/shared/motion-compiler.ts +186 -23
- package/corpus/templates/design/shared/motion-easing.ts +294 -0
- package/corpus/templates/design/shared/motion-timeline.ts +400 -34
- package/corpus/templates/design/shared/prompt-title.ts +95 -0
- package/corpus/templates/design/shared/responsive-classes.ts +448 -10
- package/corpus/templates/design/shared/screen-annotation.ts +46 -0
- package/corpus/templates/design/shared/shader-fills.ts +1009 -0
- package/corpus/templates/design/shared/shader-presets.ts +852 -4
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +15 -2
- package/corpus/templates/slides/app/components/editor/ImportButton.tsx +10 -1
- package/corpus/templates/slides/app/lib/upload-response.ts +71 -0
- package/dist/client/AgentPanel.js +1 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +11 -6
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/client/use-action.d.ts +3 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +34 -3
- package/dist/client/use-action.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +4 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +37 -18
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/create-get-db.d.ts +25 -0
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +25 -2
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +37 -1
- package/dist/server/framework-request-handler.js.map +1 -1
- package/package.json +1 -1
- package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +0 -153
- package/corpus/templates/design/app/hooks/useAgentEditRequest.ts +0 -133
- package/corpus/templates/design/app/pages/DesignEditor.tsx +0 -22924
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getBreakpointOverrideState,
|
|
3
|
+
type BreakpointOverrideState,
|
|
4
|
+
} from "@shared/breakpoint-media";
|
|
5
|
+
import type { InteractionState } from "@shared/interaction-states";
|
|
6
|
+
|
|
7
|
+
import type { MotionKeyframeCssProperty } from "../inspector";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* PF12: gesture-lifecycle metadata threaded alongside a style commit.
|
|
11
|
+
*
|
|
12
|
+
* - "preview": a live, in-progress tick (a ScrubInput scrub sample or a
|
|
13
|
+
* DesignColorPicker drag tick) — cheap to show in the live iframe preview,
|
|
14
|
+
* but must NOT trigger the expensive source commit (projection parse + HTML
|
|
15
|
+
* patch + history entry) on every tick.
|
|
16
|
+
* - "commit" (or omitted, for callers that don't pass meta at all): the
|
|
17
|
+
* gesture's authoritative final value — exactly one per gesture — which
|
|
18
|
+
* DOES trigger the full source commit. Omitting meta entirely preserves
|
|
19
|
+
* prior behavior (treated as "commit") for every non-scrub/color call site.
|
|
20
|
+
*
|
|
21
|
+
* - `interactionState`: set on EVERY style commit (regardless of `phase`)
|
|
22
|
+
* while the inspector's element interaction-state selector
|
|
23
|
+
* (`InteractionStatePanel`) has a non-default state active — see
|
|
24
|
+
* `shared/interaction-states.ts` for the persisted format. Omitted (or
|
|
25
|
+
* `undefined`) means "commit to the element's normal inline style /
|
|
26
|
+
* class", exactly like today. This is a PHASE-2 CONTRACT: EditPanel only
|
|
27
|
+
* attaches the field, it never calls the shared upsert helpers itself —
|
|
28
|
+
* DesignEditor's `onStyleChange`/`onStylesChange` handlers must branch on
|
|
29
|
+
* `meta.interactionState` and, when present, route the commit through
|
|
30
|
+
* `upsertStateStyle` / `upsertStateStyles` (targeting `activeContent` +
|
|
31
|
+
* the selected element's `sourceId` as the node id) instead of the normal
|
|
32
|
+
* inline-style patch path, then re-derive the forced-preview twins with
|
|
33
|
+
* `duplicateStatePreviewRules` before persisting — all as ONE history
|
|
34
|
+
* step, same as any other single style commit today.
|
|
35
|
+
*
|
|
36
|
+
* - `breakpointReset`: set ONLY on the synthetic commit fired by a
|
|
37
|
+
* `BreakpointOverrideIndicator`'s reset button (see `breakpointContext` on
|
|
38
|
+
* `EditPanelProps`). Means "clear this property's override at
|
|
39
|
+
* `maxWidthPx`, don't write a new value" — the accompanying `value`
|
|
40
|
+
* argument on `onStyleChange`/`onStylesChange` is the CURRENT (base or
|
|
41
|
+
* wider-scope) value the field falls back to displaying, not a value to
|
|
42
|
+
* persist. CONTRACT: DesignEditor's handlers must branch on
|
|
43
|
+
* `meta.breakpointReset` and, when present, call
|
|
44
|
+
* `removeBreakpointMediaDeclaration` (or clear the matching max-width
|
|
45
|
+
* utility class — whichever persistence layer
|
|
46
|
+
* `getBreakpointOverrideState` reported the override on) for `property` at
|
|
47
|
+
* `maxWidthPx`, instead of writing `value` through the normal inline-style
|
|
48
|
+
* / managed-breakpoint-block commit path.
|
|
49
|
+
*/
|
|
50
|
+
export interface StyleChangeMeta {
|
|
51
|
+
phase?: "preview" | "commit";
|
|
52
|
+
interactionState?: InteractionState;
|
|
53
|
+
breakpointReset?: { property: string; maxWidthPx: number };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type StyleChangeHandler = (
|
|
57
|
+
property: string,
|
|
58
|
+
value: string,
|
|
59
|
+
meta?: StyleChangeMeta,
|
|
60
|
+
) => void;
|
|
61
|
+
|
|
62
|
+
export type StylesChangeHandler = (
|
|
63
|
+
styles: Record<string, string>,
|
|
64
|
+
meta?: StyleChangeMeta,
|
|
65
|
+
) => void;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Per-render bundle the style-section components below use to render the
|
|
69
|
+
* motion keyframe diamond next to a field — precomputed once in `EditPanel`
|
|
70
|
+
* from `motionKeyframeState`/`onToggleMotionKeyframe` so each section only
|
|
71
|
+
* needs to know its own field's CSS property name. `undefined` (the whole
|
|
72
|
+
* bundle, or `hasTimeline: false`) means "render no diamonds" — sections
|
|
73
|
+
* check this before rendering `MotionKeyframeDiamond` at all.
|
|
74
|
+
*/
|
|
75
|
+
export interface MotionKeyframeFieldContext {
|
|
76
|
+
hasTimeline: boolean;
|
|
77
|
+
keyframedProperties: readonly string[];
|
|
78
|
+
onToggle?: (cssProperty: MotionKeyframeCssProperty) => void;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Per-render bundle the style-section components below use to render the
|
|
83
|
+
* breakpoint override indicator next to a field — precomputed once in
|
|
84
|
+
* `EditPanel` from `breakpointContext`. `undefined` means "render no
|
|
85
|
+
* indicators" (feature off or editing the base frame).
|
|
86
|
+
*/
|
|
87
|
+
export interface BreakpointOverrideFieldContext {
|
|
88
|
+
nodeId: string | undefined;
|
|
89
|
+
breakpointWidths: readonly number[];
|
|
90
|
+
baseWidthPx: number;
|
|
91
|
+
activeWidthPx: number | null;
|
|
92
|
+
html: string;
|
|
93
|
+
onReset: (property: string, maxWidthPx: number) => void;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Resolve a single property's override state against
|
|
98
|
+
* `BreakpointOverrideFieldContext`, or `undefined` when the feature is off /
|
|
99
|
+
* there's no stable node id for the current selection. Thin wrapper around
|
|
100
|
+
* `getBreakpointOverrideState` so call sites don't repeat the
|
|
101
|
+
* className/nodeId/html plumbing at every field.
|
|
102
|
+
*/
|
|
103
|
+
export function resolveBreakpointOverride(
|
|
104
|
+
ctx: BreakpointOverrideFieldContext | undefined,
|
|
105
|
+
className: string,
|
|
106
|
+
property: string,
|
|
107
|
+
): BreakpointOverrideState | undefined {
|
|
108
|
+
if (!ctx || !ctx.nodeId || ctx.activeWidthPx == null) return undefined;
|
|
109
|
+
return getBreakpointOverrideState({
|
|
110
|
+
className,
|
|
111
|
+
html: ctx.html,
|
|
112
|
+
nodeId: ctx.nodeId,
|
|
113
|
+
property,
|
|
114
|
+
breakpointWidths: ctx.breakpointWidths,
|
|
115
|
+
baseWidthPx: ctx.baseWidthPx,
|
|
116
|
+
activeWidthPx: ctx.activeWidthPx,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export function parseNumericValue(value: string): number {
|
|
2
|
+
return parseFloat(value) || 0;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function sidesAreLinked(values: {
|
|
6
|
+
top: string;
|
|
7
|
+
right: string;
|
|
8
|
+
bottom: string;
|
|
9
|
+
left: string;
|
|
10
|
+
}) {
|
|
11
|
+
return (
|
|
12
|
+
parseNumericValue(values.top || "0") ===
|
|
13
|
+
parseNumericValue(values.right || "0") &&
|
|
14
|
+
parseNumericValue(values.top || "0") ===
|
|
15
|
+
parseNumericValue(values.bottom || "0") &&
|
|
16
|
+
parseNumericValue(values.top || "0") ===
|
|
17
|
+
parseNumericValue(values.left || "0")
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const ALIGN_SELF_OPTIONS = [
|
|
22
|
+
{ value: "auto", key: "auto" },
|
|
23
|
+
{ value: "flex-start", key: "start" },
|
|
24
|
+
{ value: "center", key: "center" },
|
|
25
|
+
{ value: "flex-end", key: "end" },
|
|
26
|
+
{ value: "stretch", key: "stretch" },
|
|
27
|
+
{ value: "baseline", key: "baseline" },
|
|
28
|
+
] as const;
|
|
29
|
+
// Inside is a real `border` (draws inset from the box edge by definition).
|
|
30
|
+
// Outside and center are both implemented as CSS `outline`, which always
|
|
31
|
+
// paints just outside the border-box edge — `outline-offset` then pushes it
|
|
32
|
+
// further out (outside, offset 0) or pulls it back by half its own width so
|
|
33
|
+
// it straddles the edge (center, offset -width/2). See readStrokeOutlinePosition
|
|
34
|
+
// for how a persisted outline is read back into one of these three options.
|
|
35
|
+
export const STROKE_POSITION_OPTIONS = [
|
|
36
|
+
{ value: "inside", key: "inside" },
|
|
37
|
+
{ value: "outside", key: "outside" },
|
|
38
|
+
{ value: "center", key: "center" },
|
|
39
|
+
] as const;
|
|
40
|
+
export const BLEND_MODE_OPTIONS = [
|
|
41
|
+
{ value: "normal", label: "Normal" },
|
|
42
|
+
{ value: "multiply", label: "Multiply" },
|
|
43
|
+
{ value: "screen", label: "Screen" },
|
|
44
|
+
{ value: "overlay", label: "Overlay" },
|
|
45
|
+
{ value: "darken", label: "Darken" },
|
|
46
|
+
{ value: "lighten", label: "Lighten" },
|
|
47
|
+
{ value: "color-dodge", label: "Color dodge" }, // i18n-ignore design blend mode label
|
|
48
|
+
{ value: "color-burn", label: "Color burn" }, // i18n-ignore design blend mode label
|
|
49
|
+
{ value: "hard-light", label: "Hard light" }, // i18n-ignore design blend mode label
|
|
50
|
+
{ value: "soft-light", label: "Soft light" }, // i18n-ignore design blend mode label
|
|
51
|
+
{ value: "difference", label: "Difference" },
|
|
52
|
+
{ value: "exclusion", label: "Exclusion" },
|
|
53
|
+
{ value: "hue", label: "Hue" },
|
|
54
|
+
{ value: "saturation", label: "Saturation" },
|
|
55
|
+
{ value: "color", label: "Color" },
|
|
56
|
+
{ value: "luminosity", label: "Luminosity" },
|
|
57
|
+
] as const;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Resolve a CSS line-height value to a unitless ratio for display/editing.
|
|
61
|
+
* When the browser returns a px-computed value (e.g. "19.2px" for line-height
|
|
62
|
+
* 1.2 on a 16px font), divide by the font-size to recover the unitless ratio.
|
|
63
|
+
* Falls back to 1.2 when the value cannot be parsed.
|
|
64
|
+
*/
|
|
65
|
+
export function resolveLineHeight(
|
|
66
|
+
lineHeight: string | undefined,
|
|
67
|
+
fontSize: string | undefined,
|
|
68
|
+
): number {
|
|
69
|
+
const lh = lineHeight?.trim() || "";
|
|
70
|
+
if (!lh || lh === "normal") return 1.2;
|
|
71
|
+
if (lh.endsWith("px")) {
|
|
72
|
+
const lhPx = parseFloat(lh);
|
|
73
|
+
const fsPx = parseFloat(fontSize || "");
|
|
74
|
+
if (Number.isFinite(lhPx) && Number.isFinite(fsPx) && fsPx > 0) {
|
|
75
|
+
return Math.round((lhPx / fsPx) * 100) / 100;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const numeric = parseFloat(lh);
|
|
79
|
+
return Number.isFinite(numeric) && numeric > 0 ? numeric : 1.2;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function optionValue<T extends readonly { value: string }[]>(
|
|
83
|
+
options: T,
|
|
84
|
+
value: string | undefined,
|
|
85
|
+
fallback: T[number]["value"],
|
|
86
|
+
) {
|
|
87
|
+
return options.some((option) => option.value === value) ? value! : fallback;
|
|
88
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Matches a 2D rotate()/rotateZ() with any CSS angle unit (not rotateX/Y/3d).
|
|
2
|
+
const ROTATE_FN_PATTERN =
|
|
3
|
+
/rotate[Zz]?\(\s*([+-]?[\d.]+(?:e[+-]?\d+)?)(deg|rad|turn|grad)?\s*\)/i;
|
|
4
|
+
|
|
5
|
+
export function parseRotationValue(transform: string | undefined): number {
|
|
6
|
+
if (!transform || transform === "none") return 0;
|
|
7
|
+
const match = transform.match(ROTATE_FN_PATTERN);
|
|
8
|
+
if (match) {
|
|
9
|
+
const value = Number(match[1]);
|
|
10
|
+
if (Number.isFinite(value)) {
|
|
11
|
+
const unit = (match[2] || "deg").toLowerCase();
|
|
12
|
+
const deg =
|
|
13
|
+
unit === "rad"
|
|
14
|
+
? value * (180 / Math.PI)
|
|
15
|
+
: unit === "turn"
|
|
16
|
+
? value * 360
|
|
17
|
+
: unit === "grad"
|
|
18
|
+
? value * 0.9
|
|
19
|
+
: value;
|
|
20
|
+
return Math.round(deg * 10) / 10;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// Fallback for rotate3d()/matrix()/skew composites: read the 2D rotation
|
|
24
|
+
// component off the resolved matrix so the panel doesn't report 0.
|
|
25
|
+
if (typeof DOMMatrixReadOnly !== "undefined") {
|
|
26
|
+
try {
|
|
27
|
+
const m = new DOMMatrixReadOnly(transform);
|
|
28
|
+
return Math.round(((Math.atan2(m.b, m.a) * 180) / Math.PI) * 10) / 10;
|
|
29
|
+
} catch {
|
|
30
|
+
// Unparseable transform — fall through to 0.
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Parse a CSS `scale` property value (e.g. "-1 1", "1", "none") into two
|
|
38
|
+
* numeric components [scaleX, scaleY]. Defaults both axes to 1 when absent
|
|
39
|
+
* or unparseable, matching the CSS initial value.
|
|
40
|
+
*/
|
|
41
|
+
export function parseScaleValue(value: string | undefined): [number, number] {
|
|
42
|
+
if (!value || value === "none") return [1, 1];
|
|
43
|
+
const parts = value.trim().split(/\s+/);
|
|
44
|
+
const x = Number(parts[0]);
|
|
45
|
+
const y = parts.length > 1 ? Number(parts[1]) : x;
|
|
46
|
+
return [Number.isFinite(x) ? x : 1, Number.isFinite(y) ? y : 1];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Normalize an angle in degrees into the (-180, 180] range the inspector
|
|
51
|
+
* displays and commits (design-tool convention: 270° reads as -90°, a full
|
|
52
|
+
* 360° turn reads as 0°). Exported for tests.
|
|
53
|
+
*/
|
|
54
|
+
export function normalizeRotationDegrees(degrees: number): number {
|
|
55
|
+
if (!Number.isFinite(degrees)) return 0;
|
|
56
|
+
let normalized = degrees % 360;
|
|
57
|
+
if (normalized > 180) normalized -= 360;
|
|
58
|
+
else if (normalized <= -180) normalized += 360;
|
|
59
|
+
return Object.is(normalized, -0) ? 0 : normalized;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Exported for tests. */
|
|
63
|
+
export function mergeRotationValue(
|
|
64
|
+
transform: string | undefined,
|
|
65
|
+
degrees: number,
|
|
66
|
+
) {
|
|
67
|
+
// Round first, then normalize, so a rounded -179.96 → -180 still lands
|
|
68
|
+
// inside (-180, 180] as +180.
|
|
69
|
+
const normalizedDegrees = normalizeRotationDegrees(
|
|
70
|
+
Math.round(degrees * 10) / 10,
|
|
71
|
+
);
|
|
72
|
+
const nextRotate = `rotate(${normalizedDegrees}deg)`;
|
|
73
|
+
if (!transform || transform === "none") return nextRotate;
|
|
74
|
+
// Replace an existing rotate()/rotateZ() in ANY unit so we don't append a
|
|
75
|
+
// second rotate() (which would compound, e.g. "rotate(0.5turn) rotate(30deg)").
|
|
76
|
+
if (ROTATE_FN_PATTERN.test(transform)) {
|
|
77
|
+
return transform.replace(ROTATE_FN_PATTERN, nextRotate);
|
|
78
|
+
}
|
|
79
|
+
return `${transform} ${nextRotate}`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Replace or remove a translateX/translateY function within an existing
|
|
84
|
+
* transform string while preserving all other transform functions (rotate,
|
|
85
|
+
* scale, skew, etc.). Pass `null` as `value` to strip the function.
|
|
86
|
+
*/
|
|
87
|
+
export function mergeTranslateFunction(
|
|
88
|
+
transform: string | undefined,
|
|
89
|
+
axis: "X" | "Y",
|
|
90
|
+
value: string | null,
|
|
91
|
+
): string {
|
|
92
|
+
const pattern =
|
|
93
|
+
axis === "X" ? /translateX\([^)]*\)/g : /translateY\([^)]*\)/g;
|
|
94
|
+
const base = (!transform || transform === "none" ? "" : transform)
|
|
95
|
+
.replace(pattern, "")
|
|
96
|
+
.trim();
|
|
97
|
+
if (value === null) return base || "none";
|
|
98
|
+
const fn = `translate${axis}(${value})`;
|
|
99
|
+
return base ? `${fn} ${base}` : fn;
|
|
100
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
export const FONT_FAMILY_OPTIONS = [
|
|
2
|
+
{ value: "inherit", key: "inherit" },
|
|
3
|
+
{ value: "sans-serif", key: "sansSerif" },
|
|
4
|
+
{ value: "serif", key: "serif" },
|
|
5
|
+
{ value: "monospace", key: "monospace" },
|
|
6
|
+
{ value: "'Inter', sans-serif", key: "inter" },
|
|
7
|
+
{ value: "'Poppins', sans-serif", key: "poppins" },
|
|
8
|
+
{ value: "'Playfair Display', serif", key: "playfairDisplay" },
|
|
9
|
+
{ value: "'JetBrains Mono', monospace", key: "jetBrainsMono" },
|
|
10
|
+
] as const;
|
|
11
|
+
|
|
12
|
+
export const FONT_WEIGHT_OPTIONS = [
|
|
13
|
+
{ value: "100", key: "thin" },
|
|
14
|
+
{ value: "200", key: "extraLight" },
|
|
15
|
+
{ value: "300", key: "light" },
|
|
16
|
+
{ value: "400", key: "regular" },
|
|
17
|
+
{ value: "500", key: "medium" },
|
|
18
|
+
{ value: "600", key: "semiBold" },
|
|
19
|
+
{ value: "700", key: "bold" },
|
|
20
|
+
{ value: "800", key: "extraBold" },
|
|
21
|
+
{ value: "900", key: "black" },
|
|
22
|
+
] as const;
|
|
23
|
+
|
|
24
|
+
export type TextResizeMode = "auto-width" | "auto-height" | "fixed";
|
|
25
|
+
|
|
26
|
+
function cleanFontFamilyName(value: string): string {
|
|
27
|
+
const trimmed = value.trim();
|
|
28
|
+
if (
|
|
29
|
+
(trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
30
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'"))
|
|
31
|
+
) {
|
|
32
|
+
return trimmed.slice(1, -1).trim();
|
|
33
|
+
}
|
|
34
|
+
return trimmed;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function splitFontFamilyList(value: string | undefined): string[] {
|
|
38
|
+
const raw = value?.trim();
|
|
39
|
+
if (!raw) return [];
|
|
40
|
+
|
|
41
|
+
const families: string[] = [];
|
|
42
|
+
let token = "";
|
|
43
|
+
let quote: '"' | "'" | null = null;
|
|
44
|
+
|
|
45
|
+
for (let i = 0; i < raw.length; i += 1) {
|
|
46
|
+
const char = raw[i];
|
|
47
|
+
if ((char === '"' || char === "'") && raw[i - 1] !== "\\") {
|
|
48
|
+
if (quote === char) quote = null;
|
|
49
|
+
else if (!quote) quote = char;
|
|
50
|
+
token += char;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (char === "," && !quote) {
|
|
54
|
+
const cleaned = cleanFontFamilyName(token);
|
|
55
|
+
if (cleaned) families.push(cleaned);
|
|
56
|
+
token = "";
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
token += char;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const cleaned = cleanFontFamilyName(token);
|
|
63
|
+
if (cleaned) families.push(cleaned);
|
|
64
|
+
return families;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function normalizeFontFamilyName(value: string): string {
|
|
68
|
+
return cleanFontFamilyName(value).replace(/\s+/g, " ").toLowerCase();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function normalizeFontFamilyStack(value: string): string {
|
|
72
|
+
return splitFontFamilyList(value).map(normalizeFontFamilyName).join(",");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function displayFontFamilyName(value: string | undefined): string {
|
|
76
|
+
const first = splitFontFamilyList(value)[0];
|
|
77
|
+
if (!first) return "Sans Serif"; // i18n-ignore design generic font label
|
|
78
|
+
|
|
79
|
+
const normalized = normalizeFontFamilyName(first);
|
|
80
|
+
if (normalized === "sans-serif") {
|
|
81
|
+
return "Sans Serif"; // i18n-ignore design generic font label
|
|
82
|
+
}
|
|
83
|
+
if (normalized === "serif") return "Serif"; // i18n-ignore design generic font label
|
|
84
|
+
if (normalized === "monospace") {
|
|
85
|
+
return "Monospace"; // i18n-ignore design generic font label
|
|
86
|
+
}
|
|
87
|
+
if (normalized === "system-ui" || normalized === "-apple-system") {
|
|
88
|
+
return "System UI"; // i18n-ignore design generic font label
|
|
89
|
+
}
|
|
90
|
+
if (normalized === "blinkmacsystemfont") {
|
|
91
|
+
return "Apple System"; // i18n-ignore design generic font label
|
|
92
|
+
}
|
|
93
|
+
return first;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function resolveFontFamilySelectValue(
|
|
97
|
+
value: string | undefined,
|
|
98
|
+
): string {
|
|
99
|
+
const raw = value?.trim();
|
|
100
|
+
if (!raw) return "sans-serif";
|
|
101
|
+
|
|
102
|
+
const normalizedStack = normalizeFontFamilyStack(raw);
|
|
103
|
+
const exactOption = FONT_FAMILY_OPTIONS.find(
|
|
104
|
+
(option) => normalizeFontFamilyStack(option.value) === normalizedStack,
|
|
105
|
+
);
|
|
106
|
+
if (exactOption) return exactOption.value;
|
|
107
|
+
|
|
108
|
+
const firstFamily = normalizeFontFamilyName(
|
|
109
|
+
splitFontFamilyList(raw)[0] ?? "",
|
|
110
|
+
);
|
|
111
|
+
const firstFamilyOption = FONT_FAMILY_OPTIONS.find(
|
|
112
|
+
(option) =>
|
|
113
|
+
normalizeFontFamilyName(splitFontFamilyList(option.value)[0] ?? "") ===
|
|
114
|
+
firstFamily,
|
|
115
|
+
);
|
|
116
|
+
return firstFamilyOption?.value ?? raw;
|
|
117
|
+
}
|