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,526 @@
|
|
|
1
|
+
import { extractVarCalls, splitTopLevel, splitTopLevelWhitespace, topLevelSlashIndex } from "./cssSyntax.js";
|
|
2
|
+
const MIX_PERCENTAGE_OR_TOKEN = /^(?:\d+\.?\d*|\.\d+)%$|^var\([\s\S]+\)$/i;
|
|
3
|
+
const COLOR_FUNCTIONS_WITH_ALPHA_SYNTAX = new Set(["rgb", "hsl", "hwb", "lab", "lch", "oklab", "oklch", "color"]);
|
|
4
|
+
const COLOR_FUNCTION_NAMES = new Set([
|
|
5
|
+
...COLOR_FUNCTIONS_WITH_ALPHA_SYNTAX,
|
|
6
|
+
"rgba",
|
|
7
|
+
"hsla",
|
|
8
|
+
]);
|
|
9
|
+
// CSS named colors are valid color values even though they do not have an
|
|
10
|
+
// explicit alpha syntax. Opacity edits represent them with color-mix(), while
|
|
11
|
+
// full opacity preserves the authored keyword.
|
|
12
|
+
const NAMED_COLOR_KEYWORDS = new Set([
|
|
13
|
+
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black",
|
|
14
|
+
"blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse",
|
|
15
|
+
"chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan",
|
|
16
|
+
"darkgoldenrod", "darkgray", "darkgrey", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
|
|
17
|
+
"darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue",
|
|
18
|
+
"darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue",
|
|
19
|
+
"dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia",
|
|
20
|
+
"gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "grey", "green", "greenyellow",
|
|
21
|
+
"honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush",
|
|
22
|
+
"lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow",
|
|
23
|
+
"lightgray", "lightgrey", "lightgreen", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue",
|
|
24
|
+
"lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen",
|
|
25
|
+
"magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
|
|
26
|
+
"mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred",
|
|
27
|
+
"midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive",
|
|
28
|
+
"olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise",
|
|
29
|
+
"palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple",
|
|
30
|
+
"rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen",
|
|
31
|
+
"seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow",
|
|
32
|
+
"springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat",
|
|
33
|
+
"white", "whitesmoke", "yellow", "yellowgreen",
|
|
34
|
+
]);
|
|
35
|
+
const CSS_NUMBER = /^[+-]?(?:(?:\d+\.?\d*)|(?:\.\d+))(?:e[+-]?\d+)?$/i;
|
|
36
|
+
function formatOpacityPercent(value) {
|
|
37
|
+
return `${String(Number(value.toFixed(4)))}%`;
|
|
38
|
+
}
|
|
39
|
+
function parseOpacityPercent(value, clamp = true) {
|
|
40
|
+
const trimmed = value.trim();
|
|
41
|
+
if (!trimmed)
|
|
42
|
+
return null;
|
|
43
|
+
const isPercent = trimmed.endsWith("%");
|
|
44
|
+
const numericText = isPercent ? trimmed.slice(0, -1).trim() : trimmed;
|
|
45
|
+
if (!CSS_NUMBER.test(numericText))
|
|
46
|
+
return null;
|
|
47
|
+
const numeric = Number(numericText);
|
|
48
|
+
if (!Number.isFinite(numeric))
|
|
49
|
+
return null;
|
|
50
|
+
const percent = isPercent ? numeric : numeric * 100;
|
|
51
|
+
return clamp ? Math.max(0, Math.min(100, percent)) : percent;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Normalizes an authored opacity to a clamped percent string. Accepts `%`
|
|
55
|
+
* and `0..1` forms; returns null when the input is not a parseable opacity.
|
|
56
|
+
*/
|
|
57
|
+
export function normalizeOpacityPercent(value) {
|
|
58
|
+
const percent = parseOpacityPercent(value);
|
|
59
|
+
return percent === null ? null : formatOpacityPercent(percent);
|
|
60
|
+
}
|
|
61
|
+
function parseColorMixItem(value) {
|
|
62
|
+
const parts = splitTopLevelWhitespace(value.trim());
|
|
63
|
+
if (parts.length > 1 && MIX_PERCENTAGE_OR_TOKEN.test(parts.at(-1))) {
|
|
64
|
+
return { color: parts.slice(0, -1).join(" "), percentage: parts.at(-1) };
|
|
65
|
+
}
|
|
66
|
+
if (parts.length > 1 && MIX_PERCENTAGE_OR_TOKEN.test(parts[0])) {
|
|
67
|
+
return { color: parts.slice(1).join(" "), percentage: parts[0] };
|
|
68
|
+
}
|
|
69
|
+
return { color: value.trim(), percentage: null };
|
|
70
|
+
}
|
|
71
|
+
function isExactVarFunction(value) {
|
|
72
|
+
if (!/^var\(/i.test(value))
|
|
73
|
+
return false;
|
|
74
|
+
let depth = 0;
|
|
75
|
+
let quote = null;
|
|
76
|
+
for (let index = 0; index < value.length; index++) {
|
|
77
|
+
const char = value[index];
|
|
78
|
+
if (quote) {
|
|
79
|
+
if (char === quote && value[index - 1] !== "\\")
|
|
80
|
+
quote = null;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (char === '"' || char === "'")
|
|
84
|
+
quote = char;
|
|
85
|
+
else if (char === "(")
|
|
86
|
+
depth++;
|
|
87
|
+
else if (char === ")") {
|
|
88
|
+
depth--;
|
|
89
|
+
if (depth === 0)
|
|
90
|
+
return index === value.length - 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
function resolveOpacityPercentage(authoredValue, ctx, clamp = true) {
|
|
96
|
+
const trimmed = authoredValue.trim();
|
|
97
|
+
const exactVar = isExactVarFunction(trimmed);
|
|
98
|
+
const tokenResult = exactVar ? ctx.resolveTokenReference?.(trimmed) ?? null : null;
|
|
99
|
+
const localName = exactVar ? extractVarCalls(trimmed)[0]?.name : undefined;
|
|
100
|
+
const localValue = localName ? ctx.localAliases?.get(localName) : undefined;
|
|
101
|
+
const fallback = exactVar ? extractVarCalls(trimmed)[0]?.fallback : undefined;
|
|
102
|
+
const resolved = localValue
|
|
103
|
+
?? (tokenResult?.resolvedValue && !/^var\(/i.test(tokenResult.resolvedValue)
|
|
104
|
+
? tokenResult.resolvedValue
|
|
105
|
+
: fallback ?? trimmed);
|
|
106
|
+
const percent = parseOpacityPercent(resolved, clamp);
|
|
107
|
+
if (percent === null)
|
|
108
|
+
return null;
|
|
109
|
+
const token = tokenResult?.tokens.find((candidate) => candidate.name === tokenResult.tokenName)
|
|
110
|
+
?? tokenResult?.tokens[0];
|
|
111
|
+
return {
|
|
112
|
+
percent,
|
|
113
|
+
component: {
|
|
114
|
+
value: formatOpacityPercent(percent),
|
|
115
|
+
authoredValue: trimmed,
|
|
116
|
+
tokenName: tokenResult?.tokenName ?? null,
|
|
117
|
+
token,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function resolveOpacityComponent(authoredValue, ctx) {
|
|
122
|
+
return resolveOpacityPercentage(authoredValue, ctx)?.component ?? null;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Derives the alpha component of a `color-mix(...)` whose second argument
|
|
126
|
+
* reconciles a color against `transparent`. The component is the color item's
|
|
127
|
+
* percentage, or the 100−p mirror of the transparent item's percentage when
|
|
128
|
+
* only that one is authored.
|
|
129
|
+
*/
|
|
130
|
+
function resolveColorMixOpacity(value, ctx) {
|
|
131
|
+
const open = value.indexOf("(");
|
|
132
|
+
const close = value.lastIndexOf(")");
|
|
133
|
+
if (open < 0 || close <= open)
|
|
134
|
+
return undefined;
|
|
135
|
+
const parts = splitTopLevel(value.slice(open + 1, close), ",");
|
|
136
|
+
if (parts.length !== 3 || !/^\s*in\s+/i.test(parts[0]))
|
|
137
|
+
return undefined;
|
|
138
|
+
const items = parts.slice(1).map(parseColorMixItem);
|
|
139
|
+
const transparentIndex = items.findIndex((item) => item.color.toLowerCase() === "transparent");
|
|
140
|
+
if (transparentIndex < 0 || items.filter((item) => item.color.toLowerCase() === "transparent").length !== 1)
|
|
141
|
+
return undefined;
|
|
142
|
+
const colorIndex = transparentIndex === 0 ? 1 : 0;
|
|
143
|
+
const colorItem = items[colorIndex];
|
|
144
|
+
const transparentItem = items[transparentIndex];
|
|
145
|
+
const colorPercentage = colorItem.percentage
|
|
146
|
+
? resolveOpacityPercentage(colorItem.percentage, ctx, false)
|
|
147
|
+
: null;
|
|
148
|
+
const transparentPercentage = transparentItem.percentage
|
|
149
|
+
? resolveOpacityPercentage(transparentItem.percentage, ctx, false)
|
|
150
|
+
: null;
|
|
151
|
+
if ((colorItem.percentage && !colorPercentage) || (transparentItem.percentage && !transparentPercentage))
|
|
152
|
+
return undefined;
|
|
153
|
+
let colorWeight = colorPercentage?.percent;
|
|
154
|
+
let transparentWeight = transparentPercentage?.percent;
|
|
155
|
+
if (colorWeight === undefined && transparentWeight === undefined) {
|
|
156
|
+
colorWeight = 50;
|
|
157
|
+
transparentWeight = 50;
|
|
158
|
+
}
|
|
159
|
+
else if (colorWeight === undefined) {
|
|
160
|
+
if (transparentWeight < 0 || transparentWeight > 100)
|
|
161
|
+
return undefined;
|
|
162
|
+
colorWeight = 100 - transparentWeight;
|
|
163
|
+
}
|
|
164
|
+
else if (transparentWeight === undefined) {
|
|
165
|
+
if (colorWeight < 0 || colorWeight > 100)
|
|
166
|
+
return undefined;
|
|
167
|
+
transparentWeight = 100 - colorWeight;
|
|
168
|
+
}
|
|
169
|
+
const resolvedColorWeight = colorWeight;
|
|
170
|
+
const resolvedTransparentWeight = transparentWeight;
|
|
171
|
+
if (resolvedColorWeight === undefined || resolvedTransparentWeight === undefined)
|
|
172
|
+
return undefined;
|
|
173
|
+
if (resolvedColorWeight < 0 || resolvedTransparentWeight < 0)
|
|
174
|
+
return undefined;
|
|
175
|
+
const total = resolvedColorWeight + resolvedTransparentWeight;
|
|
176
|
+
if (total <= 0)
|
|
177
|
+
return undefined;
|
|
178
|
+
const effectivePercent = total < 100 ? resolvedColorWeight : (resolvedColorWeight / total) * 100;
|
|
179
|
+
const attribution = colorPercentage?.component ?? transparentPercentage?.component;
|
|
180
|
+
return {
|
|
181
|
+
value: formatOpacityPercent(effectivePercent),
|
|
182
|
+
authoredValue: attribution?.authoredValue ?? "50%",
|
|
183
|
+
tokenName: attribution?.tokenName ?? null,
|
|
184
|
+
token: attribution?.token,
|
|
185
|
+
source: "color-mix",
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Interprets the alpha component of one authored color value. Returns a
|
|
190
|
+
* `ColorOpacity` when the value carries a recognized alpha channel (hex,
|
|
191
|
+
* rgb/hsl, or color-mix against transparent), and undefined otherwise.
|
|
192
|
+
*/
|
|
193
|
+
export function interpretColorOpacity(value, ctx) {
|
|
194
|
+
const trimmed = value.trim();
|
|
195
|
+
const hex = /^#([\da-f]{4}|[\da-f]{8})$/i.exec(trimmed);
|
|
196
|
+
if (hex) {
|
|
197
|
+
const raw = hex[1];
|
|
198
|
+
const alpha = raw.length === 4 ? raw.slice(-1) : raw.slice(-2);
|
|
199
|
+
const max = raw.length === 4 ? 15 : 255;
|
|
200
|
+
return {
|
|
201
|
+
value: formatOpacityPercent((Number.parseInt(alpha, 16) / max) * 100),
|
|
202
|
+
authoredValue: alpha,
|
|
203
|
+
source: "hex",
|
|
204
|
+
tokenName: null,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
const colorFunction = /^(rgba?|hsla?)\(([\s\S]*)\)$/i.exec(trimmed);
|
|
208
|
+
if (colorFunction) {
|
|
209
|
+
const body = colorFunction[2];
|
|
210
|
+
const commaParts = splitTopLevel(body, ",");
|
|
211
|
+
const alpha = commaParts.length >= 4
|
|
212
|
+
? commaParts[3]
|
|
213
|
+
: (() => {
|
|
214
|
+
const slash = topLevelSlashIndex(body);
|
|
215
|
+
return slash >= 0 ? body.slice(slash + 1).trim() : null;
|
|
216
|
+
})();
|
|
217
|
+
if (alpha) {
|
|
218
|
+
const component = resolveOpacityComponent(alpha, ctx);
|
|
219
|
+
if (component) {
|
|
220
|
+
return { ...component, source: colorFunction[1].toLowerCase().startsWith("rgb") ? "rgb" : "hsl" };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (/^color-mix\(/i.test(trimmed))
|
|
225
|
+
return resolveColorMixOpacity(trimmed, ctx);
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
/** Returns whether a color value carries its own alpha channel. */
|
|
229
|
+
export function colorValueHasEmbeddedAlpha(value) {
|
|
230
|
+
const trimmed = value.trim();
|
|
231
|
+
if (/^transparent$/i.test(trimmed))
|
|
232
|
+
return true;
|
|
233
|
+
if (/^#(?:[\da-f]{4}|[\da-f]{8})$/i.test(trimmed))
|
|
234
|
+
return true;
|
|
235
|
+
const colorFunction = /^([a-z-]+)\(([\s\S]*)\)$/i.exec(trimmed);
|
|
236
|
+
if (!colorFunction)
|
|
237
|
+
return false;
|
|
238
|
+
const name = colorFunction[1].toLowerCase();
|
|
239
|
+
const body = colorFunction[2];
|
|
240
|
+
if (name === "rgba" || name === "hsla")
|
|
241
|
+
return true;
|
|
242
|
+
if (COLOR_FUNCTIONS_WITH_ALPHA_SYNTAX.has(name)) {
|
|
243
|
+
if (topLevelSlashIndex(body) >= 0)
|
|
244
|
+
return true;
|
|
245
|
+
if ((name === "rgb" || name === "hsl") && splitTopLevel(body, ",").length >= 4)
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
if (name !== "color-mix")
|
|
249
|
+
return false;
|
|
250
|
+
const parts = splitTopLevel(body, ",");
|
|
251
|
+
return parts.length === 3 && parts.slice(1).some((part) => {
|
|
252
|
+
const item = parseColorMixItem(part);
|
|
253
|
+
return item.color.toLowerCase() === "transparent" || colorValueHasEmbeddedAlpha(item.color);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
/** Interprets UI-relevant color shape through the value-semantics seam. */
|
|
257
|
+
export function interpretColorValue(value, ctx) {
|
|
258
|
+
const trimmed = value.trim();
|
|
259
|
+
return {
|
|
260
|
+
opacity: interpretColorOpacity(trimmed, ctx),
|
|
261
|
+
facts: {
|
|
262
|
+
hasEmbeddedAlpha: colorValueHasEmbeddedAlpha(trimmed),
|
|
263
|
+
isExpression: /^color-mix\(/i.test(trimmed),
|
|
264
|
+
opacityEditable: applyColorOpacity(trimmed, "50%").ok,
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function replaceFunctionOpacity(value, opacity) {
|
|
269
|
+
const open = value.indexOf("(");
|
|
270
|
+
const close = value.lastIndexOf(")");
|
|
271
|
+
if (open < 0 || close <= open)
|
|
272
|
+
return null;
|
|
273
|
+
const body = value.slice(open + 1, close);
|
|
274
|
+
const commaParts = splitTopLevel(body, ",");
|
|
275
|
+
if (commaParts.length >= 4) {
|
|
276
|
+
return `${value.slice(0, open + 1)}${commaParts.slice(0, 3).map((part) => part.trim()).join(", ")}, ${opacity}${value.slice(close)}`;
|
|
277
|
+
}
|
|
278
|
+
const slash = topLevelSlashIndex(body);
|
|
279
|
+
if (slash < 0)
|
|
280
|
+
return null;
|
|
281
|
+
return `${value.slice(0, open + 1)}${body.slice(0, slash).trim()} / ${opacity}${value.slice(close)}`;
|
|
282
|
+
}
|
|
283
|
+
function isOpaqueRgbOrHslFunction(value) {
|
|
284
|
+
const match = /^(?:rgba?|hsla?)\(([\s\S]*)\)$/i.exec(value);
|
|
285
|
+
if (!match)
|
|
286
|
+
return false;
|
|
287
|
+
const body = match[1];
|
|
288
|
+
if (topLevelSlashIndex(body) >= 0)
|
|
289
|
+
return false;
|
|
290
|
+
const commaParts = splitTopLevel(body, ",");
|
|
291
|
+
return commaParts.length === 3
|
|
292
|
+
|| (commaParts.length === 1 && splitTopLevelWhitespace(body).length === 3);
|
|
293
|
+
}
|
|
294
|
+
function replaceColorMixItemPercentage(item, opacity) {
|
|
295
|
+
const parts = splitTopLevelWhitespace(item.trim());
|
|
296
|
+
if (parts.length > 1 && MIX_PERCENTAGE_OR_TOKEN.test(parts.at(-1))) {
|
|
297
|
+
return [...parts.slice(0, -1), opacity].join(" ");
|
|
298
|
+
}
|
|
299
|
+
if (parts.length > 1 && MIX_PERCENTAGE_OR_TOKEN.test(parts[0])) {
|
|
300
|
+
return [opacity, ...parts.slice(1)].join(" ");
|
|
301
|
+
}
|
|
302
|
+
return `${item.trim()} ${opacity}`;
|
|
303
|
+
}
|
|
304
|
+
function replaceColorMixOpacity(value, opacity) {
|
|
305
|
+
const open = value.indexOf("(");
|
|
306
|
+
const close = value.lastIndexOf(")");
|
|
307
|
+
if (open < 0 || close <= open)
|
|
308
|
+
return null;
|
|
309
|
+
const parts = splitTopLevel(value.slice(open + 1, close), ",");
|
|
310
|
+
if (parts.length !== 3 || !/^\s*in\s+/i.test(parts[0]))
|
|
311
|
+
return null;
|
|
312
|
+
const items = parts.slice(1).map(parseColorMixItem);
|
|
313
|
+
const transparentIndex = items.findIndex((item) => item.color.toLowerCase() === "transparent");
|
|
314
|
+
if (transparentIndex < 0 || items.filter((item) => item.color.toLowerCase() === "transparent").length !== 1)
|
|
315
|
+
return null;
|
|
316
|
+
const colorIndex = transparentIndex === 0 ? 1 : 0;
|
|
317
|
+
const updated = [...parts];
|
|
318
|
+
const colorItem = items[colorIndex];
|
|
319
|
+
const transparentItem = items[transparentIndex];
|
|
320
|
+
if (colorItem.percentage && transparentItem.percentage) {
|
|
321
|
+
const percent = parseOpacityPercent(opacity);
|
|
322
|
+
if (percent === null)
|
|
323
|
+
return null;
|
|
324
|
+
updated[colorIndex + 1] = replaceColorMixItemPercentage(parts[colorIndex + 1], formatOpacityPercent(percent));
|
|
325
|
+
updated[transparentIndex + 1] = replaceColorMixItemPercentage(parts[transparentIndex + 1], formatOpacityPercent(100 - percent));
|
|
326
|
+
}
|
|
327
|
+
else if (colorItem.percentage) {
|
|
328
|
+
updated[colorIndex + 1] = replaceColorMixItemPercentage(parts[colorIndex + 1], opacity);
|
|
329
|
+
}
|
|
330
|
+
else if (transparentItem.percentage) {
|
|
331
|
+
const percent = parseOpacityPercent(opacity);
|
|
332
|
+
if (percent === null)
|
|
333
|
+
return null;
|
|
334
|
+
updated[transparentIndex + 1] = replaceColorMixItemPercentage(parts[transparentIndex + 1], formatOpacityPercent(100 - percent));
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
updated[colorIndex + 1] = `${parts[colorIndex + 1].trim()} ${opacity}`;
|
|
338
|
+
}
|
|
339
|
+
return `${value.slice(0, open + 1)}${updated.join(", ")}${value.slice(close)}`;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Rewrites the alpha of a supported color expression to a normalized opacity
|
|
343
|
+
* percent. Hex alpha channels are rewritten digit-for-digit, rgb/hsl slash or
|
|
344
|
+
* comma alpha is replaced, `color-mix(... transparent)` reconciles its
|
|
345
|
+
* percentage (or its 100−p mirror), and a bare `var()` wraps into
|
|
346
|
+
* `color-mix(in srgb, var(...) <pct>, transparent)` — unwrapping back to the
|
|
347
|
+
* plain `var()` when the opacity reaches 100%. Unsupported value shapes and
|
|
348
|
+
* unparseable opacities return an explicit `ok: false`.
|
|
349
|
+
*/
|
|
350
|
+
export function applyColorOpacity(value, opacity) {
|
|
351
|
+
const normalized = normalizeOpacityPercent(opacity);
|
|
352
|
+
if (normalized === null)
|
|
353
|
+
return { ok: false, reason: "invalid-opacity" };
|
|
354
|
+
const trimmed = value.trim();
|
|
355
|
+
if (/^var\(\s*--[\w-]+(?:\s*,[\s\S]*)?\s*\)$/i.test(trimmed)) {
|
|
356
|
+
return normalized === "100%"
|
|
357
|
+
? { ok: true, value: trimmed }
|
|
358
|
+
: { ok: true, value: `color-mix(in srgb, ${trimmed} ${normalized}, transparent)` };
|
|
359
|
+
}
|
|
360
|
+
const hex = /^#([\da-f]{4}|[\da-f]{8})$/i.exec(trimmed);
|
|
361
|
+
if (hex) {
|
|
362
|
+
const raw = hex[1];
|
|
363
|
+
const max = raw.length === 4 ? 15 : 255;
|
|
364
|
+
const digits = raw.length === 4 ? 1 : 2;
|
|
365
|
+
const alpha = Math.round((parseOpacityPercent(normalized) / 100) * max).toString(16).padStart(digits, "0");
|
|
366
|
+
return { ok: true, value: `${trimmed.slice(0, -digits)}${alpha}` };
|
|
367
|
+
}
|
|
368
|
+
if (/^#(?:[\da-f]{3}|[\da-f]{6})$/i.test(trimmed)) {
|
|
369
|
+
return normalized === "100%"
|
|
370
|
+
? { ok: true, value: trimmed }
|
|
371
|
+
: { ok: true, value: `color-mix(in srgb, ${trimmed} ${normalized}, transparent)` };
|
|
372
|
+
}
|
|
373
|
+
const functionName = /^(\w[\w-]*)\(/i.exec(trimmed)?.[1]?.toLowerCase();
|
|
374
|
+
if (functionName && COLOR_FUNCTION_NAMES.has(functionName)) {
|
|
375
|
+
const open = trimmed.indexOf("(");
|
|
376
|
+
if (open < 0 || !trimmed.endsWith(")") || !trimmed.slice(open + 1, -1).trim()) {
|
|
377
|
+
return { ok: false, reason: "unsupported" };
|
|
378
|
+
}
|
|
379
|
+
const next = replaceFunctionOpacity(trimmed, normalized);
|
|
380
|
+
if (next)
|
|
381
|
+
return { ok: true, value: next };
|
|
382
|
+
if (functionName === "rgb" || functionName === "rgba" || functionName === "hsl" || functionName === "hsla") {
|
|
383
|
+
if (!isOpaqueRgbOrHslFunction(trimmed))
|
|
384
|
+
return { ok: false, reason: "unsupported" };
|
|
385
|
+
}
|
|
386
|
+
return normalized === "100%"
|
|
387
|
+
? { ok: true, value: trimmed }
|
|
388
|
+
: { ok: true, value: `color-mix(in srgb, ${trimmed} ${normalized}, transparent)` };
|
|
389
|
+
}
|
|
390
|
+
if (NAMED_COLOR_KEYWORDS.has(trimmed.toLowerCase())) {
|
|
391
|
+
return normalized === "100%"
|
|
392
|
+
? { ok: true, value: trimmed }
|
|
393
|
+
: { ok: true, value: `color-mix(in srgb, ${trimmed} ${normalized}, transparent)` };
|
|
394
|
+
}
|
|
395
|
+
if (/^color-mix\(/i.test(trimmed)) {
|
|
396
|
+
const next = replaceColorMixOpacity(trimmed, normalized);
|
|
397
|
+
return next ? { ok: true, value: next } : { ok: false, reason: "unsupported" };
|
|
398
|
+
}
|
|
399
|
+
return { ok: false, reason: "unsupported" };
|
|
400
|
+
}
|
|
401
|
+
function tokenReferenceName(entry) {
|
|
402
|
+
const name = entry.cssName ?? entry.name;
|
|
403
|
+
return name.startsWith("--") ? name : null;
|
|
404
|
+
}
|
|
405
|
+
function rgbTuple(value) {
|
|
406
|
+
const trimmed = value.trim();
|
|
407
|
+
const hex = /^#([\da-f]{3}|[\da-f]{6})$/i.exec(trimmed);
|
|
408
|
+
if (hex) {
|
|
409
|
+
const raw = hex[1];
|
|
410
|
+
const expanded = raw.length === 3 ? raw.split("").map((part) => part + part).join("") : raw;
|
|
411
|
+
// SAFETY: hex length was validated and expanded to six hex digits before parsing RGB channels.
|
|
412
|
+
const rgb = [0, 2, 4].map((offset) => Number.parseInt(expanded.slice(offset, offset + 2), 16));
|
|
413
|
+
return [rgb[0], rgb[1], rgb[2]];
|
|
414
|
+
}
|
|
415
|
+
const match = /^rgba?\(([\s\S]*)\)$/i.exec(trimmed);
|
|
416
|
+
if (!match)
|
|
417
|
+
return null;
|
|
418
|
+
const body = match[1];
|
|
419
|
+
const commaParts = splitTopLevel(body, ",");
|
|
420
|
+
if (commaParts.length > 1 && commaParts.length !== 3 && commaParts.length !== 4)
|
|
421
|
+
return null;
|
|
422
|
+
const channelParts = commaParts.length >= 3
|
|
423
|
+
? commaParts.slice(0, 3)
|
|
424
|
+
: splitTopLevelWhitespace(body.slice(0, Math.max(0, topLevelSlashIndex(body) < 0 ? body.length : topLevelSlashIndex(body))));
|
|
425
|
+
if (channelParts.length !== 3)
|
|
426
|
+
return null;
|
|
427
|
+
const channels = channelParts.map((part) => CSS_NUMBER.test(part.trim()) ? Number(part.trim()) : Number.NaN);
|
|
428
|
+
if (channels.some((channel) => !Number.isFinite(channel) || channel < 0 || channel > 255))
|
|
429
|
+
return null;
|
|
430
|
+
// SAFETY: channel count and finite 0-255 range were validated before rounding to an RGB tuple.
|
|
431
|
+
const rounded = channels.map((channel) => Math.round(channel));
|
|
432
|
+
return [rounded[0], rounded[1], rounded[2]];
|
|
433
|
+
}
|
|
434
|
+
function sameRgb(left, right) {
|
|
435
|
+
return Boolean(left && right && left.every((channel, index) => channel === right[index]));
|
|
436
|
+
}
|
|
437
|
+
function replaceRgbChannels(value, oldValue, nextValue) {
|
|
438
|
+
const match = /^(rgba?)\(([\s\S]*)\)$/i.exec(value.trim());
|
|
439
|
+
const oldRgb = rgbTuple(oldValue);
|
|
440
|
+
const nextRgb = rgbTuple(nextValue);
|
|
441
|
+
if (!match || !sameRgb(rgbTuple(value), oldRgb) || !nextRgb)
|
|
442
|
+
return null;
|
|
443
|
+
const body = match[2];
|
|
444
|
+
const commaParts = splitTopLevel(body, ",");
|
|
445
|
+
if (commaParts.length >= 3) {
|
|
446
|
+
const alpha = commaParts.length === 4 ? `, ${commaParts[3].trim()}` : "";
|
|
447
|
+
return `${match[1]}(${nextRgb.join(", ")}${alpha})`;
|
|
448
|
+
}
|
|
449
|
+
const slash = topLevelSlashIndex(body);
|
|
450
|
+
const alpha = slash >= 0 ? ` / ${body.slice(slash + 1).trim()}` : "";
|
|
451
|
+
return `${match[1]}(${nextRgb.join(" ")}${alpha})`;
|
|
452
|
+
}
|
|
453
|
+
function replaceColorMixItemColor(item, color) {
|
|
454
|
+
const parsed = parseColorMixItem(item);
|
|
455
|
+
if (!parsed.percentage)
|
|
456
|
+
return color;
|
|
457
|
+
const parts = splitTopLevelWhitespace(item.trim());
|
|
458
|
+
return MIX_PERCENTAGE_OR_TOKEN.test(parts[0])
|
|
459
|
+
? `${parsed.percentage} ${color}`
|
|
460
|
+
: `${color} ${parsed.percentage}`;
|
|
461
|
+
}
|
|
462
|
+
function replaceColorMixColor(value, oldValue, nextColor) {
|
|
463
|
+
const open = value.indexOf("(");
|
|
464
|
+
const close = value.lastIndexOf(")");
|
|
465
|
+
if (open < 0 || close <= open)
|
|
466
|
+
return null;
|
|
467
|
+
const parts = splitTopLevel(value.slice(open + 1, close), ",");
|
|
468
|
+
if (parts.length !== 3 || !/^\s*in\s+/i.test(parts[0]))
|
|
469
|
+
return null;
|
|
470
|
+
const items = parts.slice(1).map(parseColorMixItem);
|
|
471
|
+
const colorIndexes = items.flatMap((item, index) => item.color.toLowerCase() === "transparent" ? [] : [index]);
|
|
472
|
+
if (colorIndexes.length !== 1)
|
|
473
|
+
return null;
|
|
474
|
+
const colorIndex = colorIndexes[0];
|
|
475
|
+
if (!sameRgb(rgbTuple(items[colorIndex].color), rgbTuple(oldValue)) && items[colorIndex].color.trim().toLowerCase() !== oldValue.trim().toLowerCase())
|
|
476
|
+
return null;
|
|
477
|
+
const updated = [...parts];
|
|
478
|
+
updated[colorIndex + 1] = replaceColorMixItemColor(parts[colorIndex + 1], nextColor);
|
|
479
|
+
return `${value.slice(0, open + 1)}${updated.join(", ")}${value.slice(close)}`;
|
|
480
|
+
}
|
|
481
|
+
function escapeRegExp(value) {
|
|
482
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Replaces only the color token in a separable color expression. Keeping this
|
|
486
|
+
* separate from a plain token swap preserves authored alpha modifiers, for
|
|
487
|
+
* example Tailwind's `color-mix(... var(--color-red-500) 10%, transparent)`
|
|
488
|
+
* keeps its `10%` when the color token changes.
|
|
489
|
+
*/
|
|
490
|
+
export function applyColorTokenReplacement(value, oldToken, newToken) {
|
|
491
|
+
const nextName = tokenReferenceName(newToken);
|
|
492
|
+
if (nextName) {
|
|
493
|
+
for (const oldName of [oldToken.cssName, oldToken.name].filter((name) => Boolean(name))) {
|
|
494
|
+
const reference = new RegExp(`var\\(\\s*${escapeRegExp(oldName)}(?=\\s*(?:,|\\)))`, "i");
|
|
495
|
+
if (reference.test(value)) {
|
|
496
|
+
return {
|
|
497
|
+
ok: true,
|
|
498
|
+
value: value.replace(new RegExp(`var\\(\\s*${escapeRegExp(oldName)}(?=\\s*(?:,|\\)))`, "gi"), `var(${nextName}`),
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
const oldValue = oldToken.cssValue?.trim() || oldToken.value.trim();
|
|
504
|
+
const nextValue = newToken.cssValue?.trim() || newToken.value.trim();
|
|
505
|
+
if (!oldValue || !nextValue)
|
|
506
|
+
return { ok: false, reason: "unsupported" };
|
|
507
|
+
const replacement = nextName ? `var(${nextName})` : nextValue;
|
|
508
|
+
if (value.trim().toLowerCase() === oldValue.toLowerCase())
|
|
509
|
+
return { ok: true, value: replacement };
|
|
510
|
+
if (sameRgb(rgbTuple(value), rgbTuple(oldValue)) && !/[/,]/.test(value))
|
|
511
|
+
return { ok: true, value: replacement };
|
|
512
|
+
const rgbReplacement = replaceRgbChannels(value, oldValue, nextValue);
|
|
513
|
+
if (rgbReplacement)
|
|
514
|
+
return { ok: true, value: rgbReplacement };
|
|
515
|
+
const mixReplacement = replaceColorMixColor(value, oldValue, replacement);
|
|
516
|
+
if (mixReplacement)
|
|
517
|
+
return { ok: true, value: mixReplacement };
|
|
518
|
+
return { ok: false, reason: "unsupported" };
|
|
519
|
+
}
|
|
520
|
+
/** The public meaning-preserving edit operation for supported value edits. */
|
|
521
|
+
export function applyValueEdit(request) {
|
|
522
|
+
if (request.kind === "color-opacity") {
|
|
523
|
+
return applyColorOpacity(request.authored, request.opacity);
|
|
524
|
+
}
|
|
525
|
+
return applyColorTokenReplacement(request.authored, request.currentToken, request.nextToken);
|
|
526
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level, browser-safe CSS value splitting helpers shared by the
|
|
3
|
+
* value-semantics Modules (plan slice 3.4). These are internal parsing seams,
|
|
4
|
+
* not public Interface: they split structure, they do not interpret meaning.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Balanced `var()` scanning. Handles nested parentheses and takes the first
|
|
8
|
+
* top-level comma as the fallback separator.
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractVarCalls(value: string): Array<{
|
|
11
|
+
name: string;
|
|
12
|
+
fallback?: string;
|
|
13
|
+
}>;
|
|
14
|
+
/** Index of the first top-level `/` in a value, or -1 when none exists. */
|
|
15
|
+
export declare function topLevelSlashIndex(value: string): number;
|
|
16
|
+
/** Splits CSS values at top-level combinators or an optional delimiter. */
|
|
17
|
+
export declare function splitTopLevel(s: string, sep?: string): string[];
|
|
18
|
+
/** Splits a value at top-level whitespace, honoring quotes and nesting. */
|
|
19
|
+
export declare function splitTopLevelWhitespace(value: string): string[];
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level, browser-safe CSS value splitting helpers shared by the
|
|
3
|
+
* value-semantics Modules (plan slice 3.4). These are internal parsing seams,
|
|
4
|
+
* not public Interface: they split structure, they do not interpret meaning.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Balanced `var()` scanning. Handles nested parentheses and takes the first
|
|
8
|
+
* top-level comma as the fallback separator.
|
|
9
|
+
*/
|
|
10
|
+
export function extractVarCalls(value) {
|
|
11
|
+
const calls = [];
|
|
12
|
+
let i = 0;
|
|
13
|
+
while (i < value.length) {
|
|
14
|
+
const start = value.indexOf("var(", i);
|
|
15
|
+
if (start < 0)
|
|
16
|
+
break;
|
|
17
|
+
let depth = 1;
|
|
18
|
+
let j = start + 4;
|
|
19
|
+
let comma = -1;
|
|
20
|
+
while (j < value.length && depth > 0) {
|
|
21
|
+
const char = value[j];
|
|
22
|
+
if (char === "(")
|
|
23
|
+
depth++;
|
|
24
|
+
else if (char === ")")
|
|
25
|
+
depth--;
|
|
26
|
+
else if (char === "," && depth === 1 && comma < 0)
|
|
27
|
+
comma = j;
|
|
28
|
+
j++;
|
|
29
|
+
}
|
|
30
|
+
const body = value.slice(start + 4, Math.max(start + 4, j - 1)).trim();
|
|
31
|
+
const name = (body.slice(0, comma < 0 ? body.length : comma - start - 4).trim().match(/^--[\w-]+/) ?? [])[0];
|
|
32
|
+
if (name) {
|
|
33
|
+
const fallback = comma >= 0 ? value.slice(comma + 1, Math.max(comma + 1, j - 1)).trim() : undefined;
|
|
34
|
+
calls.push({ name, fallback });
|
|
35
|
+
}
|
|
36
|
+
i = Math.max(j, start + 4);
|
|
37
|
+
}
|
|
38
|
+
return calls;
|
|
39
|
+
}
|
|
40
|
+
/** Index of the first top-level `/` in a value, or -1 when none exists. */
|
|
41
|
+
export function topLevelSlashIndex(value) {
|
|
42
|
+
let depth = 0;
|
|
43
|
+
for (let index = 0; index < value.length; index++) {
|
|
44
|
+
const char = value[index];
|
|
45
|
+
if (char === "(")
|
|
46
|
+
depth++;
|
|
47
|
+
else if (char === ")")
|
|
48
|
+
depth = Math.max(0, depth - 1);
|
|
49
|
+
else if (char === "/" && depth === 0)
|
|
50
|
+
return index;
|
|
51
|
+
}
|
|
52
|
+
return -1;
|
|
53
|
+
}
|
|
54
|
+
/** Splits CSS values at top-level combinators or an optional delimiter. */
|
|
55
|
+
export function splitTopLevel(s, sep) {
|
|
56
|
+
const parts = [];
|
|
57
|
+
let depth = 0;
|
|
58
|
+
let start = 0;
|
|
59
|
+
for (let i = 0; i < s.length; i++) {
|
|
60
|
+
if (s[i] === "(")
|
|
61
|
+
depth++;
|
|
62
|
+
else if (s[i] === ")")
|
|
63
|
+
depth--;
|
|
64
|
+
else if (depth === 0 && sep && s[i] === sep) {
|
|
65
|
+
parts.push(s.slice(start, i));
|
|
66
|
+
start = i + 1;
|
|
67
|
+
}
|
|
68
|
+
else if (depth === 0 && !sep && (s[i] === " " || s[i] === ">" || s[i] === "+" || s[i] === "~")) {
|
|
69
|
+
// Only split on combinators that have non-space around them.
|
|
70
|
+
if (i > start)
|
|
71
|
+
parts.push(s.slice(start, i).trim());
|
|
72
|
+
start = i + 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const last = s.slice(start).trim();
|
|
76
|
+
if (last)
|
|
77
|
+
parts.push(last);
|
|
78
|
+
return parts;
|
|
79
|
+
}
|
|
80
|
+
/** Splits a value at top-level whitespace, honoring quotes and nesting. */
|
|
81
|
+
export function splitTopLevelWhitespace(value) {
|
|
82
|
+
const parts = [];
|
|
83
|
+
let depth = 0;
|
|
84
|
+
let quote = null;
|
|
85
|
+
let start = 0;
|
|
86
|
+
for (let i = 0; i < value.length; i++) {
|
|
87
|
+
const char = value[i];
|
|
88
|
+
if (quote) {
|
|
89
|
+
if (char === quote && value[i - 1] !== "\\")
|
|
90
|
+
quote = null;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (char === '"' || char === "'") {
|
|
94
|
+
quote = char;
|
|
95
|
+
}
|
|
96
|
+
else if (char === "(" || char === "[") {
|
|
97
|
+
depth++;
|
|
98
|
+
}
|
|
99
|
+
else if (char === ")" || char === "]") {
|
|
100
|
+
depth = Math.max(0, depth - 1);
|
|
101
|
+
}
|
|
102
|
+
else if (depth === 0 && /\s/.test(char ?? "")) {
|
|
103
|
+
if (i > start)
|
|
104
|
+
parts.push(value.slice(start, i));
|
|
105
|
+
start = i + 1;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (start < value.length)
|
|
109
|
+
parts.push(value.slice(start));
|
|
110
|
+
return parts;
|
|
111
|
+
}
|