nudge-ui 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/nudge-ui.mjs +3 -1
- package/dist/cli/agentCommand.d.ts +8 -0
- package/dist/cli/agentCommand.js +59 -0
- package/dist/client.mjs +878 -11
- package/dist/hosts/astro/astroRuntimeConfig.js +1 -1
- package/dist/hosts/astro/clientTransport.js +63 -11
- package/dist/hosts/astro/integration.d.ts +2 -2
- package/dist/hosts/astro/integration.js +4 -3
- package/dist/hosts/environment.d.ts +15 -0
- package/dist/hosts/environment.js +16 -0
- package/dist/hosts/next/sidecar.d.ts +4 -0
- package/dist/hosts/next/sidecar.js +56 -7
- package/dist/hosts/next/wrapper.d.ts +2 -0
- package/dist/hosts/next/wrapper.js +32 -3
- package/dist/hosts/projectBridge.d.ts +21 -0
- package/dist/hosts/projectBridge.js +98 -0
- package/dist/hosts/static/cli.d.ts +1 -1
- package/dist/hosts/static/cli.js +6 -1
- package/dist/hosts/static/manifest.d.ts +1 -1
- package/dist/hosts/static/manifest.js +3 -1
- package/dist/hosts/static/server.js +45 -3
- package/dist/hosts/vite/vite.d.ts +6 -1
- package/dist/hosts/vite/vite.js +82 -15
- package/dist/inspector/agent/McpConnectionDialog.d.ts +5 -4
- package/dist/inspector/agent/McpConnectionDialog.js +20 -37
- package/dist/inspector/agent/client.d.ts +16 -3
- package/dist/inspector/agent/client.js +114 -11
- package/dist/inspector/agent/connectionStatus.d.ts +3 -3
- package/dist/inspector/agent/connectionStatus.js +11 -4
- package/dist/inspector/agent/httpTransport.d.ts +8 -0
- package/dist/inspector/agent/httpTransport.js +78 -18
- package/dist/inspector/agent/protocol.d.ts +11 -3
- package/dist/inspector/agent/protocol.js +1 -1
- package/dist/inspector/agent/verification.d.ts +1 -1
- package/dist/inspector/agent/verification.js +69 -12
- package/dist/inspector/canvas/CanvasCard.d.ts +5 -3
- package/dist/inspector/canvas/CanvasCard.js +181 -91
- package/dist/inspector/canvas/CanvasElementOverlay.js +288 -52
- package/dist/inspector/canvas/CanvasToolbar.d.ts +12 -0
- package/dist/inspector/canvas/CanvasToolbar.js +24 -0
- package/dist/inspector/canvas/CanvasWorkspace.d.ts +4 -1
- package/dist/inspector/canvas/CanvasWorkspace.js +410 -72
- package/dist/inspector/canvas/activeCanvasDocument.d.ts +5 -0
- package/dist/inspector/canvas/activeCanvasDocument.js +23 -0
- package/dist/inspector/canvas/canvasResize.d.ts +30 -0
- package/dist/inspector/canvas/canvasResize.js +52 -0
- package/dist/inspector/canvas/canvasStore.d.ts +30 -6
- package/dist/inspector/canvas/canvasStore.js +128 -61
- package/dist/inspector/canvas/frameProtocol.d.ts +82 -5
- package/dist/inspector/canvas/frameProtocol.js +63 -2
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +4 -0
- package/dist/inspector/canvas/keyboardShortcuts.js +16 -0
- package/dist/inspector/canvas/linkEligibility.d.ts +0 -5
- package/dist/inspector/canvas/linkEligibility.js +0 -29
- package/dist/inspector/canvas/projection.d.ts +7 -0
- package/dist/inspector/canvas/projection.js +118 -25
- package/dist/inspector/canvas/rendererBootstrap.js +42 -29
- package/dist/inspector/canvas/rendererElementSelector.d.ts +1 -1
- package/dist/inspector/canvas/rendererElementSelector.js +385 -58
- package/dist/inspector/canvas/rendererMessageRouter.d.ts +11 -0
- package/dist/inspector/canvas/rendererMessageRouter.js +43 -0
- package/dist/inspector/canvas/rendererSelectionProxy.js +6 -2
- package/dist/inspector/canvas/sessionStore.d.ts +1 -0
- package/dist/inspector/canvas/sessionStore.js +12 -4
- package/dist/inspector/canvas/staleChangeDetector.js +16 -14
- package/dist/inspector/changes/changesLog.js +31 -1
- package/dist/inspector/changes/managedStyleProjection.d.ts +1 -1
- package/dist/inspector/changes/managedStyleProjection.js +3 -3
- package/dist/inspector/changes/structuralTypes.d.ts +4 -0
- package/dist/inspector/changes/workspaceChanges.d.ts +4 -0
- package/dist/inspector/changes/workspaceChanges.js +29 -3
- package/dist/inspector/clientManifest.d.ts +7 -0
- package/dist/inspector/clientManifest.js +12 -0
- package/dist/inspector/componentSemantics/adapterRegistry.js +4 -3
- package/dist/inspector/componentSemantics/runtimeBridge.d.ts +2 -2
- package/dist/inspector/componentSemantics/runtimeBridge.js +16 -3
- package/dist/inspector/index.d.ts +2 -0
- package/dist/inspector/index.js +80 -32
- package/dist/inspector/inline-text/inlineTextDiagnostics.d.ts +10 -0
- package/dist/inspector/inline-text/inlineTextDiagnostics.js +65 -0
- package/dist/inspector/inline-text/inlineTextEditor.d.ts +3 -5
- package/dist/inspector/inline-text/inlineTextEditor.js +74 -206
- package/dist/inspector/inline-text/inlineTextFeedback.d.ts +5 -0
- package/dist/inspector/inline-text/inlineTextFeedback.js +27 -0
- package/dist/inspector/inline-text/inlineTextLifecycle.js +2 -0
- package/dist/inspector/inline-text/textEditChange.d.ts +14 -0
- package/dist/inspector/inline-text/textEditChange.js +165 -0
- package/dist/inspector/inspection/selectionProperty.d.ts +1 -0
- package/dist/inspector/inspection/selectionProperty.js +1 -0
- package/dist/inspector/overlay/DomNavigator.d.ts +10 -0
- package/dist/inspector/overlay/DomNavigator.js +40 -0
- package/dist/inspector/overlay/InspectorOverlay.js +6 -2
- package/dist/inspector/overlay/clickPolicy.d.ts +18 -2
- package/dist/inspector/overlay/clickPolicy.js +34 -3
- package/dist/inspector/overlay/elementSelector.d.ts +1 -1
- package/dist/inspector/overlay/elementSelector.js +18 -7
- package/dist/inspector/overlay/selectedGeometry.js +21 -2
- package/dist/inspector/overlay/spacingGestures.d.ts +45 -0
- package/dist/inspector/overlay/spacingGestures.js +351 -0
- package/dist/inspector/overlay/structuralGestures.d.ts +2 -2
- package/dist/inspector/overlay/structuralGestures.js +12 -10
- package/dist/inspector/projection/managedStylesheet.js +4 -1
- package/dist/inspector/projection/renderedInstance.d.ts +2 -0
- package/dist/inspector/projection/renderedInstance.js +5 -1
- package/dist/inspector/projection/structuralProjection.d.ts +2 -0
- package/dist/inspector/projection/structuralProjection.js +85 -1
- package/dist/inspector/projection/structuralProjectionBoundary.js +17 -1
- package/dist/inspector/projection/textProjection.d.ts +2 -0
- package/dist/inspector/projection/textProjection.js +10 -4
- package/dist/inspector/prompt/clipboardHandoff.d.ts +1 -1
- package/dist/inspector/prompt/clipboardHandoff.js +3 -3
- package/dist/inspector/prompt/generatePrompt.d.ts +2 -1
- package/dist/inspector/prompt/generatePrompt.js +19 -2
- package/dist/inspector/runtime/editorShell.d.ts +2 -0
- package/dist/inspector/runtime/editorShell.js +4 -0
- package/dist/inspector/runtime/runtimeConfig.d.ts +5 -1
- package/dist/inspector/runtime/runtimeConfig.js +4 -0
- package/dist/inspector/selection/hierarchy.d.ts +6 -0
- package/dist/inspector/selection/hierarchy.js +8 -0
- package/dist/inspector/selection/selectionStore.js +2 -0
- package/dist/inspector/settings/SettingsDialog.d.ts +1 -1
- package/dist/inspector/settings/SettingsDialog.js +12 -2
- package/dist/inspector/shell/AppShell.js +5 -1
- package/dist/inspector/shell/ChangesLog.js +26 -22
- package/dist/inspector/shell/CopyPromptButton.js +102 -19
- package/dist/inspector/shell/EmptyState.js +1 -1
- package/dist/inspector/shell/InspectorShell.d.ts +0 -1
- package/dist/inspector/shell/InspectorShell.js +38 -42
- package/dist/inspector/shell/PeekOriginalButton.d.ts +7 -0
- package/dist/inspector/shell/PeekOriginalButton.js +57 -0
- package/dist/inspector/shell/PeekOriginalIcon.d.ts +7 -0
- package/dist/inspector/shell/PeekOriginalIcon.js +9 -0
- package/dist/inspector/shell/originalPreview.d.ts +9 -0
- package/dist/inspector/shell/originalPreview.js +61 -0
- package/dist/inspector/shell/shortcuts.d.ts +3 -0
- package/dist/inspector/shell/shortcuts.js +15 -0
- package/dist/inspector/sketch/SketchChanges.d.ts +2 -0
- package/dist/inspector/sketch/SketchChanges.js +72 -0
- package/dist/inspector/sketch/SketchEditor.d.ts +21 -0
- package/dist/inspector/sketch/SketchEditor.js +402 -0
- package/dist/inspector/sketch/SketchEntryButton.d.ts +4 -0
- package/dist/inspector/sketch/SketchEntryButton.js +11 -0
- package/dist/inspector/sketch/SketchFrameOverlay.d.ts +11 -0
- package/dist/inspector/sketch/SketchFrameOverlay.js +119 -0
- package/dist/inspector/sketch/SketchLayersPanel.d.ts +2 -0
- package/dist/inspector/sketch/SketchLayersPanel.js +63 -0
- package/dist/inspector/sketch/SketchOverlay.d.ts +19 -0
- package/dist/inspector/sketch/SketchOverlay.js +420 -0
- package/dist/inspector/sketch/SketchPromptPanel.d.ts +15 -0
- package/dist/inspector/sketch/SketchPromptPanel.js +18 -0
- package/dist/inspector/sketch/SketchWorkspace.d.ts +13 -0
- package/dist/inspector/sketch/SketchWorkspace.js +152 -0
- package/dist/inspector/sketch/capture.d.ts +55 -0
- package/dist/inspector/sketch/capture.js +350 -0
- package/dist/inspector/sketch/freehand.d.ts +13 -0
- package/dist/inspector/sketch/freehand.js +64 -0
- package/dist/inspector/sketch/geometry.d.ts +17 -0
- package/dist/inspector/sketch/geometry.js +98 -0
- package/dist/inspector/sketch/handoff.d.ts +21 -0
- package/dist/inspector/sketch/handoff.js +72 -0
- package/dist/inspector/sketch/interaction.d.ts +21 -0
- package/dist/inspector/sketch/interaction.js +98 -0
- package/dist/inspector/sketch/model.d.ts +104 -0
- package/dist/inspector/sketch/model.js +282 -0
- package/dist/inspector/sketch/persistence.d.ts +21 -0
- package/dist/inspector/sketch/persistence.js +205 -0
- package/dist/inspector/sketch/raster.d.ts +22 -0
- package/dist/inspector/sketch/raster.js +203 -0
- package/dist/inspector/sketch/sketchNote.d.ts +10 -0
- package/dist/inspector/sketch/sketchNote.js +30 -0
- package/dist/inspector/sketch/store.d.ts +47 -0
- package/dist/inspector/sketch/store.js +434 -0
- package/dist/inspector/styleEditors/BorderEditor.js +15 -19
- package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -6
- package/dist/inspector/styleEditors/BoxShadowEditor.js +12 -1
- package/dist/inspector/styleEditors/ColorPicker.js +11 -36
- package/dist/inspector/styleEditors/GapField.d.ts +3 -2
- package/dist/inspector/styleEditors/GapField.js +2 -2
- package/dist/inspector/styleEditors/GridSection.js +1 -1
- package/dist/inspector/styleEditors/LayoutSection.js +11 -8
- package/dist/inspector/styleEditors/SpacingBox.js +31 -33
- package/dist/inspector/styleEditors/layoutPreviewState.d.ts +5 -0
- package/dist/inspector/styleEditors/layoutPreviewState.js +19 -0
- package/dist/inspector/styleEditors/layoutValue.js +3 -0
- package/dist/inspector/styleEditors/nudgeValue.d.ts +11 -0
- package/dist/inspector/styleEditors/nudgeValue.js +93 -5
- package/dist/inspector/styleEditors/stylePresence.d.ts +7 -0
- package/dist/inspector/styleEditors/stylePresence.js +22 -0
- package/dist/inspector/styleEditors/textRelevance.d.ts +3 -0
- package/dist/inspector/styleEditors/textRelevance.js +35 -0
- package/dist/inspector/styleEditors/useFieldVisibility.d.ts +6 -0
- package/dist/inspector/styleEditors/useFieldVisibility.js +26 -0
- package/dist/inspector/tokens/TokenField.js +130 -7
- package/dist/inspector/tokens/TokensPanel.js +2 -1
- package/dist/inspector/tokens/dragPointerLock.d.ts +8 -0
- package/dist/inspector/tokens/dragPointerLock.js +70 -0
- package/dist/inspector/tokens/editActions.d.ts +2 -0
- package/dist/inspector/tokens/editActions.js +2 -2
- package/dist/inspector/tokens/resolution/cssomCollector.d.ts +1 -1
- package/dist/inspector/tokens/resolution/cssomCollector.js +9 -5
- package/dist/inspector/tokens/resolution/ruleMatching.d.ts +40 -0
- package/dist/inspector/tokens/resolution/ruleMatching.js +423 -0
- package/dist/inspector/tokens/resolution/selectorSemantics.d.ts +19 -3
- package/dist/inspector/tokens/resolution/selectorSemantics.js +378 -4
- package/dist/inspector/tokens/resolution.d.ts +3 -26
- package/dist/inspector/tokens/resolution.js +44 -735
- package/dist/inspector/tokens/tokenAvailability.d.ts +18 -0
- package/dist/inspector/tokens/tokenAvailability.js +204 -0
- package/dist/inspector/ui/Button.d.ts +1 -1
- package/dist/inspector/ui/Disclosure.d.ts +22 -0
- package/dist/inspector/ui/Disclosure.js +13 -0
- package/dist/inspector/ui/SideValuesField.js +2 -2
- package/dist/inspector/ui/StatusCallout.d.ts +4 -1
- package/dist/inspector/ui/StatusCallout.js +2 -2
- package/dist/inspector/ui/dragCursor.d.ts +8 -0
- package/dist/inspector/ui/dragCursor.js +21 -0
- package/dist/inspector/ui/styles.js +21 -17
- package/dist/internal/agent-protocol.d.ts +65 -1
- package/dist/internal/agent-protocol.js +183 -3
- package/dist/nudge-ui.mjs +276 -58
- package/dist/transport/editor.d.ts +47 -0
- package/dist/transport/editor.js +163 -0
- package/dist/transport/index.d.ts +1 -0
- package/dist/transport/index.js +1 -0
- package/dist/transport/routes.d.ts +10 -0
- package/dist/transport/routes.js +10 -0
- package/package.json +3 -1
- package/dist/inspector/shell/DomNavigation.d.ts +0 -8
- package/dist/inspector/shell/DomNavigation.js +0 -30
- package/dist/inspector/shell/panelLayout.d.ts +0 -2
- package/dist/inspector/shell/panelLayout.js +0 -29
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { IconLinkOff } from "@tabler/icons-react";
|
|
4
4
|
import { applyValueEdit, normalizeOpacityPercent, selectTokens, } from "../../css/value-semantics/index.js";
|
|
5
5
|
import { promoteToToken, swapToken } from "./editActions.js";
|
|
6
6
|
import { setStyle } from "./editActions.js";
|
|
7
7
|
import { completeCssValue } from "../styleEditors/completeCssValue.js";
|
|
8
|
-
import { nudgeCssValue, nudgeOpacityValue } from "../styleEditors/nudgeValue.js";
|
|
8
|
+
import { canNudgeCssValueByDrag, nudgeCssValue, nudgeCssValueByDrag, nudgeOpacityValue, supportsDragNudge, } from "../styleEditors/nudgeValue.js";
|
|
9
9
|
import { valuePolicyFor } from "../styleEditors/valuePolicy.js";
|
|
10
10
|
import { IconButton } from "../ui/IconButton.js";
|
|
11
11
|
import { PopoverListbox } from "../ui/PopoverListbox.js";
|
|
@@ -13,6 +13,8 @@ import { ColorSwatch } from "../ui/ColorSwatch.js";
|
|
|
13
13
|
import { getStateStyleValue } from "../shell/stateValue.js";
|
|
14
14
|
import { AtRuleIndicator, useFieldAtRules } from "../ui/AtRuleContext.js";
|
|
15
15
|
import { TokenChip } from "./TokenChip.js";
|
|
16
|
+
import { startDragPointerLock } from "./dragPointerLock.js";
|
|
17
|
+
import { createChangeHistoryGroup } from "../changes/workspaceChanges.js";
|
|
16
18
|
import { isMultiTarget } from "../selection/editTarget.js";
|
|
17
19
|
const NON_COLOR_FACTS = { hasEmbeddedAlpha: false, isExpression: false, opacityEditable: false };
|
|
18
20
|
function colorFacts(value) {
|
|
@@ -61,6 +63,16 @@ function formatNumber(value) {
|
|
|
61
63
|
function stripCssUnit(value) {
|
|
62
64
|
return value.replace(/^(-?\d+(?:\.\d+)?)(px|rem|em|vh|vw|vmin|vmax|%|ch|ex|cm|mm|in|pt|pc)$/i, "$1");
|
|
63
65
|
}
|
|
66
|
+
function releasePointerCapture(state) {
|
|
67
|
+
try {
|
|
68
|
+
if (state.handle.hasPointerCapture?.(state.pointerId)) {
|
|
69
|
+
state.handle.releasePointerCapture(state.pointerId);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// The browser may release capture before pointerup/pointercancel arrives.
|
|
74
|
+
}
|
|
75
|
+
}
|
|
64
76
|
/** Returns the first family in a CSS family list without splitting var() fallbacks. */
|
|
65
77
|
function primaryFontFamily(value) {
|
|
66
78
|
let depth = 0;
|
|
@@ -138,8 +150,9 @@ function browserRecognizesColor(value) {
|
|
|
138
150
|
function NativeColorSwatch({ value, onChange, disabled, }) {
|
|
139
151
|
const resolvedHex = colorValueToHex(value);
|
|
140
152
|
const hex = resolvedHex ?? "#000000";
|
|
141
|
-
const
|
|
142
|
-
|
|
153
|
+
const cssColor = browserRecognizesColor(value) ? value.trim() : resolvedHex;
|
|
154
|
+
const hasRenderableColor = cssColor !== null;
|
|
155
|
+
return (_jsxs("label", { className: "token-color-control", "data-resolved": hasRenderableColor ? "true" : "false", children: [_jsx(ColorSwatch, { color: cssColor ?? "transparent", "data-test": "token-color-swatch" }), _jsx("input", { className: "token-color-control__input", "data-test": "token-color-input", type: "color", value: hex, disabled: disabled, "aria-label": "Choose color", onChange: (event) => onChange(event.target.value) })] }));
|
|
143
156
|
}
|
|
144
157
|
export function TokenValueField(props) {
|
|
145
158
|
const { property, domElement, semanticSlot, committedValue, resolvedValue = committedValue, activeTokenName: controlledTokenName = null, entries, suggestions = [], inputDataTest = "raw-input", allowedTokenNames, isColor = false, disabled = false, mixed = false, formatRawValue = (value) => value.trim(), onCommitRaw, onSelectToken, onUnlink, attributionTokens = [], leading, trailing, className, label, opacity, color, onCommitOpacity, atRules, chipVariant = "default", } = props;
|
|
@@ -164,6 +177,8 @@ export function TokenValueField(props) {
|
|
|
164
177
|
const selectedFromPopover = useRef(false);
|
|
165
178
|
const cancelOnBlur = useRef(false);
|
|
166
179
|
const isNavigatingSuggestions = useRef(false);
|
|
180
|
+
const dragNudgeRef = useRef(null);
|
|
181
|
+
const [isDraggingNudge, setIsDraggingNudge] = useState(false);
|
|
167
182
|
useEffect(() => {
|
|
168
183
|
setRawValue(committedValue);
|
|
169
184
|
setActiveTokenName(controlledTokenName);
|
|
@@ -301,6 +316,106 @@ export function TokenValueField(props) {
|
|
|
301
316
|
inputRef.current?.blur();
|
|
302
317
|
}
|
|
303
318
|
}
|
|
319
|
+
const stopDragNudge = useCallback(() => {
|
|
320
|
+
const drag = dragNudgeRef.current;
|
|
321
|
+
if (!drag)
|
|
322
|
+
return;
|
|
323
|
+
dragNudgeRef.current = null;
|
|
324
|
+
drag.pointerLock?.stop();
|
|
325
|
+
releasePointerCapture(drag);
|
|
326
|
+
setIsDraggingNudge(false);
|
|
327
|
+
}, []);
|
|
328
|
+
useEffect(() => {
|
|
329
|
+
const stopOnWindowBlur = () => stopDragNudge();
|
|
330
|
+
window.addEventListener("blur", stopOnWindowBlur);
|
|
331
|
+
return () => {
|
|
332
|
+
window.removeEventListener("blur", stopOnWindowBlur);
|
|
333
|
+
stopDragNudge();
|
|
334
|
+
};
|
|
335
|
+
}, [stopDragNudge]);
|
|
336
|
+
function handleDragNudgePointerDown(event) {
|
|
337
|
+
if (event.button !== 0)
|
|
338
|
+
return;
|
|
339
|
+
if (disabled || !supportsDragNudge(property))
|
|
340
|
+
return;
|
|
341
|
+
if (!canNudgeCssValueByDrag(property, rawValue))
|
|
342
|
+
return;
|
|
343
|
+
stopDragNudge();
|
|
344
|
+
const handle = event.currentTarget;
|
|
345
|
+
const drag = {
|
|
346
|
+
commit: createChangeHistoryGroup(),
|
|
347
|
+
handle,
|
|
348
|
+
pointerId: event.pointerId,
|
|
349
|
+
lastClientX: event.clientX,
|
|
350
|
+
deltaX: 0,
|
|
351
|
+
startValue: rawValue,
|
|
352
|
+
lastValue: rawValue,
|
|
353
|
+
shiftActive: event.shiftKey,
|
|
354
|
+
shiftSnapPending: event.shiftKey,
|
|
355
|
+
};
|
|
356
|
+
dragNudgeRef.current = drag;
|
|
357
|
+
if (typeof handle.setPointerCapture === "function")
|
|
358
|
+
handle.setPointerCapture(event.pointerId);
|
|
359
|
+
if (event.pointerType === "mouse") {
|
|
360
|
+
drag.pointerLock = startDragPointerLock(handle, { x: event.clientX, y: event.clientY }, (mouseEvent) => {
|
|
361
|
+
updateDragNudge(mouseEvent, mouseEvent.movementX);
|
|
362
|
+
}, stopDragNudge);
|
|
363
|
+
}
|
|
364
|
+
setIsDraggingNudge(true);
|
|
365
|
+
event.preventDefault();
|
|
366
|
+
event.stopPropagation();
|
|
367
|
+
}
|
|
368
|
+
function handleDragNudgePointerMove(event) {
|
|
369
|
+
const drag = dragNudgeRef.current;
|
|
370
|
+
if (!drag || drag.pointerId !== event.pointerId)
|
|
371
|
+
return;
|
|
372
|
+
if (drag.pointerLock?.isLocked())
|
|
373
|
+
return;
|
|
374
|
+
const movementX = event.clientX - drag.lastClientX;
|
|
375
|
+
drag.lastClientX = event.clientX;
|
|
376
|
+
updateDragNudge(event, movementX);
|
|
377
|
+
}
|
|
378
|
+
function updateDragNudge(event, movementX) {
|
|
379
|
+
const drag = dragNudgeRef.current;
|
|
380
|
+
if (!drag)
|
|
381
|
+
return;
|
|
382
|
+
if (event.shiftKey !== drag.shiftActive) {
|
|
383
|
+
drag.shiftActive = event.shiftKey;
|
|
384
|
+
drag.startValue = drag.lastValue;
|
|
385
|
+
drag.deltaX = 0;
|
|
386
|
+
drag.shiftSnapPending = event.shiftKey;
|
|
387
|
+
}
|
|
388
|
+
drag.deltaX += movementX;
|
|
389
|
+
const next = nudgeCssValueByDrag(property, drag.startValue, drag.deltaX, drag.shiftActive, drag.shiftActive && drag.shiftSnapPending);
|
|
390
|
+
if (next === null || next === drag.lastValue)
|
|
391
|
+
return;
|
|
392
|
+
drag.lastValue = next;
|
|
393
|
+
if (drag.shiftActive && drag.shiftSnapPending) {
|
|
394
|
+
drag.startValue = next;
|
|
395
|
+
drag.deltaX = 0;
|
|
396
|
+
drag.shiftSnapPending = false;
|
|
397
|
+
}
|
|
398
|
+
event.preventDefault();
|
|
399
|
+
event.stopPropagation();
|
|
400
|
+
setRawValue(next);
|
|
401
|
+
setActiveTokenName(null);
|
|
402
|
+
drag.commit(() => onCommitRaw(next));
|
|
403
|
+
}
|
|
404
|
+
function handleDragNudgePointerEnd(event) {
|
|
405
|
+
if (dragNudgeRef.current?.pointerId !== event.pointerId)
|
|
406
|
+
return;
|
|
407
|
+
stopDragNudge();
|
|
408
|
+
}
|
|
409
|
+
function renderLeading() {
|
|
410
|
+
if (!leading)
|
|
411
|
+
return null;
|
|
412
|
+
const canDrag = !disabled
|
|
413
|
+
&& supportsDragNudge(property)
|
|
414
|
+
&& canNudgeCssValueByDrag(property, rawValue);
|
|
415
|
+
if (!canDrag)
|
|
416
|
+
return _jsx("span", { className: "token-field__leading", children: leading });
|
|
417
|
+
return (_jsx("span", { className: "token-field__leading token-field__leading--nudge", "data-test": "nudge-handle", "data-dragging": isDraggingNudge ? "true" : undefined, title: `Drag to adjust ${label ?? property}`, onPointerDown: handleDragNudgePointerDown, onPointerMove: handleDragNudgePointerMove, onPointerUp: handleDragNudgePointerEnd, onPointerCancel: handleDragNudgePointerEnd, onBlur: stopDragNudge, children: leading }));
|
|
418
|
+
}
|
|
304
419
|
function commitOpacityValue(value = opacityValue) {
|
|
305
420
|
if (!showOpacity || !onCommitOpacity)
|
|
306
421
|
return;
|
|
@@ -343,12 +458,12 @@ export function TokenValueField(props) {
|
|
|
343
458
|
if (activeToken) {
|
|
344
459
|
const chipValue = chipVariant === "small" ? stripCssUnit(activeToken.value) : activeToken.name;
|
|
345
460
|
const embedColorSwatch = isColor && chipVariant !== "small";
|
|
346
|
-
return (_jsxs("span", { className: `token-field${isColor ? " token-field--color" : ""}${embedColorSwatch ? " token-field--color-chip" : ""}${className ? ` ${className}` : ""}`, "data-test": "token-field", "data-property": property, "aria-label": label, title: label, children: [
|
|
461
|
+
return (_jsxs("span", { className: `token-field${isColor ? " token-field--color" : ""}${embedColorSwatch ? " token-field--color-chip" : ""}${className ? ` ${className}` : ""}`, "data-test": "token-field", "data-property": property, "aria-label": label, title: label, children: [renderLeading(), embedColorSwatch ? null : colorControlEl, _jsxs(TokenChip, { size: chipVariant, "data-group": groupByTokenName.get(activeToken.name) ?? tokenGroup(activeToken), children: [_jsx(PopoverListbox, { query: "", value: activeToken.name, open: isTokenPickerOpen, trigger: (_jsxs(TokenChip.Picker, { children: [embedColorSwatch ? colorControlEl : null, _jsx(TokenChip.Label, { title: activeToken.name, children: chipValue })] })), triggerClassName: "token-chip__trigger", triggerDataTest: "token-chip", triggerAriaLabel: `Change ${property} token`, searchable: true, searchPlaceholder: "Search tokens\u2026", searchAriaLabel: "Search tokens", items: [...rawSuggestionItems, ...relevantTokens.map((entry) => tokenSuggestion(entry, groupByTokenName))], onQueryChange: () => undefined, onOpenChange: setTokenPickerOpen, disabled: disabled, onSelect: (value) => {
|
|
347
462
|
handleSuggestionSelect(value);
|
|
348
463
|
} }), _jsx(TokenChip.Action, { children: _jsx(IconButton, { variant: "quiet", size: "compact", style: { borderRadius: "var(--radius-4)" }, label: "Replace with raw value", "data-test": "delink-btn", disabled: disabled, onClick: handleDelink, children: _jsx(IconLinkOff, { size: chipVariant === "small" ? 12 : 14, stroke: 1.75, "aria-hidden": "true" }) }) })] }), opacityControl, _jsx(AtRuleIndicator, { atRules: fieldAtRules }), trailing ? _jsx("span", { className: "token-field__trailing", children: trailing }) : null] }));
|
|
349
464
|
}
|
|
350
465
|
const showPopover = isFocused && (filteredTokens.length > 0 || availableSuggestions.length > 0);
|
|
351
|
-
return (_jsxs("span", { className: `token-field token-field--raw${isColor ? " token-field--color" : ""}${className ? ` ${className}` : ""}`, "data-test": "token-field", "data-property": property, "aria-label": label, title: label, children: [
|
|
466
|
+
return (_jsxs("span", { className: `token-field token-field--raw${isColor ? " token-field--color" : ""}${className ? ` ${className}` : ""}`, "data-test": "token-field", "data-property": property, "aria-label": label, title: label, children: [renderLeading(), colorControlEl, _jsx(PopoverListbox, { query: rawValue, value: null, open: showPopover, placeholder: property, inputRef: inputRef, inputAppearance: "embedded", inputDataTest: inputDataTest, inputOnFocus: () => {
|
|
352
467
|
setIsFocused(true);
|
|
353
468
|
if (mixed && rawValue.trim().toLowerCase() === "mixed")
|
|
354
469
|
setRawValue("");
|
|
@@ -417,7 +532,15 @@ export function TokenField(props) {
|
|
|
417
532
|
const currentToken = activeTokenName
|
|
418
533
|
? entries.find((entry) => entry.name === activeTokenName) ?? null
|
|
419
534
|
: null;
|
|
420
|
-
|
|
535
|
+
let resolvedValue = tokenRow?.propertyOpacity?.value ?? tokenRow?.resolvedValue ?? committedValue;
|
|
536
|
+
if (property === "background-color") {
|
|
537
|
+
// Background rows can contain the complete computed shorthand. Extract
|
|
538
|
+
// its color before passing it to the color control, preserving alpha.
|
|
539
|
+
const style = el.ownerDocument.createElement("span").style;
|
|
540
|
+
style.background = resolvedValue;
|
|
541
|
+
resolvedValue = style.backgroundColor || resolvedValue;
|
|
542
|
+
}
|
|
543
|
+
return (_jsx(TokenValueField, { property: property, domElement: el, semanticSlot: semanticSlot, committedValue: committedValue, resolvedValue: resolvedValue, activeTokenName: activeTokenName, attributionTokens: attributionTokens
|
|
421
544
|
?? (selectedProperty?.token.kind === "mixed" ? ["Mixed tokens"] : undefined)
|
|
422
545
|
?? (expression
|
|
423
546
|
? tokenRow?.tokens?.filter((token) => token.name !== tokenRow.opacity?.tokenName).map((token) => token.name)
|
|
@@ -3,6 +3,7 @@ import { useMemo, useState } from "react";
|
|
|
3
3
|
import { isTokenChange, useChanges } from "../changes/changesLog.js";
|
|
4
4
|
import { TextInput } from "../ui/TextInput.js";
|
|
5
5
|
import { ControlSurface } from "../ui/ControlSurface.js";
|
|
6
|
+
import { Disclosure } from "../ui/Disclosure.js";
|
|
6
7
|
import { TokenValueField } from "./TokenField.js";
|
|
7
8
|
import { TOKEN_GROUP_LABELS, TOKEN_GROUP_ORDER, aliasName, compatibleTokenNames, contextLabel, filterTokenRows, } from "./catalog.js";
|
|
8
9
|
import { setGlobalTokenValue } from "./tokenEdits.js";
|
|
@@ -43,5 +44,5 @@ function TokenCatalogItem({ row, rows, entries, }) {
|
|
|
43
44
|
const allowed = compatibleTokenNames(effectiveRow, effectiveRows);
|
|
44
45
|
const variants = row.definition.declarations.filter((declaration) => declaration !== row.activeDeclaration);
|
|
45
46
|
const tokenName = row.definition.name || row.definition.cssName;
|
|
46
|
-
return (_jsxs("article", { className: "token-row", "data-test": "global-token-row", "data-token-name": row.definition.cssName, "data-active": row.activeDeclaration ? "true" : "false", children: [_jsxs("div", { className: "token-row__inline", children: [_jsx(TokenLabel, { as: "code", className: "token-row__name", title: tokenName, children: tokenName }), row.activeDeclaration ? (_jsx(ControlSurface, { children: _jsx(TokenValueField, { property: row.definition.cssName, committedValue: committedValue, resolvedValue: row.resolvedValue || committedValue, activeTokenName: activeAlias, entries: entries, allowedTokenNames: allowed, isColor: row.group === "color", onCommitRaw: (value) => setGlobalTokenValue(row, value), onSelectToken: (token) => { setGlobalTokenValue(row, `var(${token.name})`); }, onUnlink: (value) => setGlobalTokenValue(row, value) }) })) : (_jsx(TextInput, { disabled: true, value: "Inactive in current theme", "aria-label": `${row.definition.cssName} inactive` }))] }), variants.length > 0 ? (
|
|
47
|
+
return (_jsxs("article", { className: "token-row", "data-test": "global-token-row", "data-token-name": row.definition.cssName, "data-active": row.activeDeclaration ? "true" : "false", children: [_jsxs("div", { className: "token-row__inline", children: [_jsx(TokenLabel, { as: "code", className: "token-row__name", title: tokenName, children: tokenName }), row.activeDeclaration ? (_jsx(ControlSurface, { children: _jsx(TokenValueField, { property: row.definition.cssName, committedValue: committedValue, resolvedValue: row.resolvedValue || committedValue, activeTokenName: activeAlias, entries: entries, allowedTokenNames: allowed, isColor: row.group === "color", onCommitRaw: (value) => setGlobalTokenValue(row, value), onSelectToken: (token) => { setGlobalTokenValue(row, `var(${token.name})`); }, onUnlink: (value) => setGlobalTokenValue(row, value) }) })) : (_jsx(TextInput, { disabled: true, value: "Inactive in current theme", "aria-label": `${row.definition.cssName} inactive` }))] }), variants.length > 0 ? (_jsx(Disclosure, { className: "token-variants", "data-test": "token-variants", title: `Variants (${variants.length})`, panelClassName: "token-variants__list", children: variants.map((declaration) => (_jsxs("div", { className: "token-variant", children: [_jsx("span", { className: "token-variant__context", children: contextLabel(declaration.context) }), _jsx("code", { children: declaration.value }), _jsx("span", { children: declaration.source })] }, `${declaration.source}-${contextLabel(declaration.context)}`))) })) : null] }));
|
|
47
48
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Keeps mouse drags relative, including when the handle is inside a shadow root. */
|
|
2
|
+
export declare function startDragPointerLock(handle: HTMLElement, point: {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
}, onMove: (event: MouseEvent) => void, onEnd: () => void): {
|
|
6
|
+
isLocked: () => boolean;
|
|
7
|
+
stop: () => void;
|
|
8
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { showLockedDragCursor } from "../ui/dragCursor.js";
|
|
2
|
+
/** Keeps mouse drags relative, including when the handle is inside a shadow root. */
|
|
3
|
+
export function startDragPointerLock(handle, point, onMove, onEnd) {
|
|
4
|
+
const doc = handle.ownerDocument;
|
|
5
|
+
const root = handle.getRootNode();
|
|
6
|
+
const isLocked = () => root.pointerLockElement === handle;
|
|
7
|
+
let stopped = false;
|
|
8
|
+
let pending = true;
|
|
9
|
+
let acquired = false;
|
|
10
|
+
let removeCursor;
|
|
11
|
+
function removeLockListeners() {
|
|
12
|
+
doc.removeEventListener("pointerlockchange", onLockChange);
|
|
13
|
+
doc.removeEventListener("pointerlockerror", onLockError);
|
|
14
|
+
}
|
|
15
|
+
function onLockChange() {
|
|
16
|
+
if (isLocked()) {
|
|
17
|
+
pending = false;
|
|
18
|
+
acquired = true;
|
|
19
|
+
if (stopped) {
|
|
20
|
+
doc.exitPointerLock();
|
|
21
|
+
removeLockListeners();
|
|
22
|
+
}
|
|
23
|
+
else if (!removeCursor) {
|
|
24
|
+
removeCursor = showLockedDragCursor(doc, point);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else if (acquired) {
|
|
28
|
+
onEnd();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function onLockError() {
|
|
32
|
+
pending = false;
|
|
33
|
+
removeLockListeners();
|
|
34
|
+
}
|
|
35
|
+
function onMouseMove(event) {
|
|
36
|
+
if (!stopped && isLocked())
|
|
37
|
+
onMove(event);
|
|
38
|
+
}
|
|
39
|
+
function onMouseUp(event) {
|
|
40
|
+
if (event.button === 0)
|
|
41
|
+
onEnd();
|
|
42
|
+
}
|
|
43
|
+
doc.addEventListener("mousemove", onMouseMove);
|
|
44
|
+
doc.addEventListener("mouseup", onMouseUp);
|
|
45
|
+
doc.addEventListener("pointerlockchange", onLockChange);
|
|
46
|
+
doc.addEventListener("pointerlockerror", onLockError);
|
|
47
|
+
try {
|
|
48
|
+
// Older implementations return void. Rejections retain pointer-capture dragging.
|
|
49
|
+
const request = handle.requestPointerLock();
|
|
50
|
+
if (request)
|
|
51
|
+
void request.catch(onLockError);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
onLockError();
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
isLocked,
|
|
58
|
+
stop() {
|
|
59
|
+
stopped = true;
|
|
60
|
+
removeCursor?.();
|
|
61
|
+
doc.removeEventListener("mousemove", onMouseMove);
|
|
62
|
+
doc.removeEventListener("mouseup", onMouseUp);
|
|
63
|
+
if (isLocked())
|
|
64
|
+
doc.exitPointerLock();
|
|
65
|
+
// A request can finish after mouse-up or unmount. Release that late lock too.
|
|
66
|
+
if (!pending)
|
|
67
|
+
removeLockListeners();
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -22,6 +22,8 @@ export declare function swapTokens(target: EditTarget, changes: readonly TokenSw
|
|
|
22
22
|
export interface StyleDeclaration {
|
|
23
23
|
property: string;
|
|
24
24
|
value: string;
|
|
25
|
+
/** Optional baseline captured before a transient preview changed the DOM. */
|
|
26
|
+
oldRawValue?: string;
|
|
25
27
|
metadata?: StyleEditMetadata;
|
|
26
28
|
}
|
|
27
29
|
export interface ElementStyleEdit {
|
|
@@ -135,7 +135,7 @@ export function setStyles(target, declarations, metadata) {
|
|
|
135
135
|
export function setElementStyles(edits) {
|
|
136
136
|
return commitElementStyles(edits);
|
|
137
137
|
}
|
|
138
|
-
function buildStyleRecord(el, scopePlan, { property, value, metadata }) {
|
|
138
|
+
function buildStyleRecord(el, scopePlan, { property, value, oldRawValue, metadata }) {
|
|
139
139
|
const cid = el.getAttribute("data-cid") ?? "";
|
|
140
140
|
const { selector, state } = stateFields(el);
|
|
141
141
|
if (!selector)
|
|
@@ -152,7 +152,7 @@ function buildStyleRecord(el, scopePlan, { property, value, metadata }) {
|
|
|
152
152
|
oldToken: null,
|
|
153
153
|
newToken: null,
|
|
154
154
|
rawValue: value,
|
|
155
|
-
oldRawValue: getStateStyleValue(el, property) || undefined,
|
|
155
|
+
oldRawValue: (oldRawValue ?? getStateStyleValue(el, property)) || undefined,
|
|
156
156
|
source: { file: source.file, line: source.line, component: cid },
|
|
157
157
|
runtimeEvidence: source.runtimeEvidence,
|
|
158
158
|
state,
|
|
@@ -15,9 +15,9 @@ export declare function subscribeDocumentRevision(doc: Document, cb: (revisions:
|
|
|
15
15
|
* the element revision. Registration is idempotent.
|
|
16
16
|
*/
|
|
17
17
|
export declare function registerResolutionElement(el: Element): void;
|
|
18
|
+
export declare function registerResolutionLineage(element: HTMLElement): void;
|
|
18
19
|
/** Releases the observer, listener, and cached state owned by one document. */
|
|
19
20
|
export declare function disposeDocumentResolution(doc: Document): void;
|
|
20
|
-
/** Keeps one document's CSSOM observer alive for a browser inspection owner. */
|
|
21
21
|
export declare function retainDocumentResolution(doc: Document): () => void;
|
|
22
22
|
export declare function documentRevisions(doc: Document): DocumentRevisions;
|
|
23
23
|
/** Invalidates CSSOM-derived snapshots after programmatic stylesheet edits. */
|
|
@@ -39,6 +39,13 @@ export function subscribeDocumentRevision(doc, cb) {
|
|
|
39
39
|
export function registerResolutionElement(el) {
|
|
40
40
|
registeredElements.add(el);
|
|
41
41
|
}
|
|
42
|
+
export function registerResolutionLineage(element) {
|
|
43
|
+
let current = element;
|
|
44
|
+
while (current) {
|
|
45
|
+
registerResolutionElement(current);
|
|
46
|
+
current = current.parentElement;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
42
49
|
/** Releases the observer, listener, and cached state owned by one document. */
|
|
43
50
|
export function disposeDocumentResolution(doc) {
|
|
44
51
|
const session = documentResolutionSessions.get(doc);
|
|
@@ -54,9 +61,8 @@ export function disposeDocumentResolution(doc) {
|
|
|
54
61
|
}
|
|
55
62
|
documentResolutionReferences.delete(doc);
|
|
56
63
|
// Keep revision counters monotonic per Document. Resetting them to (0,0)
|
|
57
|
-
// resurrects stale revision-keyed caches in
|
|
58
|
-
//
|
|
59
|
-
// concreteElementMatchCaches, sourceSiteMatchCaches): an entry written at
|
|
64
|
+
// resurrects stale revision-keyed caches in property resolution, token
|
|
65
|
+
// availability, and rule matching: an entry written at
|
|
60
66
|
// (0,0) before disposal matches immediately after disposal at (0,0), even
|
|
61
67
|
// though the CSSOM changed while no observer was attached. Bump instead so
|
|
62
68
|
// every pre-disposal cache entry misses, then let the next
|
|
@@ -73,7 +79,6 @@ export function disposeDocumentResolution(doc) {
|
|
|
73
79
|
documentRevisionListeners.get(doc)?.clear();
|
|
74
80
|
documentRevisionListeners.delete(doc);
|
|
75
81
|
}
|
|
76
|
-
/** Keeps one document's CSSOM observer alive for a browser inspection owner. */
|
|
77
82
|
export function retainDocumentResolution(doc) {
|
|
78
83
|
documentRevisions(doc);
|
|
79
84
|
const session = documentResolutionSessions.get(doc);
|
|
@@ -113,7 +118,6 @@ function changesStylesheet(record) {
|
|
|
113
118
|
|| Array.from(record.addedNodes).some(isStylesheetNode)
|
|
114
119
|
|| Array.from(record.removedNodes).some(isStylesheetNode);
|
|
115
120
|
}
|
|
116
|
-
/** A node that is, or lives inside, one of the tool's own probe elements. */
|
|
117
121
|
function isProbeNode(node) {
|
|
118
122
|
let current = node;
|
|
119
123
|
while (current && current.nodeType !== current.DOCUMENT_NODE) {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { MatchedRule } from "../../../css/model/index.js";
|
|
2
|
+
import { type InteractionState } from "../../shell/styleState.js";
|
|
3
|
+
export interface ElementMatch {
|
|
4
|
+
rule: MatchedRule;
|
|
5
|
+
/** The selector actually used for matching (state-stripped for interaction states). */
|
|
6
|
+
selectorText: string;
|
|
7
|
+
branch: string;
|
|
8
|
+
specificity: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The selector set used by a resolution. Interaction states strip or drop
|
|
12
|
+
* pseudo-class rules, `live` keeps the raw CSSOM rules (used by
|
|
13
|
+
* `getResolvedProperties`), and `stable` drops transient rules (used by
|
|
14
|
+
* `getResolvedPropertiesStable`).
|
|
15
|
+
*/
|
|
16
|
+
type CascadeTransform = InteractionState | "live" | "stable";
|
|
17
|
+
/** Test-only cache reset. */
|
|
18
|
+
export declare function resetSourceSiteMatchCache(): void;
|
|
19
|
+
/** Test-only cache size. */
|
|
20
|
+
export declare function sourceSiteMatchCacheSize(): number;
|
|
21
|
+
export declare function matchRuleForElement(el: HTMLElement, entry: {
|
|
22
|
+
rule: MatchedRule;
|
|
23
|
+
selectorText: string;
|
|
24
|
+
}): ElementMatch | null;
|
|
25
|
+
/**
|
|
26
|
+
* Shares dynamic matches across cache validation and ancestry within one sweep.
|
|
27
|
+
* Element-relative conditions, such as container queries, remain the resolver's
|
|
28
|
+
* responsibility; these results describe selector matches and stylesheet activity.
|
|
29
|
+
*/
|
|
30
|
+
export interface RuleMatcher {
|
|
31
|
+
dynamicMatchKey(element: HTMLElement): string;
|
|
32
|
+
matchesForElement(element: HTMLElement): {
|
|
33
|
+
matched: ElementMatch[];
|
|
34
|
+
allMatched: ElementMatch[];
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Creates a matcher for one CSSOM snapshot. */
|
|
38
|
+
export declare function createRuleMatcher(rules: MatchedRule[], transform: CascadeTransform): RuleMatcher;
|
|
39
|
+
export declare function getAvailableInteractionStates(el: HTMLElement): InteractionState[];
|
|
40
|
+
export {};
|