nudge-ui 0.2.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/README.md +66 -0
- package/bin/nudge-ui.mjs +7 -0
- package/dist/LICENSE +21 -0
- package/dist/client.mjs +261 -0
- package/dist/compiler/ast.d.ts +18 -0
- package/dist/compiler/ast.js +75 -0
- package/dist/compiler/componentContractTypes.d.ts +19 -0
- package/dist/compiler/componentContractTypes.js +1 -0
- package/dist/compiler/componentContracts.d.ts +2 -0
- package/dist/compiler/componentContracts.js +260 -0
- package/dist/compiler/componentInstrumentation.d.ts +32 -0
- package/dist/compiler/componentInstrumentation.js +140 -0
- package/dist/compiler/componentPolicyResolution.d.ts +71 -0
- package/dist/compiler/componentPolicyResolution.js +388 -0
- package/dist/compiler/index.d.ts +9 -0
- package/dist/compiler/index.js +9 -0
- package/dist/compiler/packageComponentContracts.d.ts +32 -0
- package/dist/compiler/packageComponentContracts.js +308 -0
- package/dist/compiler/reactComponentProtocols.d.ts +145 -0
- package/dist/compiler/reactComponentProtocols.js +47 -0
- package/dist/compiler/reactIdentity.d.ts +15 -0
- package/dist/compiler/reactIdentity.js +339 -0
- package/dist/compiler/sourcePaths.d.ts +12 -0
- package/dist/compiler/sourcePaths.js +27 -0
- package/dist/css/dialects/index.d.ts +62 -0
- package/dist/css/dialects/index.js +103 -0
- package/dist/css/dialects/tailwind.d.ts +46 -0
- package/dist/css/dialects/tailwind.js +119 -0
- package/dist/css/dialects/vanillaExtract.d.ts +20 -0
- package/dist/css/dialects/vanillaExtract.js +32 -0
- package/dist/css/index.d.ts +10 -0
- package/dist/css/index.js +10 -0
- package/dist/css/model/index.d.ts +190 -0
- package/dist/css/model/index.js +10 -0
- package/dist/css/token-inventory/index.d.ts +26 -0
- package/dist/css/token-inventory/index.js +24 -0
- package/dist/css/token-inventory/inventory.d.ts +8 -0
- package/dist/css/token-inventory/inventory.js +421 -0
- package/dist/css/token-inventory/parseStylesheet.d.ts +16 -0
- package/dist/css/token-inventory/parseStylesheet.js +155 -0
- package/dist/css/token-inventory/policy.d.ts +47 -0
- package/dist/css/token-inventory/policy.js +50 -0
- package/dist/css/token-inventory/types.d.ts +97 -0
- package/dist/css/token-inventory/types.js +1 -0
- package/dist/css/value-semantics/borderSemantics.d.ts +28 -0
- package/dist/css/value-semantics/borderSemantics.js +91 -0
- package/dist/css/value-semantics/boxSemantics.d.ts +37 -0
- package/dist/css/value-semantics/boxSemantics.js +71 -0
- package/dist/css/value-semantics/colorSemantics.d.ts +99 -0
- package/dist/css/value-semantics/colorSemantics.js +526 -0
- package/dist/css/value-semantics/cssSyntax.d.ts +19 -0
- package/dist/css/value-semantics/cssSyntax.js +111 -0
- package/dist/css/value-semantics/fontSemantics.d.ts +35 -0
- package/dist/css/value-semantics/fontSemantics.js +131 -0
- package/dist/css/value-semantics/index.d.ts +20 -0
- package/dist/css/value-semantics/index.js +15 -0
- package/dist/css/value-semantics/propertyPolicy.d.ts +118 -0
- package/dist/css/value-semantics/propertyPolicy.js +356 -0
- package/dist/css/value-semantics/stringMaps.d.ts +2 -0
- package/dist/css/value-semantics/stringMaps.js +1 -0
- package/dist/css/value-semantics/structuredValues.d.ts +64 -0
- package/dist/css/value-semantics/structuredValues.js +250 -0
- package/dist/css/value-semantics/tokenInterpretation.d.ts +90 -0
- package/dist/css/value-semantics/tokenInterpretation.js +193 -0
- package/dist/css/virtual-design-tokens.d.ts +17 -0
- package/dist/hosts/astro/astroRuntimeConfig.d.ts +12 -0
- package/dist/hosts/astro/astroRuntimeConfig.js +26 -0
- package/dist/hosts/astro/clientAsset.d.ts +12 -0
- package/dist/hosts/astro/clientAsset.js +51 -0
- package/dist/hosts/astro/clientTransport.d.ts +3 -0
- package/dist/hosts/astro/clientTransport.js +57 -0
- package/dist/hosts/astro/index.d.ts +3 -0
- package/dist/hosts/astro/index.js +2 -0
- package/dist/hosts/astro/integration.d.ts +35 -0
- package/dist/hosts/astro/integration.js +96 -0
- package/dist/hosts/astro/middleware.d.ts +13 -0
- package/dist/hosts/astro/middleware.js +22 -0
- package/dist/hosts/astro/projectContext.d.ts +11 -0
- package/dist/hosts/astro/projectContext.js +34 -0
- package/dist/hosts/astro/responseInstrumentation.d.ts +41 -0
- package/dist/hosts/astro/responseInstrumentation.js +80 -0
- package/dist/hosts/next/index.d.ts +4 -0
- package/dist/hosts/next/index.js +7 -0
- package/dist/hosts/next/loader.d.ts +66 -0
- package/dist/hosts/next/loader.js +346 -0
- package/dist/hosts/next/loaders/identity-loader.cjs +228257 -0
- package/dist/hosts/next/loaders/loader-plugin.cjs +228257 -0
- package/dist/hosts/next/manifest.d.ts +38 -0
- package/dist/hosts/next/manifest.js +30 -0
- package/dist/hosts/next/mount.d.ts +12 -0
- package/dist/hosts/next/mount.js +23 -0
- package/dist/hosts/next/repositoryScope.d.ts +20 -0
- package/dist/hosts/next/repositoryScope.js +33 -0
- package/dist/hosts/next/sidecar.d.ts +27 -0
- package/dist/hosts/next/sidecar.js +526 -0
- package/dist/hosts/next/wrapper.d.ts +67 -0
- package/dist/hosts/next/wrapper.js +310 -0
- package/dist/hosts/static/cli.d.ts +12 -0
- package/dist/hosts/static/cli.js +77 -0
- package/dist/hosts/static/html/bootstrap.d.ts +27 -0
- package/dist/hosts/static/html/bootstrap.js +93 -0
- package/dist/hosts/static/index.d.ts +4 -0
- package/dist/hosts/static/index.js +4 -0
- package/dist/hosts/static/manifest.d.ts +18 -0
- package/dist/hosts/static/manifest.js +51 -0
- package/dist/hosts/static/server.d.ts +72 -0
- package/dist/hosts/static/server.js +554 -0
- package/dist/hosts/vite/index.d.ts +20 -0
- package/dist/hosts/vite/index.js +48 -0
- package/dist/hosts/vite/react.d.ts +67 -0
- package/dist/hosts/vite/react.js +231 -0
- package/dist/hosts/vite/tokens/activeStylesheets.d.ts +28 -0
- package/dist/hosts/vite/tokens/activeStylesheets.js +70 -0
- package/dist/hosts/vite/tokens/fileMap.d.ts +2 -0
- package/dist/hosts/vite/tokens/fileMap.js +1 -0
- package/dist/hosts/vite/tokens/viteStylesheetArtifacts.d.ts +46 -0
- package/dist/hosts/vite/tokens/viteStylesheetArtifacts.js +104 -0
- package/dist/hosts/vite/virtual/design-tokens.d.ts +9 -0
- package/dist/hosts/vite/virtual/design-tokens.js +7 -0
- package/dist/hosts/vite/virtual-design-tokens.d.ts +1 -0
- package/dist/hosts/vite/vite.d.ts +62 -0
- package/dist/hosts/vite/vite.js +854 -0
- package/dist/html/dom.d.ts +13 -0
- package/dist/html/dom.js +46 -0
- package/dist/html/identity.d.ts +40 -0
- package/dist/html/identity.js +196 -0
- package/dist/html/insertions.d.ts +26 -0
- package/dist/html/insertions.js +59 -0
- package/dist/inspector/agent/McpConnectionDialog.d.ts +26 -0
- package/dist/inspector/agent/McpConnectionDialog.js +135 -0
- package/dist/inspector/agent/client.d.ts +98 -0
- package/dist/inspector/agent/client.js +728 -0
- package/dist/inspector/agent/connectionStatus.d.ts +13 -0
- package/dist/inspector/agent/connectionStatus.js +35 -0
- package/dist/inspector/agent/httpTransport.d.ts +21 -0
- package/dist/inspector/agent/httpTransport.js +347 -0
- package/dist/inspector/agent/protocol.d.ts +95 -0
- package/dist/inspector/agent/protocol.js +9 -0
- package/dist/inspector/agent/verification.d.ts +39 -0
- package/dist/inspector/agent/verification.js +207 -0
- package/dist/inspector/canvas/CanvasCard.d.ts +10 -0
- package/dist/inspector/canvas/CanvasCard.js +275 -0
- package/dist/inspector/canvas/CanvasElementOverlay.d.ts +2 -0
- package/dist/inspector/canvas/CanvasElementOverlay.js +301 -0
- package/dist/inspector/canvas/CanvasWorkspace.d.ts +2 -0
- package/dist/inspector/canvas/CanvasWorkspace.js +301 -0
- package/dist/inspector/canvas/LockedWorkspaceNotice.d.ts +6 -0
- package/dist/inspector/canvas/LockedWorkspaceNotice.js +17 -0
- package/dist/inspector/canvas/StaleChangeIndicator.d.ts +7 -0
- package/dist/inspector/canvas/StaleChangeIndicator.js +43 -0
- package/dist/inspector/canvas/agentPresentation.d.ts +87 -0
- package/dist/inspector/canvas/agentPresentation.js +421 -0
- package/dist/inspector/canvas/canvasGestures.d.ts +12 -0
- package/dist/inspector/canvas/canvasGestures.js +21 -0
- package/dist/inspector/canvas/canvasStore.d.ts +108 -0
- package/dist/inspector/canvas/canvasStore.js +448 -0
- package/dist/inspector/canvas/frameProtocol.d.ts +231 -0
- package/dist/inspector/canvas/frameProtocol.js +165 -0
- package/dist/inspector/canvas/linkEligibility.d.ts +8 -0
- package/dist/inspector/canvas/linkEligibility.js +68 -0
- package/dist/inspector/canvas/measurementProjection.d.ts +8 -0
- package/dist/inspector/canvas/measurementProjection.js +16 -0
- package/dist/inspector/canvas/normalizeUrl.d.ts +7 -0
- package/dist/inspector/canvas/normalizeUrl.js +27 -0
- package/dist/inspector/canvas/projection.d.ts +41 -0
- package/dist/inspector/canvas/projection.js +232 -0
- package/dist/inspector/canvas/rendererBootstrap.d.ts +4 -0
- package/dist/inspector/canvas/rendererBootstrap.js +410 -0
- package/dist/inspector/canvas/rendererCidIndex.d.ts +11 -0
- package/dist/inspector/canvas/rendererCidIndex.js +21 -0
- package/dist/inspector/canvas/rendererElementSelector.d.ts +2 -0
- package/dist/inspector/canvas/rendererElementSelector.js +378 -0
- package/dist/inspector/canvas/rendererSelectionProxy.d.ts +2 -0
- package/dist/inspector/canvas/rendererSelectionProxy.js +61 -0
- package/dist/inspector/canvas/rendererStylesheet.d.ts +16 -0
- package/dist/inspector/canvas/rendererStylesheet.js +221 -0
- package/dist/inspector/canvas/resizeHandleScale.d.ts +13 -0
- package/dist/inspector/canvas/resizeHandleScale.js +20 -0
- package/dist/inspector/canvas/roleDetection.d.ts +5 -0
- package/dist/inspector/canvas/roleDetection.js +21 -0
- package/dist/inspector/canvas/sessionStore.d.ts +71 -0
- package/dist/inspector/canvas/sessionStore.js +453 -0
- package/dist/inspector/canvas/staleChangeDetector.d.ts +11 -0
- package/dist/inspector/canvas/staleChangeDetector.js +217 -0
- package/dist/inspector/canvas/toolbarScale.d.ts +7 -0
- package/dist/inspector/canvas/toolbarScale.js +11 -0
- package/dist/inspector/canvas/workspaceLease.d.ts +26 -0
- package/dist/inspector/canvas/workspaceLease.js +214 -0
- package/dist/inspector/changes/changesLog.d.ts +46 -0
- package/dist/inspector/changes/changesLog.js +209 -0
- package/dist/inspector/changes/codecs.d.ts +98 -0
- package/dist/inspector/changes/codecs.js +389 -0
- package/dist/inspector/changes/editModel.d.ts +74 -0
- package/dist/inspector/changes/editModel.js +120 -0
- package/dist/inspector/changes/managedStyleProjection.d.ts +6 -0
- package/dist/inspector/changes/managedStyleProjection.js +109 -0
- package/dist/inspector/changes/model.d.ts +13 -0
- package/dist/inspector/changes/model.js +163 -0
- package/dist/inspector/changes/presentation.d.ts +14 -0
- package/dist/inspector/changes/presentation.js +81 -0
- package/dist/inspector/changes/previewDiagnostics.d.ts +39 -0
- package/dist/inspector/changes/previewDiagnostics.js +172 -0
- package/dist/inspector/changes/structuralTypes.d.ts +35 -0
- package/dist/inspector/changes/structuralTypes.js +1 -0
- package/dist/inspector/changes/types.d.ts +76 -0
- package/dist/inspector/changes/types.js +16 -0
- package/dist/inspector/changes/workspaceChanges.d.ts +43 -0
- package/dist/inspector/changes/workspaceChanges.js +239 -0
- package/dist/inspector/clientManifest.d.ts +24 -0
- package/dist/inspector/clientManifest.js +69 -0
- package/dist/inspector/componentSemantics/ComponentPropsSection.d.ts +5 -0
- package/dist/inspector/componentSemantics/ComponentPropsSection.js +44 -0
- package/dist/inspector/componentSemantics/adapterRegistry.d.ts +11 -0
- package/dist/inspector/componentSemantics/adapterRegistry.js +75 -0
- package/dist/inspector/componentSemantics/boundaries.d.ts +2 -0
- package/dist/inspector/componentSemantics/boundaries.js +10 -0
- package/dist/inspector/componentSemantics/changeAction.d.ts +3 -0
- package/dist/inspector/componentSemantics/changeAction.js +6 -0
- package/dist/inspector/componentSemantics/changeModel.d.ts +8 -0
- package/dist/inspector/componentSemantics/changeModel.js +60 -0
- package/dist/inspector/componentSemantics/index.d.ts +4 -0
- package/dist/inspector/componentSemantics/index.js +2 -0
- package/dist/inspector/componentSemantics/reactRuntime.d.ts +10 -0
- package/dist/inspector/componentSemantics/reactRuntime.js +186 -0
- package/dist/inspector/componentSemantics/runtimeBridge.d.ts +25 -0
- package/dist/inspector/componentSemantics/runtimeBridge.js +161 -0
- package/dist/inspector/componentSemantics/runtimeTypes.d.ts +2 -0
- package/dist/inspector/componentSemantics/runtimeTypes.js +1 -0
- package/dist/inspector/componentSemantics/textBinding.d.ts +69 -0
- package/dist/inspector/componentSemantics/textBinding.js +514 -0
- package/dist/inspector/componentSemantics/types.d.ts +96 -0
- package/dist/inspector/componentSemantics/types.js +5 -0
- package/dist/inspector/conformance/borderCases.d.ts +7 -0
- package/dist/inspector/conformance/borderCases.js +428 -0
- package/dist/inspector/conformance/colorCases.d.ts +8 -0
- package/dist/inspector/conformance/colorCases.js +470 -0
- package/dist/inspector/conformance/fixture.d.ts +68 -0
- package/dist/inspector/conformance/fixture.js +153 -0
- package/dist/inspector/conformance/projection.d.ts +2 -0
- package/dist/inspector/conformance/projection.js +3 -0
- package/dist/inspector/conformance/spacingCases.d.ts +6 -0
- package/dist/inspector/conformance/spacingCases.js +417 -0
- package/dist/inspector/conformance/typographyCases.d.ts +7 -0
- package/dist/inspector/conformance/typographyCases.js +174 -0
- package/dist/inspector/editScope.d.ts +4 -0
- package/dist/inspector/editScope.js +5 -0
- package/dist/inspector/index.d.ts +20 -0
- package/dist/inspector/index.js +236 -0
- package/dist/inspector/inline-text/inlineTextEditor.d.ts +74 -0
- package/dist/inspector/inline-text/inlineTextEditor.js +1207 -0
- package/dist/inspector/inline-text/inlineTextLifecycle.d.ts +2 -0
- package/dist/inspector/inline-text/inlineTextLifecycle.js +17 -0
- package/dist/inspector/inline-text/textChangeBoundary.d.ts +6 -0
- package/dist/inspector/inline-text/textChangeBoundary.js +1 -0
- package/dist/inspector/inspection/bridge.d.ts +72 -0
- package/dist/inspector/inspection/bridge.js +134 -0
- package/dist/inspector/inspection/browserCssInspection.d.ts +74 -0
- package/dist/inspector/inspection/browserCssInspection.js +317 -0
- package/dist/inspector/inspection/browserCssInspectionRegistry.d.ts +12 -0
- package/dist/inspector/inspection/browserCssInspectionRegistry.js +66 -0
- package/dist/inspector/inspection/selectionProperty.d.ts +32 -0
- package/dist/inspector/inspection/selectionProperty.js +33 -0
- package/dist/inspector/inspection/useBrowserCssInspection.d.ts +20 -0
- package/dist/inspector/inspection/useBrowserCssInspection.js +159 -0
- package/dist/inspector/overlay/DropGuideOverlay.d.ts +17 -0
- package/dist/inspector/overlay/DropGuideOverlay.js +17 -0
- package/dist/inspector/overlay/InspectorOverlay.d.ts +5 -0
- package/dist/inspector/overlay/InspectorOverlay.js +328 -0
- package/dist/inspector/overlay/MeasurementGuideOverlay.d.ts +19 -0
- package/dist/inspector/overlay/MeasurementGuideOverlay.js +40 -0
- package/dist/inspector/overlay/clickPolicy.d.ts +7 -0
- package/dist/inspector/overlay/clickPolicy.js +13 -0
- package/dist/inspector/overlay/dropGuide.d.ts +22 -0
- package/dist/inspector/overlay/dropGuide.js +48 -0
- package/dist/inspector/overlay/elementSelector.d.ts +1 -0
- package/dist/inspector/overlay/elementSelector.js +100 -0
- package/dist/inspector/overlay/frameThrottle.d.ts +10 -0
- package/dist/inspector/overlay/frameThrottle.js +38 -0
- package/dist/inspector/overlay/interactionStyles.d.ts +3 -0
- package/dist/inspector/overlay/interactionStyles.js +70 -0
- package/dist/inspector/overlay/measurementGeometry.d.ts +25 -0
- package/dist/inspector/overlay/measurementGeometry.js +104 -0
- package/dist/inspector/overlay/overlayGeometry.d.ts +40 -0
- package/dist/inspector/overlay/overlayGeometry.js +59 -0
- package/dist/inspector/overlay/selectedGeometry.d.ts +7 -0
- package/dist/inspector/overlay/selectedGeometry.js +51 -0
- package/dist/inspector/overlay/structuralGestures.d.ts +28 -0
- package/dist/inspector/overlay/structuralGestures.js +180 -0
- package/dist/inspector/projection/cssEscapes.d.ts +3 -0
- package/dist/inspector/projection/cssEscapes.js +20 -0
- package/dist/inspector/projection/managedStylesheet.d.ts +33 -0
- package/dist/inspector/projection/managedStylesheet.js +240 -0
- package/dist/inspector/projection/renderedInstance.d.ts +56 -0
- package/dist/inspector/projection/renderedInstance.js +306 -0
- package/dist/inspector/projection/structuralProjection.d.ts +93 -0
- package/dist/inspector/projection/structuralProjection.js +560 -0
- package/dist/inspector/projection/structuralProjectionBoundary.d.ts +5 -0
- package/dist/inspector/projection/structuralProjectionBoundary.js +65 -0
- package/dist/inspector/projection/textProjection.d.ts +53 -0
- package/dist/inspector/projection/textProjection.js +705 -0
- package/dist/inspector/projection/workspaceProjection.d.ts +43 -0
- package/dist/inspector/projection/workspaceProjection.js +58 -0
- package/dist/inspector/prompt/PromptSettingsDialog.d.ts +15 -0
- package/dist/inspector/prompt/PromptSettingsDialog.js +17 -0
- package/dist/inspector/prompt/clipboardHandoff.d.ts +34 -0
- package/dist/inspector/prompt/clipboardHandoff.js +212 -0
- package/dist/inspector/prompt/copyToClipboard.d.ts +1 -0
- package/dist/inspector/prompt/copyToClipboard.js +34 -0
- package/dist/inspector/prompt/detectFramework.d.ts +6 -0
- package/dist/inspector/prompt/detectFramework.js +4 -0
- package/dist/inspector/prompt/generatePrompt.d.ts +7 -0
- package/dist/inspector/prompt/generatePrompt.js +391 -0
- package/dist/inspector/prompt/promptSettings.d.ts +8 -0
- package/dist/inspector/prompt/promptSettings.js +28 -0
- package/dist/inspector/runtime/devFlag.d.ts +28 -0
- package/dist/inspector/runtime/devFlag.js +50 -0
- package/dist/inspector/runtime/documentStylesheetOrder.d.ts +19 -0
- package/dist/inspector/runtime/documentStylesheetOrder.js +89 -0
- package/dist/inspector/runtime/domRealm.d.ts +4 -0
- package/dist/inspector/runtime/domRealm.js +11 -0
- package/dist/inspector/runtime/runtimeConfig.d.ts +119 -0
- package/dist/inspector/runtime/runtimeConfig.js +276 -0
- package/dist/inspector/runtime/staticHtmlRuntimeIdentity.d.ts +32 -0
- package/dist/inspector/runtime/staticHtmlRuntimeIdentity.js +149 -0
- package/dist/inspector/runtime/useRuntimeConfig.d.ts +10 -0
- package/dist/inspector/runtime/useRuntimeConfig.js +13 -0
- package/dist/inspector/selection/editScope.d.ts +32 -0
- package/dist/inspector/selection/editScope.js +140 -0
- package/dist/inspector/selection/editTarget.d.ts +8 -0
- package/dist/inspector/selection/editTarget.js +11 -0
- package/dist/inspector/selection/hierarchy.d.ts +7 -0
- package/dist/inspector/selection/hierarchy.js +42 -0
- package/dist/inspector/selection/resolveSelection.d.ts +10 -0
- package/dist/inspector/selection/resolveSelection.js +60 -0
- package/dist/inspector/selection/selectionStore.d.ts +41 -0
- package/dist/inspector/selection/selectionStore.js +262 -0
- package/dist/inspector/selection/selectionTarget.d.ts +5 -0
- package/dist/inspector/selection/selectionTarget.js +50 -0
- package/dist/inspector/selection/sourceSite.d.ts +2 -0
- package/dist/inspector/selection/sourceSite.js +12 -0
- package/dist/inspector/selection/styleSelection.d.ts +22 -0
- package/dist/inspector/selection/styleSelection.js +104 -0
- package/dist/inspector/session/index.d.ts +3 -0
- package/dist/inspector/session/index.js +2 -0
- package/dist/inspector/session/lifecycle.d.ts +22 -0
- package/dist/inspector/session/lifecycle.js +63 -0
- package/dist/inspector/session/sessionContext.d.ts +21 -0
- package/dist/inspector/session/sessionContext.js +28 -0
- package/dist/inspector/session/sessionFactory.d.ts +29 -0
- package/dist/inspector/session/sessionFactory.js +73 -0
- package/dist/inspector/settings/SettingsDialog.d.ts +12 -0
- package/dist/inspector/settings/SettingsDialog.js +46 -0
- package/dist/inspector/shell/AppShell.d.ts +2 -0
- package/dist/inspector/shell/AppShell.js +9 -0
- package/dist/inspector/shell/ChangesLog.d.ts +6 -0
- package/dist/inspector/shell/ChangesLog.js +92 -0
- package/dist/inspector/shell/CopyPromptButton.d.ts +9 -0
- package/dist/inspector/shell/CopyPromptButton.js +159 -0
- package/dist/inspector/shell/DomNavigation.d.ts +8 -0
- package/dist/inspector/shell/DomNavigation.js +30 -0
- package/dist/inspector/shell/EmptyState.d.ts +2 -0
- package/dist/inspector/shell/EmptyState.js +15 -0
- package/dist/inspector/shell/InspectorShell.d.ts +11 -0
- package/dist/inspector/shell/InspectorShell.js +268 -0
- package/dist/inspector/shell/openStore.d.ts +6 -0
- package/dist/inspector/shell/openStore.js +29 -0
- package/dist/inspector/shell/panelLayout.d.ts +2 -0
- package/dist/inspector/shell/panelLayout.js +29 -0
- package/dist/inspector/shell/shortcuts.d.ts +3 -0
- package/dist/inspector/shell/shortcuts.js +25 -0
- package/dist/inspector/shell/stateValue.d.ts +3 -0
- package/dist/inspector/shell/stateValue.js +34 -0
- package/dist/inspector/shell/styleState.d.ts +7 -0
- package/dist/inspector/shell/styleState.js +13 -0
- package/dist/inspector/spacing/projection.d.ts +43 -0
- package/dist/inspector/spacing/projection.js +136 -0
- package/dist/inspector/styleEditors/AppearanceSection.d.ts +13 -0
- package/dist/inspector/styleEditors/AppearanceSection.js +6 -0
- package/dist/inspector/styleEditors/AspectRatioField.d.ts +17 -0
- package/dist/inspector/styleEditors/AspectRatioField.js +10 -0
- package/dist/inspector/styleEditors/BorderEditor.d.ts +13 -0
- package/dist/inspector/styleEditors/BorderEditor.js +295 -0
- package/dist/inspector/styleEditors/BorderRadiusEditor.d.ts +14 -0
- package/dist/inspector/styleEditors/BorderRadiusEditor.js +108 -0
- package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +13 -0
- package/dist/inspector/styleEditors/BoxShadowEditor.js +13 -0
- package/dist/inspector/styleEditors/ColorPicker.d.ts +15 -0
- package/dist/inspector/styleEditors/ColorPicker.js +73 -0
- package/dist/inspector/styleEditors/GapField.d.ts +17 -0
- package/dist/inspector/styleEditors/GapField.js +12 -0
- package/dist/inspector/styleEditors/GridChildSection.d.ts +14 -0
- package/dist/inspector/styleEditors/GridChildSection.js +91 -0
- package/dist/inspector/styleEditors/GridPicker.d.ts +13 -0
- package/dist/inspector/styleEditors/GridPicker.js +179 -0
- package/dist/inspector/styleEditors/GridSection.d.ts +17 -0
- package/dist/inspector/styleEditors/GridSection.js +27 -0
- package/dist/inspector/styleEditors/GridValueField.d.ts +17 -0
- package/dist/inspector/styleEditors/GridValueField.js +70 -0
- package/dist/inspector/styleEditors/InsetSection.d.ts +15 -0
- package/dist/inspector/styleEditors/InsetSection.js +15 -0
- package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +6 -0
- package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +6 -0
- package/dist/inspector/styleEditors/LayoutComboField.d.ts +18 -0
- package/dist/inspector/styleEditors/LayoutComboField.js +138 -0
- package/dist/inspector/styleEditors/LayoutDropdown.d.ts +14 -0
- package/dist/inspector/styleEditors/LayoutDropdown.js +34 -0
- package/dist/inspector/styleEditors/LayoutSection.d.ts +13 -0
- package/dist/inspector/styleEditors/LayoutSection.js +342 -0
- package/dist/inspector/styleEditors/OpacityEditor.d.ts +13 -0
- package/dist/inspector/styleEditors/OpacityEditor.js +34 -0
- package/dist/inspector/styleEditors/PositionInsets.d.ts +15 -0
- package/dist/inspector/styleEditors/PositionInsets.js +12 -0
- package/dist/inspector/styleEditors/SpacingBox.d.ts +29 -0
- package/dist/inspector/styleEditors/SpacingBox.js +189 -0
- package/dist/inspector/styleEditors/Typography.d.ts +13 -0
- package/dist/inspector/styleEditors/Typography.js +137 -0
- package/dist/inspector/styleEditors/completeCssValue.d.ts +8 -0
- package/dist/inspector/styleEditors/completeCssValue.js +34 -0
- package/dist/inspector/styleEditors/gridChildModel.d.ts +74 -0
- package/dist/inspector/styleEditors/gridChildModel.js +138 -0
- package/dist/inspector/styleEditors/layoutValue.d.ts +24 -0
- package/dist/inspector/styleEditors/layoutValue.js +103 -0
- package/dist/inspector/styleEditors/nudgeValue.d.ts +8 -0
- package/dist/inspector/styleEditors/nudgeValue.js +71 -0
- package/dist/inspector/styleEditors/rowLookup.d.ts +11 -0
- package/dist/inspector/styleEditors/rowLookup.js +13 -0
- package/dist/inspector/styleEditors/stringRecord.d.ts +4 -0
- package/dist/inspector/styleEditors/stringRecord.js +1 -0
- package/dist/inspector/styleEditors/valuePolicy.d.ts +20 -0
- package/dist/inspector/styleEditors/valuePolicy.js +82 -0
- package/dist/inspector/testing.d.ts +10 -0
- package/dist/inspector/testing.js +9 -0
- package/dist/inspector/tokens/TokenChip.d.ts +24 -0
- package/dist/inspector/tokens/TokenChip.js +23 -0
- package/dist/inspector/tokens/TokenDropdown.d.ts +13 -0
- package/dist/inspector/tokens/TokenDropdown.js +59 -0
- package/dist/inspector/tokens/TokenField.d.ts +68 -0
- package/dist/inspector/tokens/TokenField.js +485 -0
- package/dist/inspector/tokens/TokenLabel.d.ts +7 -0
- package/dist/inspector/tokens/TokenLabel.js +23 -0
- package/dist/inspector/tokens/TokensPanel.d.ts +5 -0
- package/dist/inspector/tokens/TokensPanel.js +47 -0
- package/dist/inspector/tokens/catalog.d.ts +51 -0
- package/dist/inspector/tokens/catalog.js +184 -0
- package/dist/inspector/tokens/editActions.d.ts +35 -0
- package/dist/inspector/tokens/editActions.js +164 -0
- package/dist/inspector/tokens/resolution/cascade.d.ts +14 -0
- package/dist/inspector/tokens/resolution/cascade.js +31 -0
- package/dist/inspector/tokens/resolution/cssomCollector.d.ts +43 -0
- package/dist/inspector/tokens/resolution/cssomCollector.js +528 -0
- package/dist/inspector/tokens/resolution/selectorSemantics.d.ts +12 -0
- package/dist/inspector/tokens/resolution/selectorSemantics.js +106 -0
- package/dist/inspector/tokens/resolution.d.ts +56 -0
- package/dist/inspector/tokens/resolution.js +1401 -0
- package/dist/inspector/tokens/tokenEdits.d.ts +3 -0
- package/dist/inspector/tokens/tokenEdits.js +22 -0
- package/dist/inspector/tokens/valueSemanticsAdapter.d.ts +6 -0
- package/dist/inspector/tokens/valueSemanticsAdapter.js +68 -0
- package/dist/inspector/ui/AtRuleContext.d.ts +18 -0
- package/dist/inspector/ui/AtRuleContext.js +54 -0
- package/dist/inspector/ui/Button.d.ts +9 -0
- package/dist/inspector/ui/Button.js +4 -0
- package/dist/inspector/ui/ColorSwatch.d.ts +7 -0
- package/dist/inspector/ui/ColorSwatch.js +6 -0
- package/dist/inspector/ui/ControlSurface.d.ts +14 -0
- package/dist/inspector/ui/ControlSurface.js +10 -0
- package/dist/inspector/ui/FieldRow.d.ts +14 -0
- package/dist/inspector/ui/FieldRow.js +15 -0
- package/dist/inspector/ui/IconButton.d.ts +14 -0
- package/dist/inspector/ui/IconButton.js +5 -0
- package/dist/inspector/ui/InspectorPopover.d.ts +17 -0
- package/dist/inspector/ui/InspectorPopover.js +13 -0
- package/dist/inspector/ui/PopoverListbox.d.ts +37 -0
- package/dist/inspector/ui/PopoverListbox.js +21 -0
- package/dist/inspector/ui/SegmentedControl.d.ts +24 -0
- package/dist/inspector/ui/SegmentedControl.js +16 -0
- package/dist/inspector/ui/Select.d.ts +25 -0
- package/dist/inspector/ui/Select.js +56 -0
- package/dist/inspector/ui/SideValuesField.d.ts +44 -0
- package/dist/inspector/ui/SideValuesField.js +76 -0
- package/dist/inspector/ui/StatusCallout.d.ts +9 -0
- package/dist/inspector/ui/StatusCallout.js +4 -0
- package/dist/inspector/ui/TextInput.d.ts +12 -0
- package/dist/inspector/ui/TextInput.js +5 -0
- package/dist/inspector/ui/ToggleButton.d.ts +11 -0
- package/dist/inspector/ui/ToggleButton.js +6 -0
- package/dist/inspector/ui/assets/grid.svg +14 -0
- package/dist/inspector/ui/css.d.ts +9 -0
- package/dist/inspector/ui/labels.d.ts +1 -0
- package/dist/inspector/ui/labels.js +7 -0
- package/dist/inspector/ui/styles.d.ts +1 -0
- package/dist/inspector/ui/styles.js +68 -0
- package/dist/inspector/virtual-modules.d.ts +7 -0
- package/dist/inspector/vite-env.d.ts +10 -0
- package/dist/internal/agent-protocol.d.ts +232 -0
- package/dist/internal/agent-protocol.js +237 -0
- package/dist/nudge-ui.mjs +15722 -0
- package/dist/project/files.d.ts +19 -0
- package/dist/project/files.js +226 -0
- package/dist/project/identity.d.ts +6 -0
- package/dist/project/identity.js +19 -0
- package/dist/project/pathPolicy.d.ts +8 -0
- package/dist/project/pathPolicy.js +12 -0
- package/dist/project/tokens.d.ts +36 -0
- package/dist/project/tokens.js +223 -0
- package/dist/transport/index.d.ts +8 -0
- package/dist/transport/index.js +8 -0
- package/dist/transport/routes.d.ts +13 -0
- package/dist/transport/routes.js +16 -0
- package/package.json +137 -0
|
@@ -0,0 +1,1207 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
import { appendChange } from "../changes/changesLog.js";
|
|
3
|
+
import { registerInlineTextClearHandler } from "./inlineTextLifecycle.js";
|
|
4
|
+
import { isNudgeUiDev } from "../runtime/devFlag.js";
|
|
5
|
+
import { createComponentPropChange, } from "../componentSemantics/changeModel.js";
|
|
6
|
+
import { resolveTextBinding, } from "../componentSemantics/textBinding.js";
|
|
7
|
+
import { captureTextProjectionTarget, EMPTY_TEXT_PROJECTION_ATTR, EMPTY_TEXT_PROJECTION_PATH_ATTR, getTextContentChangeById, resolveTextProjectionTarget, resolveTextProjectionTextNode, textProjectionSelector, } from "../projection/textProjection.js";
|
|
8
|
+
const listeners = new Set();
|
|
9
|
+
let activeSession = null;
|
|
10
|
+
let activeSessionDocument = null;
|
|
11
|
+
let pendingEditIntent = null;
|
|
12
|
+
// This remains armed if blur replaces the DOM between the second pointer-down
|
|
13
|
+
// and dblclick; only the next handoff attempt or explicit teardown consumes it.
|
|
14
|
+
let handoffPointerArmed = false;
|
|
15
|
+
let pendingReplayScheduled = false;
|
|
16
|
+
let sessionRevision = 0;
|
|
17
|
+
let inlineTextDiagnostics = [];
|
|
18
|
+
const diagnosticListeners = new Set();
|
|
19
|
+
function discardPendingInlineTextEdit(ownerDocument) {
|
|
20
|
+
if (!ownerDocument || pendingEditIntent?.ownerDocument === ownerDocument) {
|
|
21
|
+
pendingEditIntent = null;
|
|
22
|
+
}
|
|
23
|
+
if (!pendingEditIntent)
|
|
24
|
+
handoffPointerArmed = false;
|
|
25
|
+
}
|
|
26
|
+
function subscribe(listener) {
|
|
27
|
+
listeners.add(listener);
|
|
28
|
+
return () => listeners.delete(listener);
|
|
29
|
+
}
|
|
30
|
+
function notify() {
|
|
31
|
+
sessionRevision += 1;
|
|
32
|
+
listeners.forEach((listener) => listener());
|
|
33
|
+
}
|
|
34
|
+
function notifyDiagnostics() {
|
|
35
|
+
for (const listener of diagnosticListeners)
|
|
36
|
+
listener();
|
|
37
|
+
}
|
|
38
|
+
function recordDiagnostic(diagnostic) {
|
|
39
|
+
inlineTextDiagnostics = [...inlineTextDiagnostics.slice(-31), diagnostic];
|
|
40
|
+
notifyDiagnostics();
|
|
41
|
+
}
|
|
42
|
+
export function getInlineTextDiagnostics() {
|
|
43
|
+
return inlineTextDiagnostics;
|
|
44
|
+
}
|
|
45
|
+
export function getInlineTextDiagnostic() {
|
|
46
|
+
return inlineTextDiagnostics[inlineTextDiagnostics.length - 1] ?? null;
|
|
47
|
+
}
|
|
48
|
+
export function subscribeInlineTextDiagnostics(listener) {
|
|
49
|
+
diagnosticListeners.add(listener);
|
|
50
|
+
return () => diagnosticListeners.delete(listener);
|
|
51
|
+
}
|
|
52
|
+
export function getInlineTextSession() {
|
|
53
|
+
return activeSession;
|
|
54
|
+
}
|
|
55
|
+
export function useInlineTextSession() {
|
|
56
|
+
useSyncExternalStore(subscribe, () => sessionRevision, () => sessionRevision);
|
|
57
|
+
return activeSession;
|
|
58
|
+
}
|
|
59
|
+
export function isInlineTextEditingActive() {
|
|
60
|
+
return activeSession !== null;
|
|
61
|
+
}
|
|
62
|
+
export function cancelInlineTextEdit() {
|
|
63
|
+
discardPendingInlineTextEdit();
|
|
64
|
+
activeSession?.cancel("cancel");
|
|
65
|
+
}
|
|
66
|
+
/** End a session owned by a document/frame that is about to be disposed. */
|
|
67
|
+
export function disposeInlineTextEdit(reason = "frame-disposed", ownerDocument) {
|
|
68
|
+
if (!ownerDocument) {
|
|
69
|
+
discardPendingInlineTextEdit();
|
|
70
|
+
activeSession?.cancel(reason);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
discardPendingInlineTextEdit(ownerDocument);
|
|
74
|
+
if (activeSessionDocument === ownerDocument)
|
|
75
|
+
activeSession?.cancel(reason);
|
|
76
|
+
}
|
|
77
|
+
function ownerHTMLElement(element) {
|
|
78
|
+
const OwnerHTMLElement = element.ownerDocument.defaultView?.HTMLElement;
|
|
79
|
+
// SAFETY: The owning realm's HTMLElement constructor proves that this DOM
|
|
80
|
+
// element satisfies the HTMLElement interface, including iframe elements.
|
|
81
|
+
return OwnerHTMLElement && element instanceof OwnerHTMLElement
|
|
82
|
+
? element
|
|
83
|
+
: null;
|
|
84
|
+
}
|
|
85
|
+
function currentIntentTarget(intent) {
|
|
86
|
+
if (intent.target.isConnected)
|
|
87
|
+
return intent.target;
|
|
88
|
+
return intent.ownerDocument.elementFromPoint?.(intent.point.x, intent.point.y) ?? null;
|
|
89
|
+
}
|
|
90
|
+
function resolveInlineTextEditIntent(intent) {
|
|
91
|
+
const eventTarget = currentIntentTarget(intent);
|
|
92
|
+
if (!eventTarget)
|
|
93
|
+
return null;
|
|
94
|
+
const marker = eventTarget.closest(`[${EMPTY_TEXT_PROJECTION_ATTR}]`);
|
|
95
|
+
if (marker) {
|
|
96
|
+
const htmlMarker = ownerHTMLElement(marker);
|
|
97
|
+
if (htmlMarker)
|
|
98
|
+
return { kind: "empty-projection", marker: htmlMarker };
|
|
99
|
+
}
|
|
100
|
+
let current = eventTarget;
|
|
101
|
+
while (current) {
|
|
102
|
+
const htmlElement = ownerHTMLElement(current);
|
|
103
|
+
if (htmlElement?.hasAttribute("data-cid")) {
|
|
104
|
+
return { kind: "element", target: htmlElement };
|
|
105
|
+
}
|
|
106
|
+
current = current.parentElement;
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
function beginInlineTextEditIntent(intent) {
|
|
111
|
+
const resolved = resolveInlineTextEditIntent(intent);
|
|
112
|
+
if (!resolved)
|
|
113
|
+
return null;
|
|
114
|
+
return resolved.kind === "empty-projection"
|
|
115
|
+
? beginInlineTextEditFromEmptyProjection(resolved.marker)
|
|
116
|
+
: beginInlineTextEdit(resolved.target, intent.point);
|
|
117
|
+
}
|
|
118
|
+
function drainPendingInlineTextEdit() {
|
|
119
|
+
if (activeSession || !pendingEditIntent)
|
|
120
|
+
return null;
|
|
121
|
+
const intent = pendingEditIntent;
|
|
122
|
+
pendingEditIntent = null;
|
|
123
|
+
return beginInlineTextEditIntent(intent);
|
|
124
|
+
}
|
|
125
|
+
function schedulePendingInlineTextEdit() {
|
|
126
|
+
if (!pendingEditIntent || pendingReplayScheduled)
|
|
127
|
+
return;
|
|
128
|
+
pendingReplayScheduled = true;
|
|
129
|
+
queueMicrotask(() => {
|
|
130
|
+
pendingReplayScheduled = false;
|
|
131
|
+
drainPendingInlineTextEdit();
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Request inline editing from a document gesture. This is the interaction
|
|
136
|
+
* seam: it owns active-session handoff so gesture routers never discard a
|
|
137
|
+
* valid target switch merely because another draft is settling.
|
|
138
|
+
*/
|
|
139
|
+
function requestInlineTextEdit(target, point) {
|
|
140
|
+
if (activeSession) {
|
|
141
|
+
const hitTarget = target.ownerDocument.elementFromPoint?.(point.x, point.y);
|
|
142
|
+
if (activeSession.host.contains(target)
|
|
143
|
+
|| (hitTarget && activeSession.host.contains(hitTarget))) {
|
|
144
|
+
return "stop-propagation";
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const intent = {
|
|
148
|
+
ownerDocument: target.ownerDocument,
|
|
149
|
+
target,
|
|
150
|
+
point,
|
|
151
|
+
};
|
|
152
|
+
if (!resolveInlineTextEditIntent(intent))
|
|
153
|
+
return activeSession ? "suppress" : "pass-through";
|
|
154
|
+
if (!activeSession) {
|
|
155
|
+
const result = beginInlineTextEditIntent(intent);
|
|
156
|
+
return result && !("kind" in result) ? "suppress" : "pass-through";
|
|
157
|
+
}
|
|
158
|
+
pendingEditIntent = intent;
|
|
159
|
+
activeSession.commit("blur");
|
|
160
|
+
if (!activeSession)
|
|
161
|
+
drainPendingInlineTextEdit();
|
|
162
|
+
return "suppress";
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Handle one native interaction while keeping session-transition policy
|
|
166
|
+
* local. Pointer-down preserves double-click intent across the first click's
|
|
167
|
+
* blur commit, even when canonical projection replaces the target DOM.
|
|
168
|
+
*/
|
|
169
|
+
export function handleInlineTextEditIntent(intent) {
|
|
170
|
+
if (intent.kind === "double-click") {
|
|
171
|
+
return requestInlineTextEdit(intent.target, intent.point);
|
|
172
|
+
}
|
|
173
|
+
if (intent.clickCount <= 1) {
|
|
174
|
+
handoffPointerArmed = activeSession !== null;
|
|
175
|
+
return activeSession ? "stop-propagation" : "pass-through";
|
|
176
|
+
}
|
|
177
|
+
if (!activeSession && !handoffPointerArmed)
|
|
178
|
+
return "pass-through";
|
|
179
|
+
handoffPointerArmed = false;
|
|
180
|
+
return requestInlineTextEdit(intent.target, intent.point);
|
|
181
|
+
}
|
|
182
|
+
function isTextEditRejection(value) {
|
|
183
|
+
return "kind" in value && value.kind === "rejected";
|
|
184
|
+
}
|
|
185
|
+
function captureSelection(doc) {
|
|
186
|
+
const selection = doc.getSelection?.();
|
|
187
|
+
if (!selection)
|
|
188
|
+
return { ranges: [] };
|
|
189
|
+
const ranges = [];
|
|
190
|
+
for (let index = 0; index < selection.rangeCount; index += 1) {
|
|
191
|
+
ranges.push(selection.getRangeAt(index).cloneRange());
|
|
192
|
+
}
|
|
193
|
+
return { ranges };
|
|
194
|
+
}
|
|
195
|
+
function restoreSelection(doc, snapshot) {
|
|
196
|
+
const selection = doc.getSelection?.();
|
|
197
|
+
if (!selection)
|
|
198
|
+
return;
|
|
199
|
+
selection.removeAllRanges();
|
|
200
|
+
for (const range of snapshot.ranges) {
|
|
201
|
+
if (range.startContainer.isConnected && range.endContainer.isConnected) {
|
|
202
|
+
try {
|
|
203
|
+
selection.addRange(range);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// A framework rerender can invalidate a saved range between cleanup
|
|
207
|
+
// and restoration. Removing the transient selection is safer than
|
|
208
|
+
// retaining a range in a detached editing wrapper.
|
|
209
|
+
selection.removeAllRanges();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function hostIsOwned(candidate, host, ownership) {
|
|
215
|
+
return host.isConnected
|
|
216
|
+
&& candidate.element.isConnected
|
|
217
|
+
&& candidate.element.contains(host)
|
|
218
|
+
&& host.parentNode === ownership.parent
|
|
219
|
+
&& host.nextSibling === ownership.nextSibling;
|
|
220
|
+
}
|
|
221
|
+
function restoreDraft(candidate, host, text, ownership) {
|
|
222
|
+
if (!hostIsOwned(candidate, host, ownership))
|
|
223
|
+
return false;
|
|
224
|
+
const original = candidate.textNode;
|
|
225
|
+
// Normal typing replaces the original node inside the wrapper, leaving it
|
|
226
|
+
// detached. If reconciliation moved that node into another live tree,
|
|
227
|
+
// never move it back into the captured position.
|
|
228
|
+
if (original.isConnected && original.parentNode !== host)
|
|
229
|
+
return false;
|
|
230
|
+
original.nodeValue = text;
|
|
231
|
+
// Keep the original Text node and replace only the transient wrapper. This
|
|
232
|
+
// preserves every sibling/descendant of an icon-plus-label host.
|
|
233
|
+
host.replaceWith(original);
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
function selectAll(host) {
|
|
237
|
+
const doc = host.ownerDocument;
|
|
238
|
+
const selection = doc.getSelection?.();
|
|
239
|
+
if (!selection)
|
|
240
|
+
return;
|
|
241
|
+
const range = doc.createRange();
|
|
242
|
+
range.selectNodeContents(host);
|
|
243
|
+
selection.removeAllRanges();
|
|
244
|
+
selection.addRange(range);
|
|
245
|
+
}
|
|
246
|
+
function isNodeInsideHost(host, node) {
|
|
247
|
+
return node === host || host.contains(node);
|
|
248
|
+
}
|
|
249
|
+
function rangeInsideHost(host, range) {
|
|
250
|
+
if (!isNodeInsideHost(host, range.startContainer)
|
|
251
|
+
|| !isNodeInsideHost(host, range.endContainer))
|
|
252
|
+
return false;
|
|
253
|
+
// A host ancestor contains the common ancestor whenever both endpoints are
|
|
254
|
+
// inside it; StaticRange does not expose commonAncestorContainer.
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
function selectionInsideHost(host) {
|
|
258
|
+
const selection = host.ownerDocument.getSelection?.();
|
|
259
|
+
if (!selection || selection.rangeCount === 0)
|
|
260
|
+
return false;
|
|
261
|
+
for (let index = 0; index < selection.rangeCount; index += 1) {
|
|
262
|
+
if (!rangeInsideHost(host, selection.getRangeAt(index)))
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
const ALLOWED_INPUT_TYPES = new Set([
|
|
268
|
+
"insertText",
|
|
269
|
+
"insertReplacementText",
|
|
270
|
+
"insertCompositionText",
|
|
271
|
+
"insertFromComposition",
|
|
272
|
+
"insertFromPaste",
|
|
273
|
+
"deleteContentBackward",
|
|
274
|
+
"deleteContentForward",
|
|
275
|
+
"deleteByCut",
|
|
276
|
+
"deleteByDrag",
|
|
277
|
+
]);
|
|
278
|
+
function isParagraphInputType(inputType) {
|
|
279
|
+
return inputType === "insertParagraph" || inputType === "insertLineBreak";
|
|
280
|
+
}
|
|
281
|
+
function isAllowedInputType(inputType) {
|
|
282
|
+
return ALLOWED_INPUT_TYPES.has(inputType);
|
|
283
|
+
}
|
|
284
|
+
function plainTextFromPaste(event) {
|
|
285
|
+
try {
|
|
286
|
+
const value = event.clipboardData?.getData("text/plain");
|
|
287
|
+
return typeof value === "string" ? value : null;
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function hasParagraphBreak(value) {
|
|
294
|
+
return /[\r\n]/.test(value);
|
|
295
|
+
}
|
|
296
|
+
function replaceSelectionWithPlainText(host, value) {
|
|
297
|
+
if (hasParagraphBreak(value) || !selectionInsideHost(host))
|
|
298
|
+
return false;
|
|
299
|
+
const selection = host.ownerDocument.getSelection?.();
|
|
300
|
+
if (!selection || selection.rangeCount === 0)
|
|
301
|
+
return false;
|
|
302
|
+
const range = selection.getRangeAt(0);
|
|
303
|
+
range.deleteContents();
|
|
304
|
+
const node = host.ownerDocument.createTextNode(value);
|
|
305
|
+
range.insertNode(node);
|
|
306
|
+
range.setStartAfter(node);
|
|
307
|
+
range.collapse(true);
|
|
308
|
+
selection.removeAllRanges();
|
|
309
|
+
selection.addRange(range);
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
function flattenHostText(host) {
|
|
313
|
+
const text = host.textContent ?? "";
|
|
314
|
+
if (host.childNodes.length === 1 && host.firstChild?.nodeType === 3)
|
|
315
|
+
return text;
|
|
316
|
+
host.replaceChildren(host.ownerDocument.createTextNode(text));
|
|
317
|
+
return text;
|
|
318
|
+
}
|
|
319
|
+
function sourceForChoice(candidate, choice) {
|
|
320
|
+
if (choice?.renderedSource)
|
|
321
|
+
return choice.renderedSource;
|
|
322
|
+
if (candidate.renderedSource
|
|
323
|
+
&& (!choice || candidate.renderedSource.evidence?.callsiteId === choice.binding.target.callsiteId
|
|
324
|
+
&& candidate.renderedSource.evidence.property === choice.binding.property)) {
|
|
325
|
+
return candidate.renderedSource;
|
|
326
|
+
}
|
|
327
|
+
const parsed = /^(.*):(\d+):(\d+)$/.exec(candidate.element.getAttribute("data-src") ?? "");
|
|
328
|
+
const target = choice?.binding.target;
|
|
329
|
+
const authoredAs = choice?.authoredAs === "literal"
|
|
330
|
+
? "literal"
|
|
331
|
+
: choice?.authoredAs === "expression" || choice?.authoredAs === "spread"
|
|
332
|
+
? "expression"
|
|
333
|
+
: "unknown";
|
|
334
|
+
return {
|
|
335
|
+
file: target?.file ?? parsed?.[1] ?? candidate.element.getAttribute("data-src") ?? "",
|
|
336
|
+
line: target?.line ?? Number(parsed?.[2] ?? 0),
|
|
337
|
+
column: target?.column ?? Number(parsed?.[3] ?? 0),
|
|
338
|
+
component: target?.componentName ?? candidate.element.getAttribute("data-cid") ?? "Rendered text",
|
|
339
|
+
selector: candidate.binding.kind === "rendered-text"
|
|
340
|
+
? textProjectionSelector(candidate.binding.target) ?? ""
|
|
341
|
+
: "",
|
|
342
|
+
authoredAs,
|
|
343
|
+
evidence: choice ? {
|
|
344
|
+
callsiteId: choice.binding.target.callsiteId,
|
|
345
|
+
componentName: choice.binding.target.componentName,
|
|
346
|
+
property: choice.binding.property,
|
|
347
|
+
mountedCount: choice.mountedCount,
|
|
348
|
+
} : undefined,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
function componentEvidence(candidate, choice) {
|
|
352
|
+
const target = choice.renderedTarget
|
|
353
|
+
?? candidate.renderedTarget
|
|
354
|
+
?? captureTextProjectionTarget(candidate.element, candidate.before, candidate.textNode);
|
|
355
|
+
return {
|
|
356
|
+
occurrence: target?.occurrence ?? 0,
|
|
357
|
+
props: target?.props ?? candidate.element.getAttribute("data-cprops"),
|
|
358
|
+
ariaLabel: target?.ariaLabel ?? candidate.element.getAttribute("aria-label"),
|
|
359
|
+
beforeText: candidate.before,
|
|
360
|
+
mountedCount: choice.mountedCount,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
function textTargetFor(candidate, binding, choice) {
|
|
364
|
+
if (choice?.renderedTarget)
|
|
365
|
+
return choice.renderedTarget;
|
|
366
|
+
if (candidate.renderedTarget)
|
|
367
|
+
return candidate.renderedTarget;
|
|
368
|
+
if (binding.kind === "rendered-text")
|
|
369
|
+
return binding.target;
|
|
370
|
+
return captureTextProjectionTarget(candidate.element, candidate.before, candidate.textNode);
|
|
371
|
+
}
|
|
372
|
+
function resolveEmptyProjectionCandidate(marker) {
|
|
373
|
+
if (!marker.isConnected) {
|
|
374
|
+
return {
|
|
375
|
+
kind: "rejected",
|
|
376
|
+
reason: "no-binding",
|
|
377
|
+
message: "The empty rendered-text affordance is no longer connected.",
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
const changeId = marker.getAttribute(EMPTY_TEXT_PROJECTION_ATTR);
|
|
381
|
+
if (!changeId) {
|
|
382
|
+
return {
|
|
383
|
+
kind: "rejected",
|
|
384
|
+
reason: "no-binding",
|
|
385
|
+
message: "The empty rendered-text affordance has no canonical change.",
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
const change = getTextContentChangeById(changeId);
|
|
389
|
+
if (!change || change.after.length !== 0) {
|
|
390
|
+
return {
|
|
391
|
+
kind: "rejected",
|
|
392
|
+
reason: "no-binding",
|
|
393
|
+
message: "The empty rendered-text affordance is stale.",
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
if (marker.getAttribute(EMPTY_TEXT_PROJECTION_PATH_ATTR)
|
|
397
|
+
!== (change.target.textNodePath ? `path:${change.target.textNodePath.join(",")}` : "root")) {
|
|
398
|
+
return {
|
|
399
|
+
kind: "rejected",
|
|
400
|
+
reason: "no-binding",
|
|
401
|
+
message: "The empty rendered-text affordance no longer identifies its text node.",
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
const resolved = resolveTextProjectionTarget(marker.ownerDocument, change.target, "");
|
|
405
|
+
if (resolved.status !== "resolved" || !resolved.element.contains(marker)) {
|
|
406
|
+
return {
|
|
407
|
+
kind: "rejected",
|
|
408
|
+
reason: resolved.status === "ambiguous" ? "ambiguous-binding" : "no-binding",
|
|
409
|
+
message: "The empty rendered text no longer has a unique source projection.",
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
const textNode = resolveTextProjectionTextNode(resolved.element, change.target, "");
|
|
413
|
+
if (!textNode || textNode.nodeValue !== "") {
|
|
414
|
+
return {
|
|
415
|
+
kind: "rejected",
|
|
416
|
+
reason: "no-text",
|
|
417
|
+
message: "The empty rendered text is no longer available for editing.",
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
return {
|
|
421
|
+
binding: { kind: "rendered-text", target: change.target },
|
|
422
|
+
element: resolved.element,
|
|
423
|
+
textNode,
|
|
424
|
+
before: "",
|
|
425
|
+
scope: change.scope ?? "rendered-instance",
|
|
426
|
+
renderedTarget: change.target,
|
|
427
|
+
renderedSource: {
|
|
428
|
+
file: change.source.file,
|
|
429
|
+
line: change.source.line,
|
|
430
|
+
column: change.source.column,
|
|
431
|
+
component: change.source.component,
|
|
432
|
+
selector: change.selector,
|
|
433
|
+
authoredAs: change.authoredAs,
|
|
434
|
+
evidence: change.evidence,
|
|
435
|
+
},
|
|
436
|
+
emptyProjectionMarker: marker,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
function makeSession(candidate) {
|
|
440
|
+
const doc = candidate.element.ownerDocument;
|
|
441
|
+
const originalSelection = captureSelection(doc);
|
|
442
|
+
const previousActiveElement = doc.activeElement instanceof HTMLElement
|
|
443
|
+
? doc.activeElement
|
|
444
|
+
: null;
|
|
445
|
+
const originalParent = candidate.textNode.parentNode;
|
|
446
|
+
const originalNextSibling = candidate.textNode.nextSibling;
|
|
447
|
+
if (!originalParent) {
|
|
448
|
+
// `resolveTextBinding` only returns connected text nodes, but keep this
|
|
449
|
+
// boundary defensive if a framework mutates between resolution and wrap.
|
|
450
|
+
throw new Error("Inline text target lost its parent before editing began.");
|
|
451
|
+
}
|
|
452
|
+
const ownership = { parent: originalParent, nextSibling: originalNextSibling };
|
|
453
|
+
const capturedTarget = candidate.renderedTarget
|
|
454
|
+
?? captureTextProjectionTarget(candidate.element, candidate.before, candidate.textNode);
|
|
455
|
+
const host = doc.createElement("span");
|
|
456
|
+
host.setAttribute("data-inline-editor", "true");
|
|
457
|
+
host.setAttribute("contenteditable", "plaintext-only");
|
|
458
|
+
host.contentEditable = "plaintext-only";
|
|
459
|
+
candidate.textNode.replaceWith(host);
|
|
460
|
+
// An empty Text node is retained for exact restoration, but leaving it as
|
|
461
|
+
// the first child of a native contenteditable makes Chromium insert the
|
|
462
|
+
// first character beside it. The input handler then has to coalesce two
|
|
463
|
+
// text nodes and the browser resets the caret to the start, reversing the
|
|
464
|
+
// visible draft. Let the empty editor start childless; restoreDraft still
|
|
465
|
+
// puts the captured node back at the owned insertion point on exit.
|
|
466
|
+
if (candidate.before.length > 0)
|
|
467
|
+
host.append(candidate.textNode);
|
|
468
|
+
let finished = false;
|
|
469
|
+
let blurCommitHandle = null;
|
|
470
|
+
let compositionFinalizeHandle = null;
|
|
471
|
+
let composing = false;
|
|
472
|
+
let blurPending = false;
|
|
473
|
+
let lastSafeText = candidate.before;
|
|
474
|
+
let rejectedNextInput = null;
|
|
475
|
+
let observer = null;
|
|
476
|
+
let session;
|
|
477
|
+
let unregisterClearHandler = null;
|
|
478
|
+
const ownerWindow = doc.defaultView;
|
|
479
|
+
const history = ownerWindow?.history;
|
|
480
|
+
const originalPushState = history?.pushState;
|
|
481
|
+
const originalReplaceState = history?.replaceState;
|
|
482
|
+
let patchedPushState = null;
|
|
483
|
+
let patchedReplaceState = null;
|
|
484
|
+
let selectedChoice = candidate.bindingChoices?.length === 1
|
|
485
|
+
? candidate.bindingChoices[0]
|
|
486
|
+
: null;
|
|
487
|
+
let selectedScope = candidate.scope
|
|
488
|
+
?? (candidate.binding.kind === "rendered-text" ? "rendered-instance" : "source-site");
|
|
489
|
+
function currentBinding() {
|
|
490
|
+
if (!selectedChoice)
|
|
491
|
+
return candidate.binding;
|
|
492
|
+
if (selectedChoice.mountedCount > 1 && selectedChoice.authoredAs !== "literal") {
|
|
493
|
+
const target = selectedChoice.renderedTarget
|
|
494
|
+
?? candidate.renderedTarget
|
|
495
|
+
?? capturedTarget;
|
|
496
|
+
return target ? { kind: "rendered-text", target } : selectedChoice.binding;
|
|
497
|
+
}
|
|
498
|
+
return selectedChoice.binding;
|
|
499
|
+
}
|
|
500
|
+
function currentScopeChoices() {
|
|
501
|
+
if (selectedChoice) {
|
|
502
|
+
if (selectedChoice.mountedCount > 1 && selectedChoice.authoredAs === "literal") {
|
|
503
|
+
return ["rendered-instance", "source-site"];
|
|
504
|
+
}
|
|
505
|
+
return [];
|
|
506
|
+
}
|
|
507
|
+
return candidate.scopeChoices ?? [];
|
|
508
|
+
}
|
|
509
|
+
function choiceForCommit() {
|
|
510
|
+
const choice = selectedChoice ?? candidate.bindingChoices?.[0];
|
|
511
|
+
const target = candidate.editableTarget;
|
|
512
|
+
if (choice || !target || candidate.mountedCount === undefined)
|
|
513
|
+
return choice ?? null;
|
|
514
|
+
const property = candidate.binding.kind === "component-prop"
|
|
515
|
+
? candidate.binding.property
|
|
516
|
+
: "children";
|
|
517
|
+
return {
|
|
518
|
+
binding: candidate.binding.kind === "component-prop"
|
|
519
|
+
? candidate.binding
|
|
520
|
+
: {
|
|
521
|
+
kind: "component-prop",
|
|
522
|
+
property,
|
|
523
|
+
target: {
|
|
524
|
+
framework: target.framework,
|
|
525
|
+
componentId: target.contract.componentId,
|
|
526
|
+
callsiteId: target.meta.callsiteId,
|
|
527
|
+
componentName: target.meta.componentName,
|
|
528
|
+
file: target.meta.file,
|
|
529
|
+
line: target.meta.line,
|
|
530
|
+
column: target.meta.column,
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
editableTarget: target,
|
|
534
|
+
mountedCount: candidate.mountedCount,
|
|
535
|
+
authoredAs: target.meta.authoredProps[property] ?? "default",
|
|
536
|
+
renderedTarget: candidate.renderedTarget ?? null,
|
|
537
|
+
renderedSource: candidate.renderedSource,
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function prepareChange(after, binding, choice) {
|
|
541
|
+
if (binding.kind === "component-prop" && selectedScope === "source-site") {
|
|
542
|
+
const editableTarget = choice?.editableTarget ?? candidate.editableTarget;
|
|
543
|
+
const prop = editableTarget?.contract.props.find((item) => item.name === binding.property && item.control === "text");
|
|
544
|
+
if (!editableTarget || !prop)
|
|
545
|
+
return null;
|
|
546
|
+
return createComponentPropChange(editableTarget, prop, after, {
|
|
547
|
+
scope: "source-site",
|
|
548
|
+
evidence: choice && choice.mountedCount > 1
|
|
549
|
+
? componentEvidence(candidate, choice)
|
|
550
|
+
: undefined,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
const textTarget = textTargetFor(candidate, binding, choice);
|
|
554
|
+
const source = sourceForChoice(candidate, choice);
|
|
555
|
+
const renderedSource = source.selector || !textTarget
|
|
556
|
+
? source
|
|
557
|
+
: { ...source, selector: textProjectionSelector(textTarget) ?? "" };
|
|
558
|
+
if (!textTarget || !renderedSource.selector)
|
|
559
|
+
return null;
|
|
560
|
+
return {
|
|
561
|
+
kind: "text-content",
|
|
562
|
+
id: `text-${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`}`,
|
|
563
|
+
target: textTarget,
|
|
564
|
+
source: {
|
|
565
|
+
file: renderedSource.file,
|
|
566
|
+
line: renderedSource.line,
|
|
567
|
+
column: renderedSource.column,
|
|
568
|
+
component: renderedSource.component,
|
|
569
|
+
},
|
|
570
|
+
selector: renderedSource.selector,
|
|
571
|
+
before: candidate.before,
|
|
572
|
+
after,
|
|
573
|
+
authoredAs: renderedSource.authoredAs,
|
|
574
|
+
scope: selectedScope,
|
|
575
|
+
evidence: renderedSource.evidence,
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function restoreHostText(text) {
|
|
579
|
+
host.replaceChildren(doc.createTextNode(text));
|
|
580
|
+
lastSafeText = text;
|
|
581
|
+
}
|
|
582
|
+
function resumeDraft(text) {
|
|
583
|
+
const original = candidate.textNode;
|
|
584
|
+
if (original.parentNode !== ownership.parent
|
|
585
|
+
|| original.nextSibling !== ownership.nextSibling)
|
|
586
|
+
return false;
|
|
587
|
+
original.replaceWith(host);
|
|
588
|
+
restoreHostText(text);
|
|
589
|
+
try {
|
|
590
|
+
host.focus({ preventScroll: true });
|
|
591
|
+
}
|
|
592
|
+
catch {
|
|
593
|
+
host.focus();
|
|
594
|
+
}
|
|
595
|
+
selectAll(host);
|
|
596
|
+
return true;
|
|
597
|
+
}
|
|
598
|
+
function rejectInput(reason) {
|
|
599
|
+
recordDiagnostic({
|
|
600
|
+
kind: "inline-text",
|
|
601
|
+
status: "rejected",
|
|
602
|
+
reason,
|
|
603
|
+
before: candidate.before,
|
|
604
|
+
after: host.textContent ?? "",
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
function editorOwnsFocus() {
|
|
608
|
+
const active = doc.activeElement;
|
|
609
|
+
return active === host || (active instanceof Node && host.contains(active));
|
|
610
|
+
}
|
|
611
|
+
function cancelForReconciliation(discardedDraft) {
|
|
612
|
+
if (finished)
|
|
613
|
+
return;
|
|
614
|
+
const restoreFocus = editorOwnsFocus();
|
|
615
|
+
// A moved/reordered host has no safe insertion point. Remove only the
|
|
616
|
+
// temporary wrapper; never reinsert the original node into a new tree.
|
|
617
|
+
if (host.isConnected)
|
|
618
|
+
host.remove();
|
|
619
|
+
finish("app-reconciled", "cancelled", discardedDraft, restoreFocus);
|
|
620
|
+
}
|
|
621
|
+
function finish(reason, status, after, restoreFocus = false) {
|
|
622
|
+
if (finished)
|
|
623
|
+
return;
|
|
624
|
+
finished = true;
|
|
625
|
+
host.removeEventListener("keydown", onKeyDown);
|
|
626
|
+
host.removeEventListener("blur", onBlur);
|
|
627
|
+
host.removeEventListener("beforeinput", onBeforeInput);
|
|
628
|
+
host.removeEventListener("input", onInput);
|
|
629
|
+
host.removeEventListener("paste", onPaste);
|
|
630
|
+
host.removeEventListener("compositionstart", onCompositionStart);
|
|
631
|
+
host.removeEventListener("compositionend", onCompositionEnd);
|
|
632
|
+
host.removeEventListener("mousedown", suppressHostPointer);
|
|
633
|
+
host.removeEventListener("mouseup", suppressHostPointer);
|
|
634
|
+
host.removeEventListener("pointerdown", suppressHostPointer);
|
|
635
|
+
host.removeEventListener("pointerup", suppressHostPointer);
|
|
636
|
+
doc.removeEventListener("selectionchange", onSelectionChange);
|
|
637
|
+
doc.removeEventListener("click", suppressInteractiveAction, true);
|
|
638
|
+
doc.removeEventListener("mousedown", suppressInteractiveAction, true);
|
|
639
|
+
doc.removeEventListener("mouseup", suppressInteractiveAction, true);
|
|
640
|
+
doc.removeEventListener("pointerdown", suppressInteractiveAction, true);
|
|
641
|
+
doc.removeEventListener("pointerup", suppressInteractiveAction, true);
|
|
642
|
+
doc.removeEventListener("submit", suppressInteractiveAction, true);
|
|
643
|
+
ownerWindow?.removeEventListener("pagehide", onFrameDisposed);
|
|
644
|
+
ownerWindow?.removeEventListener("beforeunload", onFrameDisposed);
|
|
645
|
+
ownerWindow?.removeEventListener("unload", onFrameDisposed);
|
|
646
|
+
ownerWindow?.removeEventListener("popstate", onRouteDisposed);
|
|
647
|
+
ownerWindow?.removeEventListener("hashchange", onRouteDisposed);
|
|
648
|
+
if (history && originalPushState && history.pushState === patchedPushState) {
|
|
649
|
+
history.pushState = originalPushState;
|
|
650
|
+
}
|
|
651
|
+
if (history && originalReplaceState && history.replaceState === patchedReplaceState) {
|
|
652
|
+
history.replaceState = originalReplaceState;
|
|
653
|
+
}
|
|
654
|
+
observer?.disconnect();
|
|
655
|
+
observer = null;
|
|
656
|
+
if (blurCommitHandle !== null) {
|
|
657
|
+
clearTimeout(blurCommitHandle);
|
|
658
|
+
blurCommitHandle = null;
|
|
659
|
+
}
|
|
660
|
+
if (compositionFinalizeHandle !== null) {
|
|
661
|
+
clearTimeout(compositionFinalizeHandle);
|
|
662
|
+
compositionFinalizeHandle = null;
|
|
663
|
+
}
|
|
664
|
+
unregisterClearHandler?.();
|
|
665
|
+
unregisterClearHandler = null;
|
|
666
|
+
if (activeSession === session) {
|
|
667
|
+
activeSession = null;
|
|
668
|
+
activeSessionDocument = null;
|
|
669
|
+
notify();
|
|
670
|
+
}
|
|
671
|
+
if (restoreFocus) {
|
|
672
|
+
restoreSelection(doc, originalSelection);
|
|
673
|
+
if (previousActiveElement && previousActiveElement.isConnected) {
|
|
674
|
+
try {
|
|
675
|
+
previousActiveElement.focus({ preventScroll: true });
|
|
676
|
+
}
|
|
677
|
+
catch {
|
|
678
|
+
previousActiveElement.focus();
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
// A cancelled/unchanged re-entry keeps the same affordance. A committed
|
|
683
|
+
// non-empty value is synchronously reconciled by the text projection,
|
|
684
|
+
// which removes it after this session cleanup.
|
|
685
|
+
if (candidate.emptyProjectionMarker?.isConnected) {
|
|
686
|
+
candidate.emptyProjectionMarker.hidden = false;
|
|
687
|
+
}
|
|
688
|
+
recordDiagnostic({ kind: "inline-text", status, reason, before: candidate.before, after });
|
|
689
|
+
schedulePendingInlineTextEdit();
|
|
690
|
+
}
|
|
691
|
+
function onKeyDown(event) {
|
|
692
|
+
if (finished)
|
|
693
|
+
return;
|
|
694
|
+
if (event.isComposing || composing) {
|
|
695
|
+
// Enter/Escape belong to the IME until compositionend. Keeping the
|
|
696
|
+
// session alive makes the composition one canonical edit.
|
|
697
|
+
event.stopPropagation();
|
|
698
|
+
if (event.key === "Enter" || event.key === "Escape" || event.key === "Esc") {
|
|
699
|
+
event.preventDefault();
|
|
700
|
+
}
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
if (event.key === "Enter") {
|
|
704
|
+
if (blurCommitHandle !== null)
|
|
705
|
+
clearTimeout(blurCommitHandle);
|
|
706
|
+
blurCommitHandle = null;
|
|
707
|
+
event.preventDefault();
|
|
708
|
+
event.stopPropagation();
|
|
709
|
+
session.commit();
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
if (event.key === "Escape" || event.key === "Esc") {
|
|
713
|
+
if (blurCommitHandle !== null)
|
|
714
|
+
clearTimeout(blurCommitHandle);
|
|
715
|
+
blurCommitHandle = null;
|
|
716
|
+
event.preventDefault();
|
|
717
|
+
event.stopPropagation();
|
|
718
|
+
session.cancel();
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
// Keep inspector keyboard authority out of the draft while allowing the
|
|
722
|
+
// browser to handle ordinary typing and caret movement natively. The
|
|
723
|
+
// listener is scoped to this host so it does not intercept native input
|
|
724
|
+
// before the contenteditable target sees it.
|
|
725
|
+
event.stopPropagation();
|
|
726
|
+
}
|
|
727
|
+
function onBlur() {
|
|
728
|
+
if (finished)
|
|
729
|
+
return;
|
|
730
|
+
blurPending = true;
|
|
731
|
+
if (composing)
|
|
732
|
+
return;
|
|
733
|
+
// Deferring one macrotask lets Escape cancel a browser blur that occurs
|
|
734
|
+
// while a contenteditable host is handling the key event.
|
|
735
|
+
blurCommitHandle = setTimeout(() => {
|
|
736
|
+
blurCommitHandle = null;
|
|
737
|
+
if (!finished) {
|
|
738
|
+
blurPending = false;
|
|
739
|
+
session.commit("blur");
|
|
740
|
+
}
|
|
741
|
+
}, 0);
|
|
742
|
+
}
|
|
743
|
+
function onBeforeInput(event) {
|
|
744
|
+
if (finished)
|
|
745
|
+
return;
|
|
746
|
+
const rejectBeforeInput = (reason) => {
|
|
747
|
+
// Some browsers still deliver input after a non-cancelable beforeinput.
|
|
748
|
+
// Remember the safe plain draft so that onInput can undo that mutation.
|
|
749
|
+
if (!event.cancelable)
|
|
750
|
+
rejectedNextInput = reason;
|
|
751
|
+
if (event.cancelable)
|
|
752
|
+
event.preventDefault();
|
|
753
|
+
event.stopPropagation();
|
|
754
|
+
rejectInput(reason);
|
|
755
|
+
};
|
|
756
|
+
const ranges = typeof event.getTargetRanges === "function"
|
|
757
|
+
? event.getTargetRanges()
|
|
758
|
+
: [];
|
|
759
|
+
const inHost = ranges.length > 0
|
|
760
|
+
? ranges.every((range) => rangeInsideHost(host, range))
|
|
761
|
+
: selectionInsideHost(host);
|
|
762
|
+
if (!inHost) {
|
|
763
|
+
rejectBeforeInput("cross-host-range");
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
const inputType = event.inputType ?? "";
|
|
767
|
+
if (isParagraphInputType(inputType)) {
|
|
768
|
+
rejectBeforeInput("paragraph-input");
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
if (!inputType) {
|
|
772
|
+
rejectBeforeInput("invalid-input-type");
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
if (!isAllowedInputType(inputType)) {
|
|
776
|
+
rejectBeforeInput("rich-input");
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
rejectedNextInput = null;
|
|
780
|
+
lastSafeText = host.textContent ?? "";
|
|
781
|
+
event.stopPropagation();
|
|
782
|
+
}
|
|
783
|
+
function onInput(event) {
|
|
784
|
+
if (finished)
|
|
785
|
+
return;
|
|
786
|
+
if (rejectedNextInput !== null) {
|
|
787
|
+
const reason = rejectedNextInput;
|
|
788
|
+
rejectedNextInput = null;
|
|
789
|
+
event.preventDefault();
|
|
790
|
+
event.stopPropagation();
|
|
791
|
+
restoreHostText(lastSafeText);
|
|
792
|
+
rejectInput(reason);
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
if (hasParagraphBreak(host.textContent ?? "")) {
|
|
796
|
+
event.preventDefault();
|
|
797
|
+
restoreHostText(lastSafeText);
|
|
798
|
+
rejectInput("paragraph-input");
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
lastSafeText = flattenHostText(host);
|
|
802
|
+
event.stopPropagation();
|
|
803
|
+
}
|
|
804
|
+
function onPaste(event) {
|
|
805
|
+
if (finished)
|
|
806
|
+
return;
|
|
807
|
+
event.preventDefault();
|
|
808
|
+
event.stopPropagation();
|
|
809
|
+
const value = plainTextFromPaste(event);
|
|
810
|
+
if (value === null) {
|
|
811
|
+
const clipboard = ownerWindow?.navigator.clipboard;
|
|
812
|
+
const readText = clipboard?.readText;
|
|
813
|
+
if (typeof readText !== "function") {
|
|
814
|
+
rejectInput("clipboard-unavailable");
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
let clipboardResult;
|
|
818
|
+
try {
|
|
819
|
+
clipboardResult = readText.call(clipboard);
|
|
820
|
+
}
|
|
821
|
+
catch {
|
|
822
|
+
rejectInput("clipboard-unavailable");
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
void Promise.resolve(clipboardResult)
|
|
826
|
+
.then((clipboardText) => {
|
|
827
|
+
if (finished || activeSession !== session || typeof clipboardText !== "string")
|
|
828
|
+
return;
|
|
829
|
+
if (hasParagraphBreak(clipboardText)) {
|
|
830
|
+
rejectInput("multiline-paste");
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
if (!replaceSelectionWithPlainText(host, clipboardText)) {
|
|
834
|
+
rejectInput("invalid-selection");
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
lastSafeText = flattenHostText(host);
|
|
838
|
+
})
|
|
839
|
+
.catch(() => {
|
|
840
|
+
if (!finished && activeSession === session)
|
|
841
|
+
rejectInput("clipboard-unavailable");
|
|
842
|
+
});
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
if (hasParagraphBreak(value)) {
|
|
846
|
+
rejectInput("multiline-paste");
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
if (!replaceSelectionWithPlainText(host, value)) {
|
|
850
|
+
rejectInput("invalid-selection");
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
lastSafeText = flattenHostText(host);
|
|
854
|
+
}
|
|
855
|
+
function onCompositionStart(event) {
|
|
856
|
+
composing = true;
|
|
857
|
+
blurPending = false;
|
|
858
|
+
event.stopPropagation();
|
|
859
|
+
}
|
|
860
|
+
function onCompositionEnd(event) {
|
|
861
|
+
composing = false;
|
|
862
|
+
lastSafeText = flattenHostText(host);
|
|
863
|
+
event.stopPropagation();
|
|
864
|
+
if (blurPending && !finished) {
|
|
865
|
+
blurPending = false;
|
|
866
|
+
// Browsers may dispatch the final insertCompositionText/input after
|
|
867
|
+
// compositionend. Commit on the next macrotask so those final chars are
|
|
868
|
+
// part of this one canonical edit.
|
|
869
|
+
compositionFinalizeHandle = setTimeout(() => {
|
|
870
|
+
compositionFinalizeHandle = null;
|
|
871
|
+
if (!finished && !composing)
|
|
872
|
+
session.commit("blur");
|
|
873
|
+
}, 0);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
function onSelectionChange() {
|
|
877
|
+
if (finished)
|
|
878
|
+
return;
|
|
879
|
+
const selection = doc.getSelection?.();
|
|
880
|
+
if (!selection || selection.rangeCount === 0) {
|
|
881
|
+
// A panel click can clear the page selection before blur; let blur own
|
|
882
|
+
// the normal commit path unless the editing host still owns focus.
|
|
883
|
+
if (doc.activeElement === host)
|
|
884
|
+
endLifecycle("selection-removed");
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
if (selection && selection.rangeCount > 0 && selectionInsideHost(host))
|
|
888
|
+
return;
|
|
889
|
+
// A removed selection/host is a lifecycle end, not a text operation. The
|
|
890
|
+
// original node is restored only while its owning host is still connected.
|
|
891
|
+
if (!host.isConnected || !candidate.element.isConnected) {
|
|
892
|
+
endLifecycle(!host.isConnected ? "host-removed" : "selection-removed");
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
if (doc.activeElement === host)
|
|
896
|
+
endLifecycle("selection-removed");
|
|
897
|
+
}
|
|
898
|
+
function suppressInteractiveAction(event) {
|
|
899
|
+
if (finished)
|
|
900
|
+
return;
|
|
901
|
+
const target = event.target;
|
|
902
|
+
if (!(target instanceof Node))
|
|
903
|
+
return;
|
|
904
|
+
if (host.contains(target)) {
|
|
905
|
+
// All down/up events must reach the native editing host so caret and
|
|
906
|
+
// drag-selection behavior remains intact. The click itself is held so
|
|
907
|
+
// the app cannot activate the surrounding button/link.
|
|
908
|
+
if (event.type === "mousedown" || event.type === "mouseup"
|
|
909
|
+
|| event.type === "pointerdown" || event.type === "pointerup")
|
|
910
|
+
return;
|
|
911
|
+
event.preventDefault();
|
|
912
|
+
event.stopPropagation();
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
const inspectorRoot = doc.getElementById("nudge-ui-root");
|
|
916
|
+
if (inspectorRoot && (target === inspectorRoot || inspectorRoot.contains(target)))
|
|
917
|
+
return;
|
|
918
|
+
// At the document boundary, application actions are suspended for the
|
|
919
|
+
// duration of the draft. Inspector controls live in the scoped shadow
|
|
920
|
+
// host above and remain usable.
|
|
921
|
+
if (event.type !== "mousedown" && event.type !== "mouseup"
|
|
922
|
+
&& event.type !== "pointerdown" && event.type !== "pointerup") {
|
|
923
|
+
event.preventDefault();
|
|
924
|
+
}
|
|
925
|
+
event.stopPropagation();
|
|
926
|
+
}
|
|
927
|
+
function suppressHostPointer(event) {
|
|
928
|
+
// Keep the native default (focus transfer, caret placement, and drag
|
|
929
|
+
// selection) while preventing an application ancestor from observing the
|
|
930
|
+
// temporary host's pointer sequence.
|
|
931
|
+
event.stopPropagation();
|
|
932
|
+
}
|
|
933
|
+
function onFrameDisposed() {
|
|
934
|
+
endLifecycle("frame-disposed");
|
|
935
|
+
}
|
|
936
|
+
function onRouteDisposed() {
|
|
937
|
+
endLifecycle("route-disposed");
|
|
938
|
+
}
|
|
939
|
+
function patchRouteHistory() {
|
|
940
|
+
if (!history || !originalPushState || !originalReplaceState)
|
|
941
|
+
return;
|
|
942
|
+
try {
|
|
943
|
+
// SAFETY: the wrapper has the same History.pushState parameter/return contract;
|
|
944
|
+
// assignment is guarded by the captured native method and restored on finish.
|
|
945
|
+
patchedPushState = function (...args) {
|
|
946
|
+
if (!finished)
|
|
947
|
+
endLifecycle("route-disposed");
|
|
948
|
+
return originalPushState.apply(this, args);
|
|
949
|
+
};
|
|
950
|
+
// SAFETY: the wrapper has the same History.replaceState parameter/return contract;
|
|
951
|
+
// assignment is guarded by the captured native method and restored on finish.
|
|
952
|
+
patchedReplaceState = function (...args) {
|
|
953
|
+
if (!finished)
|
|
954
|
+
endLifecycle("route-disposed");
|
|
955
|
+
return originalReplaceState.apply(this, args);
|
|
956
|
+
};
|
|
957
|
+
history.pushState = patchedPushState;
|
|
958
|
+
history.replaceState = patchedReplaceState;
|
|
959
|
+
}
|
|
960
|
+
catch {
|
|
961
|
+
patchedPushState = null;
|
|
962
|
+
patchedReplaceState = null;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
function endLifecycle(reason, discardedDraft) {
|
|
966
|
+
if (finished)
|
|
967
|
+
return;
|
|
968
|
+
discardPendingInlineTextEdit(doc);
|
|
969
|
+
const restoreFocus = editorOwnsFocus();
|
|
970
|
+
if (hostIsOwned(candidate, host, ownership)) {
|
|
971
|
+
if (!restoreDraft(candidate, host, candidate.before, ownership)) {
|
|
972
|
+
cancelForReconciliation();
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
else if (host.isConnected) {
|
|
977
|
+
// A reconciliation can move the temporary host before removing the
|
|
978
|
+
// original root. It no longer has an owned insertion point, so remove
|
|
979
|
+
// the wrapper rather than leaking an editor into the new tree.
|
|
980
|
+
host.remove();
|
|
981
|
+
}
|
|
982
|
+
finish(reason, "cancelled", discardedDraft, restoreFocus);
|
|
983
|
+
}
|
|
984
|
+
session = {
|
|
985
|
+
get binding() {
|
|
986
|
+
return currentBinding();
|
|
987
|
+
},
|
|
988
|
+
get bindingChoices() {
|
|
989
|
+
return candidate.bindingChoices ?? [];
|
|
990
|
+
},
|
|
991
|
+
get selectedBindingIndex() {
|
|
992
|
+
if (!selectedChoice)
|
|
993
|
+
return null;
|
|
994
|
+
return candidate.bindingChoices?.indexOf(selectedChoice) ?? null;
|
|
995
|
+
},
|
|
996
|
+
get scope() {
|
|
997
|
+
return selectedScope;
|
|
998
|
+
},
|
|
999
|
+
get scopeChoices() {
|
|
1000
|
+
return currentScopeChoices();
|
|
1001
|
+
},
|
|
1002
|
+
host,
|
|
1003
|
+
before: candidate.before,
|
|
1004
|
+
chooseBinding(index) {
|
|
1005
|
+
if (finished)
|
|
1006
|
+
return;
|
|
1007
|
+
const choice = candidate.bindingChoices?.[index];
|
|
1008
|
+
if (!choice)
|
|
1009
|
+
return;
|
|
1010
|
+
selectedChoice = choice;
|
|
1011
|
+
selectedScope = choice.mountedCount > 1 && choice.authoredAs === "literal"
|
|
1012
|
+
? "rendered-instance"
|
|
1013
|
+
: choice.mountedCount > 1 ? "rendered-instance" : "source-site";
|
|
1014
|
+
notify();
|
|
1015
|
+
},
|
|
1016
|
+
chooseScope(scope) {
|
|
1017
|
+
if (finished || !currentScopeChoices().includes(scope))
|
|
1018
|
+
return;
|
|
1019
|
+
selectedScope = scope;
|
|
1020
|
+
notify();
|
|
1021
|
+
},
|
|
1022
|
+
commit(reason = "commit") {
|
|
1023
|
+
if (finished)
|
|
1024
|
+
return null;
|
|
1025
|
+
if (composing) {
|
|
1026
|
+
blurPending = true;
|
|
1027
|
+
return null;
|
|
1028
|
+
}
|
|
1029
|
+
if ((candidate.bindingChoices?.length ?? 0) > 1 && !selectedChoice)
|
|
1030
|
+
return null;
|
|
1031
|
+
if (!hostIsOwned(candidate, host, ownership)) {
|
|
1032
|
+
endLifecycle(!candidate.element.isConnected ? "app-reconciled" : "host-removed");
|
|
1033
|
+
return null;
|
|
1034
|
+
}
|
|
1035
|
+
const after = flattenHostText(host);
|
|
1036
|
+
if (hasParagraphBreak(after)) {
|
|
1037
|
+
rejectInput("paragraph-input");
|
|
1038
|
+
restoreHostText(lastSafeText);
|
|
1039
|
+
return null;
|
|
1040
|
+
}
|
|
1041
|
+
const binding = currentBinding();
|
|
1042
|
+
const choice = choiceForCommit();
|
|
1043
|
+
const unchanged = after === candidate.before;
|
|
1044
|
+
const change = unchanged ? null : prepareChange(after, binding, choice);
|
|
1045
|
+
if (!unchanged && !change) {
|
|
1046
|
+
endLifecycle("app-reconciled", after);
|
|
1047
|
+
return null;
|
|
1048
|
+
}
|
|
1049
|
+
// Always remove the temporary host before appending the canonical
|
|
1050
|
+
// change. The React Adapter must own the permanent preview.
|
|
1051
|
+
const restoreFocus = editorOwnsFocus();
|
|
1052
|
+
if (!restoreDraft(candidate, host, candidate.before, ownership)) {
|
|
1053
|
+
cancelForReconciliation();
|
|
1054
|
+
return null;
|
|
1055
|
+
}
|
|
1056
|
+
if (change?.kind === "text-content" && selectedScope === "rendered-instance") {
|
|
1057
|
+
// The second text value is alternate evidence for re-entry after a
|
|
1058
|
+
// previous projection. Validation happens after unwrapping because a
|
|
1059
|
+
// mounted draft can make another identical root look unique.
|
|
1060
|
+
const resolved = resolveTextProjectionTarget(doc, change.target, candidate.before);
|
|
1061
|
+
if (resolved.status !== "resolved") {
|
|
1062
|
+
if (!resumeDraft(after))
|
|
1063
|
+
cancelForReconciliation(after);
|
|
1064
|
+
return null;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
if (change) {
|
|
1068
|
+
try {
|
|
1069
|
+
if (appendChange(change) === "blocked") {
|
|
1070
|
+
if (!resumeDraft(after))
|
|
1071
|
+
cancelForReconciliation(after);
|
|
1072
|
+
return null;
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
catch (error) {
|
|
1076
|
+
if (!resumeDraft(after))
|
|
1077
|
+
cancelForReconciliation(after);
|
|
1078
|
+
throw error;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
finish(reason, "committed", after, restoreFocus);
|
|
1082
|
+
return change;
|
|
1083
|
+
},
|
|
1084
|
+
cancel(reason = "cancel") {
|
|
1085
|
+
if (finished)
|
|
1086
|
+
return;
|
|
1087
|
+
if (!hostIsOwned(candidate, host, ownership)) {
|
|
1088
|
+
endLifecycle("app-reconciled");
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
const restoreFocus = editorOwnsFocus();
|
|
1092
|
+
if (!restoreDraft(candidate, host, candidate.before, ownership)) {
|
|
1093
|
+
cancelForReconciliation();
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
finish(reason, "cancelled", candidate.before, restoreFocus);
|
|
1097
|
+
},
|
|
1098
|
+
};
|
|
1099
|
+
host.addEventListener("keydown", onKeyDown);
|
|
1100
|
+
host.addEventListener("blur", onBlur);
|
|
1101
|
+
host.addEventListener("beforeinput", onBeforeInput);
|
|
1102
|
+
host.addEventListener("input", onInput);
|
|
1103
|
+
host.addEventListener("paste", onPaste);
|
|
1104
|
+
host.addEventListener("compositionstart", onCompositionStart);
|
|
1105
|
+
host.addEventListener("compositionend", onCompositionEnd);
|
|
1106
|
+
host.addEventListener("mousedown", suppressHostPointer);
|
|
1107
|
+
host.addEventListener("mouseup", suppressHostPointer);
|
|
1108
|
+
host.addEventListener("pointerdown", suppressHostPointer);
|
|
1109
|
+
host.addEventListener("pointerup", suppressHostPointer);
|
|
1110
|
+
doc.addEventListener("selectionchange", onSelectionChange);
|
|
1111
|
+
for (const eventName of ["click", "mousedown", "mouseup", "pointerdown", "pointerup", "submit"]) {
|
|
1112
|
+
doc.addEventListener(eventName, suppressInteractiveAction, true);
|
|
1113
|
+
}
|
|
1114
|
+
patchRouteHistory();
|
|
1115
|
+
ownerWindow?.addEventListener("pagehide", onFrameDisposed);
|
|
1116
|
+
ownerWindow?.addEventListener("beforeunload", onFrameDisposed);
|
|
1117
|
+
ownerWindow?.addEventListener("unload", onFrameDisposed);
|
|
1118
|
+
ownerWindow?.addEventListener("popstate", onRouteDisposed);
|
|
1119
|
+
ownerWindow?.addEventListener("hashchange", onRouteDisposed);
|
|
1120
|
+
const OwnerMutationObserver = ownerWindow?.MutationObserver;
|
|
1121
|
+
if (OwnerMutationObserver && doc.documentElement) {
|
|
1122
|
+
observer = new OwnerMutationObserver(() => {
|
|
1123
|
+
if (finished)
|
|
1124
|
+
return;
|
|
1125
|
+
if (!hostIsOwned(candidate, host, ownership))
|
|
1126
|
+
endLifecycle("app-reconciled");
|
|
1127
|
+
});
|
|
1128
|
+
observer.observe(doc.documentElement, { childList: true, subtree: true });
|
|
1129
|
+
}
|
|
1130
|
+
activeSession = session;
|
|
1131
|
+
activeSessionDocument = doc;
|
|
1132
|
+
unregisterClearHandler = registerInlineTextClearHandler(cancelInlineTextEdit);
|
|
1133
|
+
notify();
|
|
1134
|
+
recordDiagnostic({ kind: "inline-text", status: "started", reason: "start", before: candidate.before });
|
|
1135
|
+
host.focus();
|
|
1136
|
+
selectAll(host);
|
|
1137
|
+
return session;
|
|
1138
|
+
}
|
|
1139
|
+
export const inlineTextEditor = {
|
|
1140
|
+
begin(element, point) {
|
|
1141
|
+
if (!isNudgeUiDev()) {
|
|
1142
|
+
return {
|
|
1143
|
+
kind: "rejected",
|
|
1144
|
+
reason: "no-binding",
|
|
1145
|
+
message: "Inline text editing is available only in development.",
|
|
1146
|
+
};
|
|
1147
|
+
}
|
|
1148
|
+
if (activeSession) {
|
|
1149
|
+
return {
|
|
1150
|
+
kind: "rejected",
|
|
1151
|
+
reason: "editing-active",
|
|
1152
|
+
message: "Finish the current inline text edit first.",
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
const candidate = resolveTextBinding(element, point);
|
|
1156
|
+
if (isTextEditRejection(candidate))
|
|
1157
|
+
return candidate;
|
|
1158
|
+
return makeSession(candidate);
|
|
1159
|
+
},
|
|
1160
|
+
};
|
|
1161
|
+
/** Re-enter an existing canonical rendered-text projection through its empty
|
|
1162
|
+
* inspector affordance. This never guesses a new DOM target or source node. */
|
|
1163
|
+
export function beginInlineTextEditFromEmptyProjection(marker) {
|
|
1164
|
+
if (!isNudgeUiDev()) {
|
|
1165
|
+
return {
|
|
1166
|
+
kind: "rejected",
|
|
1167
|
+
reason: "no-binding",
|
|
1168
|
+
message: "Inline text editing is available only in development.",
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
if (activeSession) {
|
|
1172
|
+
return {
|
|
1173
|
+
kind: "rejected",
|
|
1174
|
+
reason: "editing-active",
|
|
1175
|
+
message: "Finish the current inline text edit first.",
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
const candidate = resolveEmptyProjectionCandidate(marker);
|
|
1179
|
+
if (isTextEditRejection(candidate))
|
|
1180
|
+
return candidate;
|
|
1181
|
+
// Hide the affordance while its retained empty Text node is wrapped by the
|
|
1182
|
+
// native editor. The marker is restored on cancel and removed by projection
|
|
1183
|
+
// reconciliation on a successful non-empty commit.
|
|
1184
|
+
marker.hidden = true;
|
|
1185
|
+
try {
|
|
1186
|
+
return makeSession(candidate);
|
|
1187
|
+
}
|
|
1188
|
+
catch {
|
|
1189
|
+
marker.hidden = false;
|
|
1190
|
+
return {
|
|
1191
|
+
kind: "rejected",
|
|
1192
|
+
reason: "no-binding",
|
|
1193
|
+
message: "The empty rendered text could not be reopened safely.",
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
export function beginInlineTextEdit(element, point) {
|
|
1198
|
+
if (!isNudgeUiDev()) {
|
|
1199
|
+
return {
|
|
1200
|
+
kind: "rejected",
|
|
1201
|
+
reason: "no-binding",
|
|
1202
|
+
message: "Inline text editing is available only in development.",
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
return inlineTextEditor.begin(element, point);
|
|
1206
|
+
}
|
|
1207
|
+
export { resolveTextBinding } from "../componentSemantics/textBinding.js";
|