camox 0.44.0 → 0.45.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/dist/components/AuthGate.js +0 -6
- package/dist/components/DeviceSelector.js +96 -0
- package/dist/components/PlatformLabel.js +20 -24
- package/dist/core/components/lexical/HighlightNode.js +1 -1
- package/dist/core/components/lexical/InlineContentEditable.js +15 -19
- package/dist/core/components/lexical/InlineLexicalEditor.js +54 -74
- package/dist/core/components/lexical/InlineStylesPlugin.js +53 -53
- package/dist/core/components/lexical/MaxLengthPlugin.js +59 -0
- package/dist/core/components/lexical/SelectionBroadcaster.js +53 -54
- package/dist/core/components/lexical/SidebarLexicalEditor.js +322 -229
- package/dist/core/components/lexical/SummaryToggleGuard.js +42 -0
- package/dist/core/components/lexical/TextLinkPopover.js +169 -180
- package/dist/core/createApp.d.ts +241 -312
- package/dist/core/createApp.js +123 -29
- package/dist/core/createBlock.d.ts +5 -5
- package/dist/core/createBlock.js +385 -152
- package/dist/core/createCollection.d.ts +55 -0
- package/dist/core/createCollection.js +93 -0
- package/dist/core/createLayout.d.ts +197 -61
- package/dist/core/createLayout.js +114 -56
- package/dist/core/defineDocument.d.ts +3 -5
- package/dist/core/derivedRoutes.js +49 -1
- package/dist/core/dom.d.ts +13 -4
- package/dist/core/dom.js +44 -1
- package/dist/core/editing/BlockEditingRuntime.d.ts +16 -0
- package/dist/core/editing/BlockEditingRuntime.js +6 -15
- package/dist/core/editing/CompleteBlockEditingRuntime.js +28 -23
- package/dist/core/editing/createEditableBlock.d.ts +754 -633
- package/dist/core/editing/createEditableBlock.js +2113 -1066
- package/dist/core/editing/referenceWrites.js +51 -0
- package/dist/core/editing/useLatestRecord.js +90 -0
- package/dist/core/hooks/useArtifactHost.js +139 -0
- package/dist/core/hooks/useFieldSelection.js +43 -18
- package/dist/core/hooks/useIsEditable.js +12 -10
- package/dist/core/hooks/useOverlayMessage.js +15 -19
- package/dist/core/lib/artifact.d.ts +21 -0
- package/dist/core/lib/artifact.js +154 -0
- package/dist/core/lib/artifactColors.js +123 -0
- package/dist/core/lib/artifactData.d.ts +1 -0
- package/dist/core/lib/artifactData.js +131 -0
- package/dist/core/lib/artifactHost.js +205 -0
- package/dist/core/lib/artifactRuntime.js +36 -0
- package/dist/core/lib/artifactTheme.js +57 -0
- package/dist/core/lib/contentType.d.ts +302 -106
- package/dist/core/lib/contentType.js +201 -173
- package/dist/core/lib/fieldTypes.js +3 -0
- package/dist/core/lib/iconTypes.d.ts +3 -3
- package/dist/core/lib/icons.d.ts +4 -4
- package/dist/core/lib/icons.js +40 -44
- package/dist/core/lib/imagePlaceholder.js +177 -0
- package/dist/core/lib/imageTransform.js +1 -1
- package/dist/core/lib/lexicalReact.d.ts +3 -1
- package/dist/core/lib/lexicalState.js +1 -1
- package/dist/core/lib/previewPaused.js +9 -0
- package/dist/core/lib/recordScope.js +316 -0
- package/dist/core/lib/reference.d.ts +81 -0
- package/dist/core/lib/reference.js +29 -0
- package/dist/core/lib/textLinks.js +7 -5
- package/dist/core/lib/textStyles.d.ts +5 -7
- package/dist/core/lib/textStyles.js +2 -2
- package/dist/core/notFound.d.ts +7 -0
- package/dist/core/notFound.js +11 -0
- package/dist/core/pageDestinations.js +6 -3
- package/dist/core/recordItem.js +34 -0
- package/dist/core/requestContext.d.ts +26 -0
- package/dist/core/requestContext.js +20 -0
- package/dist/features/canvas/CamoxCanvas.js +1734 -0
- package/dist/features/canvas/CanvasBlockFrame.js +353 -0
- package/dist/features/canvas/CanvasBlockHeader.js +55 -0
- package/dist/features/canvas/CanvasLoadingScreen.js +35 -0
- package/dist/features/canvas/CanvasOverlays.js +254 -0
- package/dist/features/canvas/CanvasPageEdge.js +87 -0
- package/dist/features/canvas/CanvasPageFrame.js +335 -0
- package/dist/features/canvas/CanvasPageHeader.js +125 -0
- package/dist/features/canvas/CanvasPreviewPageSlot.js +103 -0
- package/dist/features/canvas/CanvasShelfMarker.js +255 -0
- package/dist/features/canvas/DerivedPagePathInput.js +238 -0
- package/dist/features/canvas/canvasCamera.js +229 -0
- package/dist/features/canvas/canvasFlight.js +104 -0
- package/dist/features/canvas/canvasFrameCapture.js +364 -0
- package/dist/features/canvas/canvasFrameDocument.js +317 -0
- package/dist/features/canvas/canvasFrameMode.js +53 -0
- package/dist/features/canvas/canvasInsertionSeams.js +44 -0
- package/dist/features/canvas/canvasItems.js +120 -0
- package/dist/features/canvas/canvasOverlayGeometry.js +240 -0
- package/dist/features/canvas/canvasPages.js +79 -0
- package/dist/features/canvas/canvasScreenSpace.js +26 -0
- package/dist/features/canvas/canvasSelection.js +18 -0
- package/dist/features/canvas/canvasStore.js +149 -0
- package/dist/features/canvas/canvasThumbnails.js +304 -0
- package/dist/features/canvas/canvasZoom.js +10 -0
- package/dist/features/canvas/sidebar/CanvasInspector.js +202 -0
- package/dist/features/canvas/sidebar/CanvasNavigator.js +226 -0
- package/dist/features/canvas/sidebar/CanvasSidebar.js +60 -0
- package/dist/features/canvas/sidebar/CanvasSidebarFrame.js +48 -0
- package/dist/features/canvas/sidebar/CanvasSidebarSkeleton.js +39 -0
- package/dist/features/canvas/sidebar/CatalogBlockInspector.js +189 -0
- package/dist/features/canvas/sidebar/CuratedPageInspector.js +69 -0
- package/dist/features/canvas/sidebar/DerivedPageInspector.js +37 -0
- package/dist/features/canvas/sidebar/LayoutPageBlocks.js +78 -0
- package/dist/features/canvas/sidebar/LayoutPageOverview.js +71 -0
- package/dist/features/canvas/sidebar/PageInspector.js +157 -0
- package/dist/features/canvas/sidebar/PageInspectorSkeleton.js +90 -0
- package/dist/features/canvas/sidebar/PageOverview.js +27 -0
- package/dist/features/canvas/sidebar/SingletonPageInspector.js +31 -0
- package/dist/features/canvas/useCanvasCamera.js +803 -0
- package/dist/features/canvas/useCanvasFrame.js +149 -0
- package/dist/features/canvas/useCanvasFrameInput.js +97 -0
- package/dist/features/canvas/useCanvasNearness.js +57 -0
- package/dist/features/canvas/useDiscoveredPreviewPaths.js +62 -0
- package/dist/features/content/CamoxContent.d.ts +2 -5
- package/dist/features/content/CamoxContent.js +174 -271
- package/dist/features/content/CollectionItemSheetContext.js +106 -0
- package/dist/features/content/ContentAssets.js +315 -0
- package/dist/features/content/ContentCollection.js +663 -0
- package/dist/features/content/collection-form.js +58 -0
- package/dist/features/content/components/AssetCard.js +80 -84
- package/dist/features/content/components/AssetCardSkeleton.js +4 -8
- package/dist/features/content/components/ContentSidebar.js +129 -18
- package/dist/features/content/components/ContentSidebarGroup.js +37 -0
- package/dist/features/content/components/DeleteCollectionItemButton.js +202 -0
- package/dist/features/content/components/MissingFromLocale.js +282 -0
- package/dist/features/content/components/UploadDropZone.js +27 -31
- package/dist/features/content/components/UploadProgressDrawer.js +90 -98
- package/dist/features/navigation/navigation.d.ts +66 -20
- package/dist/features/navigation/navigation.js +257 -90
- package/dist/features/og/defaultFonts.js +8 -8
- package/dist/features/og/geist-variable-ttf-base64.js +1 -1
- package/dist/features/og/imageResponse.d.ts +8 -0
- package/dist/features/og/imageResponse.js +26 -0
- package/dist/features/page/CuratedPageContent.js +167 -0
- package/dist/features/page/DerivedPageContent.js +26 -30
- package/dist/features/page/SharedLayoutContent.js +25 -27
- package/dist/features/preview/CamoxPreview.d.ts +23 -61
- package/dist/features/preview/CamoxPreview.js +816 -537
- package/dist/features/preview/EditablePageContent.js +1 -1
- package/dist/features/preview/EditablePageExperience.js +16 -22
- package/dist/features/preview/components/AddBlockDialog.js +270 -0
- package/dist/features/preview/components/AssetFieldEditor.js +173 -154
- package/dist/features/preview/components/AssetLightbox.js +181 -134
- package/dist/features/preview/components/AssetPickerModal.js +153 -170
- package/dist/features/preview/components/BlockActionsPopover.js +150 -149
- package/dist/features/preview/components/BlockErrorBoundary.js +8 -12
- package/dist/features/preview/components/BlockThumbnail.js +176 -100
- package/dist/features/preview/components/CanvasPreview.js +243 -0
- package/dist/features/preview/components/CreatePageModal.js +128 -137
- package/dist/features/preview/components/DebouncedFieldEditor.js +29 -33
- package/dist/features/preview/components/DerivedLayoutDialog.js +21 -19
- package/dist/features/preview/components/DrillRow.js +150 -0
- package/dist/features/preview/components/FieldOverlayStyles.js +11 -8
- package/dist/features/preview/components/FieldToolbar.js +160 -110
- package/dist/features/preview/components/Frame.js +108 -20
- package/dist/features/preview/components/IconFieldEditor.js +62 -66
- package/dist/features/preview/components/ItemFieldsEditor.js +231 -205
- package/dist/features/preview/components/LinkFieldEditor.js +135 -139
- package/dist/features/preview/components/Metadata.js +22 -30
- package/dist/features/preview/components/MobilePreviewDrawer.js +89 -108
- package/dist/features/preview/components/MultipleAssetFieldEditor.js +334 -246
- package/dist/features/preview/components/OverlayTracker.js +9 -41
- package/dist/features/preview/components/Overlays.js +81 -69
- package/dist/features/preview/components/PageInfo.js +1748 -0
- package/dist/features/preview/components/PageInfoSkeleton.js +51 -0
- package/dist/features/preview/components/PageLocationFieldset.js +112 -116
- package/dist/features/preview/components/PageNavigatorHeader.js +24 -0
- package/dist/features/preview/components/PageNicknameField.js +22 -26
- package/dist/features/preview/components/PagePicker.js +128 -130
- package/dist/features/preview/components/PageTree.js +525 -532
- package/dist/features/preview/components/PreviewActivation.js +28 -32
- package/dist/features/preview/components/PreviewPanel.js +620 -319
- package/dist/features/preview/components/PreviewToolbar.js +105 -333
- package/dist/features/preview/components/RecordCard.js +80 -0
- package/dist/features/preview/components/RecordCombobox.js +178 -0
- package/dist/features/preview/components/ReferenceFieldEditor.js +149 -0
- package/dist/features/preview/components/ReferenceListFieldEditor.js +432 -0
- package/dist/features/preview/components/RemovedBlockPlaceholder.js +95 -0
- package/dist/features/preview/components/RepeatableItemsList.js +125 -138
- package/dist/features/preview/components/SelectionEditor.js +993 -0
- package/dist/features/preview/components/ShikiMarkdown.js +14 -18
- package/dist/features/preview/components/SidebarSection.js +52 -64
- package/dist/features/preview/components/StudioEditingFallback.js +56 -0
- package/dist/features/preview/components/UnlinkAssetButton.js +104 -107
- package/dist/features/preview/components/blockGridNavigation.js +15 -0
- package/dist/features/preview/components/contentFieldSchema.js +8 -0
- package/dist/features/preview/components/useFieldWriter.js +200 -0
- package/dist/features/preview/components/useRecordView.js +383 -0
- package/dist/features/preview/components/useRepeatableItemActions.js +35 -37
- package/dist/features/preview/components/useUpdateBlockPosition.js +37 -37
- package/dist/features/preview/editingFrame.js +197 -0
- package/dist/features/preview/overlayHighlights.js +17 -44
- package/dist/features/preview/overlayMessages.js +72 -1
- package/dist/features/preview/pageRecord.js +189 -0
- package/dist/features/preview/previewConstants.js +6 -2
- package/dist/features/preview/previewPageFrame.js +95 -0
- package/dist/features/preview/previewPreparation.js +7 -0
- package/dist/features/preview/previewSelection.js +32 -63
- package/dist/features/preview/previewStore.js +225 -123
- package/dist/features/preview/referencePickerFocus.js +29 -0
- package/dist/features/preview/repeatableItemTargets.js +56 -0
- package/dist/features/preview/selectionReveal.js +21 -0
- package/dist/features/preview/usePreviewViewportActions.js +114 -0
- package/dist/features/preview/viewportContinuity.js +109 -0
- package/dist/features/provider/AuthenticatedCamoxProvider.js +69 -44
- package/dist/features/provider/CamoxProvider.d.ts +3 -6
- package/dist/features/provider/CamoxProvider.js +38 -50
- package/dist/features/provider/CoreCamoxProvider.js +66 -50
- package/dist/features/provider/LocalhostPreviewProvider.js +78 -114
- package/dist/features/provider/PreviewSignInPage.js +54 -0
- package/dist/features/provider/components/CamoxAppContext.js +11 -11
- package/dist/features/provider/components/CommandPalette.js +75 -82
- package/dist/features/provider/useAdminShortcuts.js +7 -11
- package/dist/features/routes/pageRuntime.d.ts +44 -4
- package/dist/features/routes/pageRuntime.js +244 -137
- package/dist/features/runtime/RuntimeChrome.js +117 -115
- package/dist/features/runtime/alternates.js +64 -0
- package/dist/features/runtime/analytics.d.ts +7 -0
- package/dist/features/runtime/analytics.js +66 -0
- package/dist/features/runtime/artifactSources.js +87 -0
- package/dist/features/runtime/editingFallback.js +20 -0
- package/dist/features/runtime/linkPrefetch.js +97 -0
- package/dist/features/runtime/livePages.js +62 -0
- package/dist/features/runtime/llmsTxt.js +40 -0
- package/dist/features/runtime/loopbackFetch.js +18 -0
- package/dist/features/runtime/navigationAccessibility.js +51 -0
- package/dist/features/runtime/navigationTarget.js +23 -2
- package/dist/features/runtime/pageApp.js +229 -158
- package/dist/features/runtime/pageBlockTypes.js +20 -0
- package/dist/features/runtime/pageClient.d.ts +2 -4
- package/dist/features/runtime/pageClient.js +18 -3
- package/dist/features/runtime/pageNavigation.js +254 -32
- package/dist/features/runtime/pageServer.d.ts +2 -4
- package/dist/features/runtime/pageServer.js +6 -2
- package/dist/features/runtime/pageViewport.js +7 -0
- package/dist/features/runtime/runtime.d.ts +59 -24
- package/dist/features/runtime/runtime.js +779 -191
- package/dist/features/runtime/runtimeChromeLoader.js +58 -0
- package/dist/features/runtime/runtimeRoutes.d.ts +19 -0
- package/dist/features/runtime/runtimeRoutes.js +25 -0
- package/dist/features/runtime/scrollRestoration.js +133 -0
- package/dist/features/runtime/studioApp.d.ts +4 -3
- package/dist/features/runtime/studioApp.js +5 -9
- package/dist/features/runtime/studioClient.d.ts +2 -4
- package/dist/features/runtime/studioClient.js +12 -3
- package/dist/features/runtime/studioServer.d.ts +2 -4
- package/dist/features/runtime/studioServer.js +6 -1
- package/dist/features/runtime/worker.d.ts +6 -0
- package/dist/features/runtime/worker.js +23 -0
- package/dist/features/runtime/workerRequest.js +44 -0
- package/dist/features/studio/CamoxStudio.d.ts +2 -6
- package/dist/features/studio/CamoxStudio.js +34 -49
- package/dist/features/studio/FollowAgentProvider.js +338 -0
- package/dist/features/studio/components/ChatSidebar.js +356 -0
- package/dist/features/studio/components/DraftsControl.js +676 -0
- package/dist/features/studio/components/FaviconDialog.js +318 -0
- package/dist/features/studio/components/LocalePicker.js +785 -0
- package/dist/features/studio/components/Navbar.js +123 -103
- package/dist/features/studio/components/ProjectMenu.js +239 -260
- package/dist/features/studio/components/RenameDraftDialog.js +206 -0
- package/dist/features/studio/components/ReviewDraftSheet.js +1472 -0
- package/dist/features/studio/components/ThreadComposer.js +157 -0
- package/dist/features/studio/components/ThreadMarkdown.js +113 -0
- package/dist/features/studio/components/ThreadMessages.js +270 -0
- package/dist/features/studio/components/UserButton.js +34 -23
- package/dist/features/studio/draftLabel.js +33 -0
- package/dist/features/studio/draftNotice.js +13 -0
- package/dist/features/studio/followAgent.js +250 -0
- package/dist/features/studio/followAgentContext.js +7 -0
- package/dist/features/studio/localeOptions.js +118 -0
- package/dist/features/studio/localeSwitch.js +19 -0
- package/dist/features/studio/routes.js +48 -1
- package/dist/features/studio/studioStore.js +64 -1
- package/dist/features/studio/useTheme.js +24 -27
- package/dist/features/vite/artifactRuntimeMinification.js +36 -0
- package/dist/features/vite/blockBoilerplate.js +6 -5
- package/dist/features/vite/blockChunks.js +31 -0
- package/dist/features/vite/bundlerLogs.js +17 -0
- package/dist/features/vite/definitionsSync.js +158 -226
- package/dist/features/vite/devAuthentication.js +4 -16
- package/dist/features/vite/devSignIn.js +87 -0
- package/dist/features/vite/iconGeneration.js +1 -1
- package/dist/features/vite/layoutGeneration.js +11 -1
- package/dist/features/vite/publishSeededContent.js +30 -0
- package/dist/features/vite/routeGeneration.js +6 -7
- package/dist/features/vite/runtimeDev.js +80 -99
- package/dist/features/vite/vite.d.ts +51 -31
- package/dist/features/vite/vite.js +224 -127
- package/dist/features/vite/workerBuild.js +39 -0
- package/dist/hooks/use-debounced-field.js +116 -47
- package/dist/hooks/use-file-upload.js +114 -67
- package/dist/hooks/use-marquee-selection.js +32 -36
- package/dist/hooks/use-page-destinations.js +69 -37
- package/dist/lib/api-client-server.d.ts +5 -0
- package/dist/lib/api-client-server.js +10 -4
- package/dist/lib/api-client.d.ts +6 -0
- package/dist/lib/api-client.js +51 -16
- package/dist/lib/api-socket.js +17 -0
- package/dist/lib/auth-page-styles.js +39 -0
- package/dist/lib/auth.js +117 -61
- package/dist/lib/collection-cache.js +23 -0
- package/dist/lib/draft-scope.d.ts +4 -0
- package/dist/lib/draft-scope.js +222 -0
- package/dist/lib/html.js +12 -0
- package/dist/lib/link-pages.js +154 -0
- package/dist/lib/locale-path.d.ts +22 -0
- package/dist/lib/locale-path.js +57 -0
- package/dist/lib/normalized-data.js +252 -152
- package/dist/lib/preview-handoff.js +2 -2
- package/dist/lib/queries.d.ts +11 -0
- package/dist/lib/queries.js +70 -141
- package/dist/lib/studio-reads.d.ts +14 -0
- package/dist/lib/studio-reads.js +574 -0
- package/dist/lib/use-project-room.js +50 -50
- package/dist/lib/use-thread.js +310 -0
- package/dist/lib/utils.js +25 -29
- package/dist/lib/view-locale-context.js +22 -0
- package/dist/lib/view-locale.js +46 -0
- package/dist/package.js +5 -0
- package/dist/studio-overlays.css +41 -151
- package/dist/studio.css +2 -2
- package/package.json +70 -73
- package/skills/camox/SKILL.md +16 -11
- package/skills/camox/references/artifacts.md +179 -0
- package/skills/camox/references/block-definitions.md +75 -59
- package/skills/camox/references/cli-common.md +9 -11
- package/skills/camox/references/cli-content.md +92 -69
- package/skills/camox/references/cli-publishing.md +26 -0
- package/skills/camox/references/dom-integrations.md +27 -0
- package/skills/camox/references/field-styling.md +4 -4
- package/skills/camox/references/layout-definitions.md +16 -14
- package/skills/camox/references/localization.md +56 -0
- package/skills/camox/references/routed-layouts.md +133 -15
- package/skills/camox-expand/SKILL.md +69 -0
- package/skills/camox-expand/references/jobs.md +39 -0
- package/skills/camoxify/SKILL.md +29 -7
- package/dist/core/components/AddBlockControlBar.js +0 -78
- package/dist/core/hooks/useRequireDraftSource.js +0 -23
- package/dist/features/metadata/sitemap.d.ts +0 -8
- package/dist/features/metadata/sitemap.js +0 -17
- package/dist/features/og/imageResponse.node.d.ts +0 -12
- package/dist/features/og/imageResponse.node.js +0 -49
- package/dist/features/og/imageResponse.workerd.d.ts +0 -12
- package/dist/features/og/imageResponse.workerd.js +0 -40
- package/dist/features/page/PublishedPageContent.js +0 -205
- package/dist/features/page/PublishedPageExperience.js +0 -23
- package/dist/features/preview/DerivedPreview.js +0 -134
- package/dist/features/preview/commentsEnabled.js +0 -8
- package/dist/features/preview/components/AddBlockSidebar.js +0 -381
- package/dist/features/preview/components/AttachedComments.js +0 -331
- package/dist/features/preview/components/CommentHeader.js +0 -122
- package/dist/features/preview/components/CommentSidebar.js +0 -29
- package/dist/features/preview/components/CommentTargetQuote.js +0 -167
- package/dist/features/preview/components/DerivedLayoutSidebar.d.ts +0 -5
- package/dist/features/preview/components/DerivedLayoutSidebar.js +0 -179
- package/dist/features/preview/components/DerivedPageInfoSidebar.js +0 -69
- package/dist/features/preview/components/LeftSidebar.js +0 -68
- package/dist/features/preview/components/PageEditorSidebar.js +0 -563
- package/dist/features/preview/components/PageInfoSidebar.js +0 -1551
- package/dist/features/preview/components/PageNavigatorSidebar.js +0 -78
- package/dist/features/preview/components/PageStatusBadge.js +0 -97
- package/dist/features/preview/components/PeekedBlock.js +0 -217
- package/dist/features/preview/components/PreviewComments.js +0 -56
- package/dist/features/preview/components/PreviewToolbarSpacer.js +0 -43
- package/dist/features/preview/components/PublicationRow.js +0 -422
- package/dist/features/preview/components/PublishDialog.js +0 -194
- package/dist/features/preview/components/RightSidebar.js +0 -59
- package/dist/features/preview/components/SendFeedbackDialog.js +0 -83
- package/dist/features/preview/previewCommentsStore.js +0 -135
- package/dist/features/preview/publication.js +0 -81
- package/dist/features/preview/usePageComments.js +0 -39
- package/dist/features/runtime/SharedChromeContext.js +0 -7
- package/dist/features/studio/components/EnvironmentMenu.js +0 -425
- package/dist/features/vite/appGeneration.js +0 -89
- package/dist/lib/view-queries.js +0 -28
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/Matches.d.ts +0 -114
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/RouterProvider.d.ts +0 -25
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/config.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/defer.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/fileRoute.d.ts +0 -20
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/global.d.ts +0 -8
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/hash-scroll.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/index.d.ts +0 -18
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/link.d.ts +0 -161
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/load-matches.d.ts +0 -6
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/location.d.ts +0 -54
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/lru-cache.d.ts +0 -8
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/manifest.d.ts +0 -32
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.d.ts +0 -115
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/not-found.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/redirect.d.ts +0 -49
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/rewrite.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/root.d.ts +0 -6
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/route.d.ts +0 -343
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/routeInfo.d.ts +0 -48
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/router.d.ts +0 -695
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/scroll-restoration.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/searchMiddleware.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/searchParams.d.ts +0 -5
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/ssr/serializer/RawStream.d.ts +0 -38
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/ssr/serializer/seroval-plugins.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/ssr/serializer/transformer.d.ts +0 -65
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/stores.d.ts +0 -69
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/structuralSharing.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/typePrimitives.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useLoaderData.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useLoaderDeps.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useNavigate.d.ts +0 -10
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useParams.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useRouteContext.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useSearch.d.ts +0 -1
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/utils.d.ts +0 -28
- package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/validators.d.ts +0 -49
- package/skills/camox/references/cli-environments.md +0 -37
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
//#region src/core/lib/artifactColors.ts
|
|
2
|
+
const unit = (part, percentOf) => {
|
|
3
|
+
if (part === "none") return 0;
|
|
4
|
+
const value = parseFloat(part);
|
|
5
|
+
return part.endsWith("%") ? value / 100 * percentOf : value;
|
|
6
|
+
};
|
|
7
|
+
const hue = (part) => {
|
|
8
|
+
if (part === "none") return 0;
|
|
9
|
+
const value = parseFloat(part);
|
|
10
|
+
if (part.endsWith("grad")) return value * .9;
|
|
11
|
+
if (part.endsWith("rad")) return value * 180 / Math.PI;
|
|
12
|
+
if (part.endsWith("turn")) return value * 360;
|
|
13
|
+
return value;
|
|
14
|
+
};
|
|
15
|
+
const encode = (linear) => {
|
|
16
|
+
const x = Math.min(1, Math.max(0, linear));
|
|
17
|
+
return x <= .0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - .055;
|
|
18
|
+
};
|
|
19
|
+
const fromOklab = (L, a, b) => {
|
|
20
|
+
const l = Math.pow(L + .3963377774 * a + .2158037573 * b, 3);
|
|
21
|
+
const m = Math.pow(L - .1055613458 * a - .0638541728 * b, 3);
|
|
22
|
+
const s = Math.pow(L - .0894841775 * a - 1.291485548 * b, 3);
|
|
23
|
+
return [
|
|
24
|
+
encode(4.0767416621 * l - 3.3077115913 * m + .2309699292 * s),
|
|
25
|
+
encode(-1.2684380046 * l + 2.6097574011 * m - .3413193965 * s),
|
|
26
|
+
encode(-.0041960863 * l - .7034186147 * m + 1.707614701 * s)
|
|
27
|
+
];
|
|
28
|
+
};
|
|
29
|
+
const fromHsl = (h, s, l) => {
|
|
30
|
+
const k = (n) => (n + h / 30) % 12;
|
|
31
|
+
const a = s * Math.min(l, 1 - l);
|
|
32
|
+
const f = (n) => l - a * Math.max(-1, Math.min(k(n) - 3, 9 - k(n), 1));
|
|
33
|
+
return [
|
|
34
|
+
f(0),
|
|
35
|
+
f(8),
|
|
36
|
+
f(4)
|
|
37
|
+
];
|
|
38
|
+
};
|
|
39
|
+
/** Hex, `rgb()`, `hsl()`, `oklab()` and `oklch()` colors, as channels from 0 to 1. */
|
|
40
|
+
function parse(value) {
|
|
41
|
+
const text = value.trim().toLowerCase();
|
|
42
|
+
if (text.startsWith("#")) {
|
|
43
|
+
let hex = text.slice(1);
|
|
44
|
+
if (!/^[0-9a-f]+$/.test(hex) || ![
|
|
45
|
+
3,
|
|
46
|
+
4,
|
|
47
|
+
6,
|
|
48
|
+
8
|
|
49
|
+
].includes(hex.length)) return null;
|
|
50
|
+
if (hex.length < 6) hex = hex.replace(/./g, "$&$&");
|
|
51
|
+
const [r, g, b] = [
|
|
52
|
+
0,
|
|
53
|
+
2,
|
|
54
|
+
4
|
|
55
|
+
].map((start) => parseInt(hex.slice(start, start + 2), 16) / 255);
|
|
56
|
+
return [
|
|
57
|
+
r,
|
|
58
|
+
g,
|
|
59
|
+
b
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
const open = text.indexOf("(");
|
|
63
|
+
if (open < 0 || !text.endsWith(")")) return null;
|
|
64
|
+
const parts = text.slice(open + 1, -1).split(/[^0-9a-z.%+-]+/).filter(Boolean);
|
|
65
|
+
if (parts.length < 3) return null;
|
|
66
|
+
if (parts.slice(0, 3).some((part) => part !== "none" && !Number.isFinite(parseFloat(part)))) return null;
|
|
67
|
+
const [x, y, z] = parts;
|
|
68
|
+
switch (text.slice(0, open)) {
|
|
69
|
+
case "rgb":
|
|
70
|
+
case "rgba": return [
|
|
71
|
+
unit(x, 255) / 255,
|
|
72
|
+
unit(y, 255) / 255,
|
|
73
|
+
unit(z, 255) / 255
|
|
74
|
+
];
|
|
75
|
+
case "hsl":
|
|
76
|
+
case "hsla": return fromHsl(hue(x), parseFloat(y) / 100 || 0, parseFloat(z) / 100 || 0);
|
|
77
|
+
case "oklab": return fromOklab(unit(x, 1), unit(y, .4), unit(z, .4));
|
|
78
|
+
case "oklch": {
|
|
79
|
+
const chroma = unit(y, .4);
|
|
80
|
+
const angle = hue(z) * Math.PI / 180;
|
|
81
|
+
return fromOklab(unit(x, 1), chroma * Math.cos(angle), chroma * Math.sin(angle));
|
|
82
|
+
}
|
|
83
|
+
default: return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The sRGB colors of a page's theme tokens, so artifacts get them ready to use and never parse
|
|
88
|
+
* CSS themselves. Common color syntaxes are converted directly; any other color the page's
|
|
89
|
+
* browser understands (named colors, `lab()`, `color-mix()`…) goes through a 1×1 canvas of the
|
|
90
|
+
* page's own document. Tokens that aren't colors are left out.
|
|
91
|
+
*/
|
|
92
|
+
function artifactThemeColors(tokens, page) {
|
|
93
|
+
let canvas;
|
|
94
|
+
const paint = (value) => {
|
|
95
|
+
if (!page.CSS?.supports("color", value)) return null;
|
|
96
|
+
canvas ??= page.document.createElement("canvas").getContext("2d", { willReadFrequently: true });
|
|
97
|
+
if (!canvas) return null;
|
|
98
|
+
canvas.clearRect(0, 0, 1, 1);
|
|
99
|
+
canvas.fillStyle = value;
|
|
100
|
+
canvas.fillRect(0, 0, 1, 1);
|
|
101
|
+
const [r, g, b] = canvas.getImageData(0, 0, 1, 1).data;
|
|
102
|
+
return [
|
|
103
|
+
r / 255,
|
|
104
|
+
g / 255,
|
|
105
|
+
b / 255
|
|
106
|
+
];
|
|
107
|
+
};
|
|
108
|
+
const colors = {};
|
|
109
|
+
for (const [name, value] of Object.entries(tokens)) {
|
|
110
|
+
const channels = parse(value) ?? paint(value);
|
|
111
|
+
if (!channels) continue;
|
|
112
|
+
const [r, g, b] = channels.map((channel) => Math.round(Math.min(1, Math.max(0, channel)) * 255));
|
|
113
|
+
colors[name] = {
|
|
114
|
+
r,
|
|
115
|
+
g,
|
|
116
|
+
b
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return colors;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
//#endregion
|
|
123
|
+
export { artifactThemeColors };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { TSchema } from "@sinclair/typebox";
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
//#region src/core/lib/artifactData.ts
|
|
2
|
+
const DATA_SOURCES = Symbol("camox.artifactDataSources");
|
|
3
|
+
/** Content fields that can't be Artifact Data. */
|
|
4
|
+
const unsharedFieldTypes = /* @__PURE__ */ new Set([
|
|
5
|
+
"Artifact",
|
|
6
|
+
"Repeater",
|
|
7
|
+
"Reference",
|
|
8
|
+
"ReferenceList"
|
|
9
|
+
]);
|
|
10
|
+
const text = { type: "string" };
|
|
11
|
+
function objectSchema(properties, title) {
|
|
12
|
+
return {
|
|
13
|
+
type: "object",
|
|
14
|
+
...title === void 0 ? {} : { title },
|
|
15
|
+
properties,
|
|
16
|
+
required: Object.keys(properties),
|
|
17
|
+
additionalProperties: false
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const assetProperties = {
|
|
21
|
+
Image: {
|
|
22
|
+
url: text,
|
|
23
|
+
alt: text
|
|
24
|
+
},
|
|
25
|
+
File: {
|
|
26
|
+
url: text,
|
|
27
|
+
filename: text
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
/** The JSON Schema of one normalized Artifact Data value. */
|
|
31
|
+
function valueSchema(schema) {
|
|
32
|
+
const title = schema.title;
|
|
33
|
+
const titled = title === void 0 ? {} : { title };
|
|
34
|
+
switch (schema.fieldType) {
|
|
35
|
+
case "Link": return objectSchema({
|
|
36
|
+
text,
|
|
37
|
+
href: text,
|
|
38
|
+
newTab: { type: "boolean" }
|
|
39
|
+
}, title);
|
|
40
|
+
case "Image":
|
|
41
|
+
case "File": return objectSchema(assetProperties[schema.fieldType], title);
|
|
42
|
+
case "ImageList":
|
|
43
|
+
case "FileList": {
|
|
44
|
+
const single = schema.fieldType === "ImageList" ? "Image" : "File";
|
|
45
|
+
return {
|
|
46
|
+
type: "array",
|
|
47
|
+
...titled,
|
|
48
|
+
items: objectSchema(assetProperties[single])
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
case "Boolean": return {
|
|
52
|
+
type: "boolean",
|
|
53
|
+
...titled
|
|
54
|
+
};
|
|
55
|
+
case "Enum": return {
|
|
56
|
+
type: "string",
|
|
57
|
+
...titled,
|
|
58
|
+
enum: schema.enum
|
|
59
|
+
};
|
|
60
|
+
default: return {
|
|
61
|
+
type: "string",
|
|
62
|
+
...titled
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Resolves each artifact's `data` against its siblings: the content fields and settings of a
|
|
68
|
+
* block, or of a repeatable item. Adds the Artifact Data's JSON Schema to the artifact's
|
|
69
|
+
* definition, so `blocks describe` shows agents the exact shape of `camox.data`.
|
|
70
|
+
*/
|
|
71
|
+
function attachArtifactData(content, settings, owner) {
|
|
72
|
+
for (const [key, field] of Object.entries(content)) {
|
|
73
|
+
if (field.fieldType !== "Artifact") continue;
|
|
74
|
+
const names = field.data ?? [];
|
|
75
|
+
if (names.length === 0) continue;
|
|
76
|
+
const sources = {};
|
|
77
|
+
for (const name of names) {
|
|
78
|
+
const source = Object.hasOwn(content, name) ? {
|
|
79
|
+
scope: "content",
|
|
80
|
+
schema: content[name]
|
|
81
|
+
} : settings && Object.hasOwn(settings, name) ? {
|
|
82
|
+
scope: "settings",
|
|
83
|
+
schema: settings[name]
|
|
84
|
+
} : null;
|
|
85
|
+
if (!source) throw new Error(`${owner} artifact "${key}": data "${name}" is not a field or setting`);
|
|
86
|
+
if (unsharedFieldTypes.has(source.schema.fieldType)) throw new Error(`${owner} artifact "${key}": ${String(source.schema.fieldType)} "${name}" can't be Artifact Data`);
|
|
87
|
+
sources[name] = source;
|
|
88
|
+
}
|
|
89
|
+
field.dataSchema = objectSchema(Object.fromEntries(Object.entries(sources).map(([name, s]) => [name, valueSchema(s.schema)])));
|
|
90
|
+
Reflect.set(field, DATA_SOURCES, sources);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function normalizeAsset(fieldType, file) {
|
|
94
|
+
if (!file) return null;
|
|
95
|
+
return fieldType === "Image" || fieldType === "ImageList" ? {
|
|
96
|
+
url: file.url,
|
|
97
|
+
alt: file.alt ?? ""
|
|
98
|
+
} : {
|
|
99
|
+
url: file.url,
|
|
100
|
+
filename: file.filename ?? ""
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function normalizeValue(schema, value, resolve) {
|
|
104
|
+
switch (schema.fieldType) {
|
|
105
|
+
case "Link": {
|
|
106
|
+
const link = value ?? {};
|
|
107
|
+
return {
|
|
108
|
+
text: typeof link.text === "string" ? link.text : "",
|
|
109
|
+
href: resolve.linkHref(link),
|
|
110
|
+
newTab: link.newTab === true
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
case "Image":
|
|
114
|
+
case "File": return normalizeAsset(schema.fieldType, resolve.asset(value) ?? schema.default);
|
|
115
|
+
case "ImageList":
|
|
116
|
+
case "FileList": return (Array.isArray(value) ? value : []).map((item) => normalizeAsset(schema.fieldType, resolve.asset(item))).filter(Boolean);
|
|
117
|
+
default: return value ?? schema.default;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The Artifact Data of an artifact field, from its owner's content and settings: links resolved
|
|
122
|
+
* to hrefs and assets to URLs. Artifacts without `data` receive an empty object.
|
|
123
|
+
*/
|
|
124
|
+
function artifactData(field, owner, resolve) {
|
|
125
|
+
const sources = field && Reflect.get(field, DATA_SOURCES);
|
|
126
|
+
if (!sources) return {};
|
|
127
|
+
return Object.fromEntries(Object.entries(sources).map(([name, { scope, schema }]) => [name, normalizeValue(schema, owner[scope][name], resolve)]));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
//#endregion
|
|
131
|
+
export { artifactData, attachArtifactData };
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { artifactThemeColors } from "./artifactColors.js";
|
|
2
|
+
import { observeArtifactTheme, readArtifactTheme } from "./artifactTheme.js";
|
|
3
|
+
|
|
4
|
+
//#region src/core/lib/artifactHost.ts
|
|
5
|
+
function isRuntimeMessage(data) {
|
|
6
|
+
return typeof data === "object" && data !== null && typeof data.camox === "string";
|
|
7
|
+
}
|
|
8
|
+
function sameStudio(a, b) {
|
|
9
|
+
if (!a || !b) return a === b;
|
|
10
|
+
return a.editing === b.editing && a.canvas === b.canvas;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Where an artifact's `camox.navigate(href)` leads: an internal path for the client router, an
|
|
14
|
+
* external URL for a new tab, or nowhere for anything but web URLs (such as `javascript:`).
|
|
15
|
+
*/
|
|
16
|
+
function navigationTarget(href, page) {
|
|
17
|
+
if (href.startsWith("/") && !href.startsWith("//")) return { internal: href };
|
|
18
|
+
let url;
|
|
19
|
+
try {
|
|
20
|
+
url = new URL(href, page.location.href);
|
|
21
|
+
} catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
25
|
+
if (url.origin === page.location.origin) return { internal: `${url.pathname}${url.search}${url.hash}` };
|
|
26
|
+
return { external: url.href };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Follows an artifact's navigation, only right after a real click: a click inside the frame
|
|
30
|
+
* gives the page transient user activation too, so an artifact can't redirect visitors itself.
|
|
31
|
+
*/
|
|
32
|
+
function navigateFromArtifact(href, page, options) {
|
|
33
|
+
if (page.navigator.userActivation?.isActive !== true) return;
|
|
34
|
+
const target = navigationTarget(href, page);
|
|
35
|
+
if (!target) return;
|
|
36
|
+
if ("internal" in target) {
|
|
37
|
+
options.navigate?.(target.internal);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
page.open(target.external, "_blank", "noopener,noreferrer");
|
|
41
|
+
}
|
|
42
|
+
const clamp = (value) => Math.min(1, Math.max(0, value));
|
|
43
|
+
/**
|
|
44
|
+
* Where a frame sits in its page's viewport: `progress` goes from 0 when its top enters at the
|
|
45
|
+
* bottom of the viewport to 1 when its bottom leaves at the top; `visibleRatio` is the share of
|
|
46
|
+
* the frame inside the viewport.
|
|
47
|
+
*/
|
|
48
|
+
function viewportOf(frame, viewportHeight) {
|
|
49
|
+
const { top, bottom, height } = frame.getBoundingClientRect();
|
|
50
|
+
const travel = viewportHeight + height;
|
|
51
|
+
const visible = Math.max(0, Math.min(bottom, viewportHeight) - Math.max(top, 0));
|
|
52
|
+
return {
|
|
53
|
+
progress: travel > 0 ? clamp((viewportHeight - top) / travel) : 0,
|
|
54
|
+
visibleRatio: height > 0 ? clamp(visible / height) : 0
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** How far beyond the viewport a frame counts as near it, so it starts measuring ahead of time. */
|
|
58
|
+
const NEAR_VIEWPORT = "25% 0px";
|
|
59
|
+
/**
|
|
60
|
+
* Follows the frame's place in the page's viewport, measuring at most once per animation frame
|
|
61
|
+
* after a scroll or resize anywhere on the page, and reporting only changes. An
|
|
62
|
+
* IntersectionObserver limits this to while the frame is near the viewport: far frames aren't
|
|
63
|
+
* measured on scroll, and are measured once more as they leave, so they report where they went.
|
|
64
|
+
*/
|
|
65
|
+
function trackViewport(frame, page, report) {
|
|
66
|
+
let pending = 0;
|
|
67
|
+
let last = null;
|
|
68
|
+
const measure = () => {
|
|
69
|
+
pending = 0;
|
|
70
|
+
const next = viewportOf(frame, page.innerHeight);
|
|
71
|
+
if (last && last.progress === next.progress && last.visibleRatio === next.visibleRatio) return;
|
|
72
|
+
last = next;
|
|
73
|
+
report(next);
|
|
74
|
+
};
|
|
75
|
+
const schedule = () => {
|
|
76
|
+
if (pending) return;
|
|
77
|
+
pending = page.requestAnimationFrame(measure);
|
|
78
|
+
};
|
|
79
|
+
const listener = {
|
|
80
|
+
capture: true,
|
|
81
|
+
passive: true
|
|
82
|
+
};
|
|
83
|
+
let following = false;
|
|
84
|
+
const follow = (near) => {
|
|
85
|
+
if (near === following) return;
|
|
86
|
+
following = near;
|
|
87
|
+
if (near) {
|
|
88
|
+
page.addEventListener("scroll", schedule, listener);
|
|
89
|
+
page.addEventListener("resize", schedule, listener);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
page.removeEventListener("scroll", schedule, listener);
|
|
93
|
+
page.removeEventListener("resize", schedule, listener);
|
|
94
|
+
};
|
|
95
|
+
const intersection = "IntersectionObserver" in page ? new page.IntersectionObserver((entries) => {
|
|
96
|
+
const entry = entries.at(-1);
|
|
97
|
+
if (!entry) return;
|
|
98
|
+
follow(entry.isIntersecting);
|
|
99
|
+
schedule();
|
|
100
|
+
}, { rootMargin: NEAR_VIEWPORT }) : null;
|
|
101
|
+
if (intersection) intersection.observe(frame);
|
|
102
|
+
else follow(true);
|
|
103
|
+
schedule();
|
|
104
|
+
return {
|
|
105
|
+
schedule,
|
|
106
|
+
stop() {
|
|
107
|
+
intersection?.disconnect();
|
|
108
|
+
follow(false);
|
|
109
|
+
if (pending) page.cancelAnimationFrame(pending);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Connects an artifact frame to the `camox` runtime inside it, and owns the frame's message
|
|
115
|
+
* channel (see `artifactRuntime.ts` for the protocol).
|
|
116
|
+
*
|
|
117
|
+
* The block's code may run in another realm than the frame's parent (the studio renders its
|
|
118
|
+
* preview that way), so this only goes through the frame element's own document: never the
|
|
119
|
+
* global `window`, and never `event.source`, whose identity differs across realms.
|
|
120
|
+
*/
|
|
121
|
+
function connectArtifactHost(frame, initialState, options = {}) {
|
|
122
|
+
const page = frame.ownerDocument.defaultView;
|
|
123
|
+
if (!page) return {
|
|
124
|
+
update() {},
|
|
125
|
+
disconnect() {}
|
|
126
|
+
};
|
|
127
|
+
const channel = crypto.randomUUID();
|
|
128
|
+
let state = initialState;
|
|
129
|
+
let ready = false;
|
|
130
|
+
const post = (type, payload = {}) => {
|
|
131
|
+
frame.contentWindow?.postMessage({
|
|
132
|
+
...payload,
|
|
133
|
+
camox: type,
|
|
134
|
+
channel
|
|
135
|
+
}, "*");
|
|
136
|
+
};
|
|
137
|
+
const sendStudio = () => post("studio", { studio: state.studio });
|
|
138
|
+
const sendData = () => post("data", { data: state.data ?? {} });
|
|
139
|
+
let sentTheme = null;
|
|
140
|
+
const sendTheme = (force) => {
|
|
141
|
+
const tokens = readArtifactTheme(frame);
|
|
142
|
+
const serialized = JSON.stringify(tokens);
|
|
143
|
+
if (!force && serialized === sentTheme) return;
|
|
144
|
+
sentTheme = serialized;
|
|
145
|
+
post("theme", {
|
|
146
|
+
tokens,
|
|
147
|
+
colors: artifactThemeColors(tokens, page)
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
let viewport = null;
|
|
151
|
+
const observeViewport = (observe) => {
|
|
152
|
+
viewport?.stop();
|
|
153
|
+
viewport = observe ? trackViewport(frame, page, (next) => post("viewport", next)) : null;
|
|
154
|
+
};
|
|
155
|
+
const onMessage = (event) => {
|
|
156
|
+
const message = event.data;
|
|
157
|
+
if (!isRuntimeMessage(message)) return;
|
|
158
|
+
if (message.camox === "hello") {
|
|
159
|
+
post("connect");
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (message.channel !== channel) return;
|
|
163
|
+
if (message.camox === "ready") {
|
|
164
|
+
ready = true;
|
|
165
|
+
observeViewport(false);
|
|
166
|
+
sendStudio();
|
|
167
|
+
sendData();
|
|
168
|
+
sendTheme(true);
|
|
169
|
+
if (options.size === "content") post("measure");
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (message.camox === "height") {
|
|
173
|
+
const { height } = message;
|
|
174
|
+
if (options.size !== "content" || typeof height !== "number") return;
|
|
175
|
+
if (!Number.isFinite(height) || height < 0) return;
|
|
176
|
+
options.onHeight?.(height);
|
|
177
|
+
viewport?.schedule();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (message.camox === "observe-viewport") observeViewport(message.observe === true);
|
|
181
|
+
if (message.camox === "navigate" && typeof message.href === "string") navigateFromArtifact(message.href, page, options);
|
|
182
|
+
};
|
|
183
|
+
page.addEventListener("message", onMessage);
|
|
184
|
+
const stopObservingTheme = observeArtifactTheme(frame, () => {
|
|
185
|
+
if (ready) sendTheme(false);
|
|
186
|
+
});
|
|
187
|
+
post("connect");
|
|
188
|
+
return {
|
|
189
|
+
update(next) {
|
|
190
|
+
const previous = state;
|
|
191
|
+
state = next;
|
|
192
|
+
if (!ready) return;
|
|
193
|
+
if (!sameStudio(previous.studio, next.studio)) sendStudio();
|
|
194
|
+
if (JSON.stringify(previous.data) !== JSON.stringify(next.data)) sendData();
|
|
195
|
+
},
|
|
196
|
+
disconnect() {
|
|
197
|
+
page.removeEventListener("message", onMessage);
|
|
198
|
+
observeViewport(false);
|
|
199
|
+
stopObservingTheme();
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
//#endregion
|
|
205
|
+
export { connectArtifactHost };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/core/lib/artifactRuntime.ts
|
|
2
|
+
/**
|
|
3
|
+
* The `camox` runtime, injected at the top of every artifact's `srcDoc` so `window.camox` always
|
|
4
|
+
* exists before the artifact source runs.
|
|
5
|
+
*
|
|
6
|
+
* Protocol (every message is `{ camox: <type>, channel?, ...payload }`, posted with `"*"`):
|
|
7
|
+
* - runtime → page: `hello` when the runtime starts, so the page's hosts (re)connect their frames.
|
|
8
|
+
* - host → frame: `connect` with the host's private `channel`. The runtime adopts it and answers.
|
|
9
|
+
* - runtime → page: `ready` on that channel. Only the host that owns the channel listens to it,
|
|
10
|
+
* so hosts never need `event.source`, which can't be compared across realms.
|
|
11
|
+
* - host → frame: state messages on the channel, such as `studio`, and `theme` with the page's
|
|
12
|
+
* tokens at the frame's position and their sRGB `colors`, sent once ready and again when they
|
|
13
|
+
* change. The host converts the colors, so the runtime that every frame inlines stays small.
|
|
14
|
+
* - host → frame: `data` with the latest Artifact Data. The initial data is inlined in the
|
|
15
|
+
* `srcDoc` as a `<script type="application/json" data-camox-data>` after the runtime and the
|
|
16
|
+
* font links, so it is read lazily, on first access.
|
|
17
|
+
* - runtime → page: `observe-viewport` with `observe`, when the artifact's first `onViewport`
|
|
18
|
+
* subscription starts or its last one ends. While observed, the host sends `viewport` with
|
|
19
|
+
* `progress` and `visibleRatio` whenever they change.
|
|
20
|
+
* - host → frame: `measure`, for frames sized to their content. The runtime then reports the
|
|
21
|
+
* document's `height` whenever it changes.
|
|
22
|
+
* - runtime → page: `navigate` with an `href`. The host acts only with transient user activation.
|
|
23
|
+
*
|
|
24
|
+
* The theme part applies the tokens to the artifact's `:root` and keeps the body hidden until the
|
|
25
|
+
* first theme arrives, so the artifact never paints in the wrong colors, or until a short fallback
|
|
26
|
+
* timeout, so a page that never sends one can't hide it forever.
|
|
27
|
+
*
|
|
28
|
+
* Kept as plain JavaScript in a string: it runs in the artifact's document, not in the SDK's
|
|
29
|
+
* bundle, so it can't share code or build helpers with it. The SDK's build minifies it (see
|
|
30
|
+
* `plugins/minifyArtifactRuntime.ts`), so it must stay one template literal without
|
|
31
|
+
* interpolations or backslashes.
|
|
32
|
+
*/
|
|
33
|
+
const ARTIFACT_RUNTIME = "(()=>{\"use strict\";let e=window.parent,t=null,n=null,r,i,a=new Set,o=()=>{if(i!==void 0)return r;let e=document.querySelector(`script[data-camox-data]`);try{r=e?JSON.parse(e.textContent):{}}catch{r={}}return i=JSON.stringify(r),r},s=(()=>{let e=new Set,t=[],n=Object.freeze({tokens:Object.freeze({}),colors:Object.freeze({})}),r=document.createElement(`style`);r.textContent=`body { visibility: hidden !important; }`,document.head.append(r);let i=()=>r.remove();setTimeout(i,300);let a=e=>Number.isFinite(e)?Math.min(255,Math.max(0,Math.round(e))):0;return{get current(){return n},receive(r){let o={},s={},c=r.colors||{};for(let[e,t]of Object.entries(r.tokens||{})){if(!e.startsWith(`--`)||typeof t!=`string`)continue;o[e]=t;let n=Object.hasOwn(c,e)?c[e]:null;n&&typeof n==`object`&&(s[e]=Object.freeze({r:a(n.r),g:a(n.g),b:a(n.b)}))}let l=document.documentElement.style;for(let e of t)Object.hasOwn(o,e)||l.removeProperty(e);for(let[e,t]of Object.entries(o))l.setProperty(e,t);t=Object.keys(o),i(),n=Object.freeze({tokens:Object.freeze(o),colors:Object.freeze(s)});for(let t of[...e])t(n)},subscribe(t){return e.add(t),()=>{e.delete(t)}}}})(),c=new Set,l=null,u=null,d=null,f=()=>{let e=Math.ceil(document.documentElement.getBoundingClientRect().height);e!==d&&(d=e,p(`height`,{height:d}))},p=(n,r)=>{t&&e.postMessage({...r,camox:n,channel:t},`*`)},m=()=>p(`observe-viewport`,{observe:c.size>0}),h={studio(e){let t=e.studio;n=t?Object.freeze({editing:!!t.editing,canvas:!!t.canvas}):null},data(e){o();let t=JSON.stringify(e.data??{});if(t!==i){r=JSON.parse(t),i=t;for(let e of[...a])e(r)}},theme:s.receive,measure(){d=null,u||(u=new ResizeObserver(f),u.observe(document.documentElement)),f()},viewport(e){let{progress:t,visibleRatio:n}=e;if(typeof t==`number`&&typeof n==`number`){l=Object.freeze({progress:t,visibleRatio:n}),document.documentElement.style.setProperty(`--camox-progress`,String(t));for(let e of c)e(l)}}};window.addEventListener(`message`,e=>{let n=e.data;if(n&&typeof n.camox==`string`){if(n.camox===`connect`){if(typeof n.channel!=`string`||n.channel===t)return;t=n.channel,p(`ready`),c.size>0&&m()}else t&&n.channel===t&&Object.hasOwn(h,n.camox)&&h[n.camox](n)}});let g=Object.freeze({get studio(){return n},get data(){return o()},onData(e){return a.add(e),()=>{a.delete(e)}},get theme(){return s.current},onTheme:s.subscribe,navigate(e){p(`navigate`,{href:String(e)})},onViewport(e){if(typeof e!=`function`)throw TypeError(`camox.onViewport needs a callback`);let t=t=>e(t);return c.add(t),c.size===1?m():l&&queueMicrotask(()=>c.has(t)&&e(l)),()=>{c.delete(t)&&c.size===0&&m()}}});Object.defineProperty(window,\"camox\",{value:g,enumerable:!0}),e!==window&&e.postMessage({camox:`hello`},`*`)})();";
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { ARTIFACT_RUNTIME };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
//#region src/core/lib/artifactTheme.ts
|
|
2
|
+
function addCustomProperties(style, names) {
|
|
3
|
+
if (!style) return;
|
|
4
|
+
for (let index = 0; index < style.length; index++) {
|
|
5
|
+
const name = style.item(index);
|
|
6
|
+
if (name.startsWith("--")) names.add(name);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function addRuleCustomProperties(container, names) {
|
|
10
|
+
for (const rule of Array.from(container.cssRules)) {
|
|
11
|
+
addCustomProperties(rule.style, names);
|
|
12
|
+
if (rule.cssRules) addRuleCustomProperties(rule, names);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** The custom properties declared in the page's stylesheets and on the frame or its ancestors. */
|
|
16
|
+
function declaredCustomProperties(frame) {
|
|
17
|
+
const names = /* @__PURE__ */ new Set();
|
|
18
|
+
for (const sheet of Array.from(frame.ownerDocument.styleSheets)) try {
|
|
19
|
+
addRuleCustomProperties(sheet, names);
|
|
20
|
+
} catch {}
|
|
21
|
+
for (let element = frame; element; element = element.parentElement) addCustomProperties(element.style, names);
|
|
22
|
+
return names;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The theme tokens as resolved at the frame's position, so a `.dark` section, a `data-theme`
|
|
26
|
+
* attribute or a media query on the page all apply.
|
|
27
|
+
*/
|
|
28
|
+
function readArtifactTheme(frame) {
|
|
29
|
+
const page = frame.ownerDocument.defaultView;
|
|
30
|
+
if (!page) return {};
|
|
31
|
+
const style = page.getComputedStyle(frame);
|
|
32
|
+
const tokens = {};
|
|
33
|
+
for (const name of [...declaredCustomProperties(frame)].sort()) {
|
|
34
|
+
const value = style.getPropertyValue(name).trim();
|
|
35
|
+
if (value) tokens[name] = value;
|
|
36
|
+
}
|
|
37
|
+
return tokens;
|
|
38
|
+
}
|
|
39
|
+
function isThemeAttribute(name) {
|
|
40
|
+
return name === "class" || name === "style" || !!name?.startsWith("data-");
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Calls `onChange` when the `class`, `style` or `data-*` attributes of the frame or one of its
|
|
44
|
+
* ancestors change, as these may change the tokens at its position. Returns a disconnect.
|
|
45
|
+
*/
|
|
46
|
+
function observeArtifactTheme(frame, onChange) {
|
|
47
|
+
const page = frame.ownerDocument.defaultView;
|
|
48
|
+
if (!page) return () => {};
|
|
49
|
+
const observer = new page.MutationObserver((records) => {
|
|
50
|
+
if (records.some((record) => isThemeAttribute(record.attributeName))) onChange();
|
|
51
|
+
});
|
|
52
|
+
for (let element = frame; element; element = element.parentElement) observer.observe(element, { attributes: true });
|
|
53
|
+
return () => observer.disconnect();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
export { observeArtifactTheme, readArtifactTheme };
|