nudge-ui 0.2.0 → 0.2.1

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.
Files changed (201) hide show
  1. package/bin/nudge-ui.mjs +3 -1
  2. package/dist/cli/agentCommand.d.ts +8 -0
  3. package/dist/cli/agentCommand.js +59 -0
  4. package/dist/client.mjs +872 -12
  5. package/dist/hosts/astro/astroRuntimeConfig.js +1 -1
  6. package/dist/hosts/astro/clientTransport.js +60 -11
  7. package/dist/hosts/next/sidecar.d.ts +4 -0
  8. package/dist/hosts/next/sidecar.js +49 -6
  9. package/dist/hosts/next/wrapper.js +30 -2
  10. package/dist/hosts/projectBridge.d.ts +20 -0
  11. package/dist/hosts/projectBridge.js +97 -0
  12. package/dist/hosts/static/cli.d.ts +1 -1
  13. package/dist/hosts/static/cli.js +6 -1
  14. package/dist/hosts/static/manifest.d.ts +1 -1
  15. package/dist/hosts/static/manifest.js +1 -1
  16. package/dist/hosts/static/server.js +44 -3
  17. package/dist/hosts/vite/vite.d.ts +5 -1
  18. package/dist/hosts/vite/vite.js +78 -14
  19. package/dist/inspector/agent/McpConnectionDialog.d.ts +2 -2
  20. package/dist/inspector/agent/McpConnectionDialog.js +11 -35
  21. package/dist/inspector/agent/client.d.ts +10 -3
  22. package/dist/inspector/agent/client.js +80 -9
  23. package/dist/inspector/agent/connectionStatus.js +3 -3
  24. package/dist/inspector/agent/httpTransport.d.ts +2 -0
  25. package/dist/inspector/agent/httpTransport.js +37 -17
  26. package/dist/inspector/agent/protocol.d.ts +8 -3
  27. package/dist/inspector/agent/protocol.js +1 -1
  28. package/dist/inspector/agent/verification.d.ts +1 -1
  29. package/dist/inspector/agent/verification.js +69 -12
  30. package/dist/inspector/canvas/CanvasCard.d.ts +5 -3
  31. package/dist/inspector/canvas/CanvasCard.js +181 -91
  32. package/dist/inspector/canvas/CanvasElementOverlay.js +246 -52
  33. package/dist/inspector/canvas/CanvasToolbar.d.ts +12 -0
  34. package/dist/inspector/canvas/CanvasToolbar.js +24 -0
  35. package/dist/inspector/canvas/CanvasWorkspace.d.ts +4 -1
  36. package/dist/inspector/canvas/CanvasWorkspace.js +392 -73
  37. package/dist/inspector/canvas/activeCanvasDocument.d.ts +5 -0
  38. package/dist/inspector/canvas/activeCanvasDocument.js +23 -0
  39. package/dist/inspector/canvas/canvasResize.d.ts +30 -0
  40. package/dist/inspector/canvas/canvasResize.js +52 -0
  41. package/dist/inspector/canvas/canvasStore.d.ts +30 -6
  42. package/dist/inspector/canvas/canvasStore.js +128 -61
  43. package/dist/inspector/canvas/frameProtocol.d.ts +69 -5
  44. package/dist/inspector/canvas/frameProtocol.js +56 -2
  45. package/dist/inspector/canvas/keyboardShortcuts.d.ts +3 -0
  46. package/dist/inspector/canvas/keyboardShortcuts.js +14 -0
  47. package/dist/inspector/canvas/projection.d.ts +7 -0
  48. package/dist/inspector/canvas/projection.js +118 -25
  49. package/dist/inspector/canvas/rendererBootstrap.js +29 -29
  50. package/dist/inspector/canvas/rendererElementSelector.js +341 -30
  51. package/dist/inspector/canvas/rendererMessageRouter.d.ts +11 -0
  52. package/dist/inspector/canvas/rendererMessageRouter.js +43 -0
  53. package/dist/inspector/canvas/rendererSelectionProxy.js +6 -2
  54. package/dist/inspector/canvas/sessionStore.d.ts +1 -0
  55. package/dist/inspector/canvas/sessionStore.js +12 -4
  56. package/dist/inspector/canvas/staleChangeDetector.js +16 -14
  57. package/dist/inspector/changes/changesLog.js +31 -1
  58. package/dist/inspector/changes/managedStyleProjection.d.ts +1 -1
  59. package/dist/inspector/changes/managedStyleProjection.js +3 -3
  60. package/dist/inspector/changes/structuralTypes.d.ts +4 -0
  61. package/dist/inspector/clientManifest.d.ts +5 -0
  62. package/dist/inspector/clientManifest.js +11 -0
  63. package/dist/inspector/componentSemantics/adapterRegistry.js +4 -3
  64. package/dist/inspector/componentSemantics/runtimeBridge.d.ts +2 -2
  65. package/dist/inspector/componentSemantics/runtimeBridge.js +16 -3
  66. package/dist/inspector/index.d.ts +2 -0
  67. package/dist/inspector/index.js +74 -24
  68. package/dist/inspector/inline-text/inlineTextDiagnostics.d.ts +10 -0
  69. package/dist/inspector/inline-text/inlineTextDiagnostics.js +65 -0
  70. package/dist/inspector/inline-text/inlineTextEditor.d.ts +3 -5
  71. package/dist/inspector/inline-text/inlineTextEditor.js +74 -206
  72. package/dist/inspector/inline-text/inlineTextFeedback.d.ts +5 -0
  73. package/dist/inspector/inline-text/inlineTextFeedback.js +27 -0
  74. package/dist/inspector/inline-text/inlineTextLifecycle.js +2 -0
  75. package/dist/inspector/inline-text/textEditChange.d.ts +14 -0
  76. package/dist/inspector/inline-text/textEditChange.js +165 -0
  77. package/dist/inspector/inspection/selectionProperty.d.ts +1 -0
  78. package/dist/inspector/inspection/selectionProperty.js +1 -0
  79. package/dist/inspector/overlay/selectedGeometry.js +21 -2
  80. package/dist/inspector/overlay/spacingGestures.d.ts +45 -0
  81. package/dist/inspector/overlay/spacingGestures.js +353 -0
  82. package/dist/inspector/overlay/structuralGestures.d.ts +2 -2
  83. package/dist/inspector/overlay/structuralGestures.js +12 -10
  84. package/dist/inspector/projection/managedStylesheet.js +4 -1
  85. package/dist/inspector/projection/renderedInstance.d.ts +2 -0
  86. package/dist/inspector/projection/renderedInstance.js +5 -1
  87. package/dist/inspector/projection/structuralProjection.d.ts +2 -0
  88. package/dist/inspector/projection/structuralProjection.js +85 -1
  89. package/dist/inspector/projection/structuralProjectionBoundary.js +17 -1
  90. package/dist/inspector/projection/textProjection.d.ts +2 -0
  91. package/dist/inspector/projection/textProjection.js +10 -4
  92. package/dist/inspector/prompt/clipboardHandoff.d.ts +1 -1
  93. package/dist/inspector/prompt/clipboardHandoff.js +3 -3
  94. package/dist/inspector/prompt/generatePrompt.d.ts +2 -1
  95. package/dist/inspector/prompt/generatePrompt.js +19 -2
  96. package/dist/inspector/runtime/editorShell.d.ts +2 -0
  97. package/dist/inspector/runtime/editorShell.js +4 -0
  98. package/dist/inspector/runtime/runtimeConfig.d.ts +4 -0
  99. package/dist/inspector/runtime/runtimeConfig.js +4 -0
  100. package/dist/inspector/selection/selectionStore.js +2 -0
  101. package/dist/inspector/settings/SettingsDialog.js +10 -0
  102. package/dist/inspector/shell/AppShell.js +5 -1
  103. package/dist/inspector/shell/ChangesLog.js +8 -4
  104. package/dist/inspector/shell/CopyPromptButton.js +95 -19
  105. package/dist/inspector/shell/EmptyState.js +1 -1
  106. package/dist/inspector/shell/InspectorShell.d.ts +0 -1
  107. package/dist/inspector/shell/InspectorShell.js +37 -38
  108. package/dist/inspector/shell/PeekOriginalButton.d.ts +7 -0
  109. package/dist/inspector/shell/PeekOriginalButton.js +57 -0
  110. package/dist/inspector/shell/PeekOriginalIcon.d.ts +7 -0
  111. package/dist/inspector/shell/PeekOriginalIcon.js +9 -0
  112. package/dist/inspector/shell/originalPreview.d.ts +9 -0
  113. package/dist/inspector/shell/originalPreview.js +61 -0
  114. package/dist/inspector/shell/shortcuts.d.ts +3 -0
  115. package/dist/inspector/shell/shortcuts.js +15 -0
  116. package/dist/inspector/sketch/SketchChanges.d.ts +2 -0
  117. package/dist/inspector/sketch/SketchChanges.js +72 -0
  118. package/dist/inspector/sketch/SketchEditor.d.ts +21 -0
  119. package/dist/inspector/sketch/SketchEditor.js +402 -0
  120. package/dist/inspector/sketch/SketchEntryButton.d.ts +4 -0
  121. package/dist/inspector/sketch/SketchEntryButton.js +11 -0
  122. package/dist/inspector/sketch/SketchFrameOverlay.d.ts +11 -0
  123. package/dist/inspector/sketch/SketchFrameOverlay.js +119 -0
  124. package/dist/inspector/sketch/SketchLayersPanel.d.ts +2 -0
  125. package/dist/inspector/sketch/SketchLayersPanel.js +63 -0
  126. package/dist/inspector/sketch/SketchOverlay.d.ts +19 -0
  127. package/dist/inspector/sketch/SketchOverlay.js +420 -0
  128. package/dist/inspector/sketch/SketchPromptPanel.d.ts +15 -0
  129. package/dist/inspector/sketch/SketchPromptPanel.js +18 -0
  130. package/dist/inspector/sketch/SketchWorkspace.d.ts +13 -0
  131. package/dist/inspector/sketch/SketchWorkspace.js +152 -0
  132. package/dist/inspector/sketch/capture.d.ts +55 -0
  133. package/dist/inspector/sketch/capture.js +350 -0
  134. package/dist/inspector/sketch/freehand.d.ts +13 -0
  135. package/dist/inspector/sketch/freehand.js +64 -0
  136. package/dist/inspector/sketch/geometry.d.ts +17 -0
  137. package/dist/inspector/sketch/geometry.js +98 -0
  138. package/dist/inspector/sketch/handoff.d.ts +21 -0
  139. package/dist/inspector/sketch/handoff.js +72 -0
  140. package/dist/inspector/sketch/interaction.d.ts +21 -0
  141. package/dist/inspector/sketch/interaction.js +98 -0
  142. package/dist/inspector/sketch/model.d.ts +104 -0
  143. package/dist/inspector/sketch/model.js +282 -0
  144. package/dist/inspector/sketch/persistence.d.ts +21 -0
  145. package/dist/inspector/sketch/persistence.js +205 -0
  146. package/dist/inspector/sketch/raster.d.ts +22 -0
  147. package/dist/inspector/sketch/raster.js +203 -0
  148. package/dist/inspector/sketch/sketchNote.d.ts +10 -0
  149. package/dist/inspector/sketch/sketchNote.js +30 -0
  150. package/dist/inspector/sketch/store.d.ts +47 -0
  151. package/dist/inspector/sketch/store.js +409 -0
  152. package/dist/inspector/styleEditors/BorderEditor.js +15 -19
  153. package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -6
  154. package/dist/inspector/styleEditors/BoxShadowEditor.js +12 -1
  155. package/dist/inspector/styleEditors/ColorPicker.js +11 -36
  156. package/dist/inspector/styleEditors/GapField.d.ts +3 -2
  157. package/dist/inspector/styleEditors/GapField.js +2 -2
  158. package/dist/inspector/styleEditors/GridSection.js +1 -1
  159. package/dist/inspector/styleEditors/LayoutSection.js +11 -8
  160. package/dist/inspector/styleEditors/SpacingBox.js +23 -30
  161. package/dist/inspector/styleEditors/layoutPreviewState.d.ts +5 -0
  162. package/dist/inspector/styleEditors/layoutPreviewState.js +19 -0
  163. package/dist/inspector/styleEditors/layoutValue.js +3 -0
  164. package/dist/inspector/styleEditors/nudgeValue.d.ts +11 -0
  165. package/dist/inspector/styleEditors/nudgeValue.js +91 -5
  166. package/dist/inspector/styleEditors/stylePresence.d.ts +7 -0
  167. package/dist/inspector/styleEditors/stylePresence.js +22 -0
  168. package/dist/inspector/styleEditors/textRelevance.d.ts +3 -0
  169. package/dist/inspector/styleEditors/textRelevance.js +35 -0
  170. package/dist/inspector/styleEditors/useFieldVisibility.d.ts +6 -0
  171. package/dist/inspector/styleEditors/useFieldVisibility.js +26 -0
  172. package/dist/inspector/tokens/TokenField.js +111 -7
  173. package/dist/inspector/tokens/editActions.d.ts +2 -0
  174. package/dist/inspector/tokens/editActions.js +2 -2
  175. package/dist/inspector/tokens/resolution/cssomCollector.d.ts +1 -1
  176. package/dist/inspector/tokens/resolution/cssomCollector.js +9 -5
  177. package/dist/inspector/tokens/resolution/ruleMatching.d.ts +40 -0
  178. package/dist/inspector/tokens/resolution/ruleMatching.js +423 -0
  179. package/dist/inspector/tokens/resolution/selectorSemantics.d.ts +19 -3
  180. package/dist/inspector/tokens/resolution/selectorSemantics.js +378 -4
  181. package/dist/inspector/tokens/resolution.d.ts +3 -26
  182. package/dist/inspector/tokens/resolution.js +44 -735
  183. package/dist/inspector/tokens/tokenAvailability.d.ts +18 -0
  184. package/dist/inspector/tokens/tokenAvailability.js +204 -0
  185. package/dist/inspector/ui/Button.d.ts +1 -1
  186. package/dist/inspector/ui/SideValuesField.js +2 -2
  187. package/dist/inspector/ui/StatusCallout.d.ts +4 -1
  188. package/dist/inspector/ui/StatusCallout.js +2 -2
  189. package/dist/inspector/ui/styles.js +13 -11
  190. package/dist/internal/agent-protocol.d.ts +65 -1
  191. package/dist/internal/agent-protocol.js +183 -3
  192. package/dist/nudge-ui.mjs +261 -57
  193. package/dist/transport/editor.d.ts +28 -0
  194. package/dist/transport/editor.js +132 -0
  195. package/dist/transport/index.d.ts +1 -0
  196. package/dist/transport/index.js +1 -0
  197. package/dist/transport/routes.d.ts +7 -0
  198. package/dist/transport/routes.js +7 -0
  199. package/package.json +3 -1
  200. package/dist/inspector/shell/panelLayout.d.ts +0 -2
  201. 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";
@@ -61,6 +61,16 @@ function formatNumber(value) {
61
61
  function stripCssUnit(value) {
62
62
  return value.replace(/^(-?\d+(?:\.\d+)?)(px|rem|em|vh|vw|vmin|vmax|%|ch|ex|cm|mm|in|pt|pc)$/i, "$1");
63
63
  }
64
+ function releasePointerCapture(state) {
65
+ try {
66
+ if (state.handle.hasPointerCapture?.(state.pointerId)) {
67
+ state.handle.releasePointerCapture(state.pointerId);
68
+ }
69
+ }
70
+ catch {
71
+ // The browser may release capture before pointerup/pointercancel arrives.
72
+ }
73
+ }
64
74
  /** Returns the first family in a CSS family list without splitting var() fallbacks. */
65
75
  function primaryFontFamily(value) {
66
76
  let depth = 0;
@@ -138,8 +148,9 @@ function browserRecognizesColor(value) {
138
148
  function NativeColorSwatch({ value, onChange, disabled, }) {
139
149
  const resolvedHex = colorValueToHex(value);
140
150
  const hex = resolvedHex ?? "#000000";
141
- const hasRenderableColor = resolvedHex !== null || browserRecognizesColor(value);
142
- return (_jsxs("label", { className: "token-color-control", "data-resolved": hasRenderableColor ? "true" : "false", children: [_jsx(ColorSwatch, { color: resolvedHex ?? (value.trim() || "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) })] }));
151
+ const cssColor = browserRecognizesColor(value) ? value.trim() : resolvedHex;
152
+ const hasRenderableColor = cssColor !== null;
153
+ 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
154
  }
144
155
  export function TokenValueField(props) {
145
156
  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 +175,8 @@ export function TokenValueField(props) {
164
175
  const selectedFromPopover = useRef(false);
165
176
  const cancelOnBlur = useRef(false);
166
177
  const isNavigatingSuggestions = useRef(false);
178
+ const dragNudgeRef = useRef(null);
179
+ const [isDraggingNudge, setIsDraggingNudge] = useState(false);
167
180
  useEffect(() => {
168
181
  setRawValue(committedValue);
169
182
  setActiveTokenName(controlledTokenName);
@@ -301,6 +314,89 @@ export function TokenValueField(props) {
301
314
  inputRef.current?.blur();
302
315
  }
303
316
  }
317
+ const stopDragNudge = useCallback(() => {
318
+ const drag = dragNudgeRef.current;
319
+ if (!drag)
320
+ return;
321
+ releasePointerCapture(drag);
322
+ dragNudgeRef.current = null;
323
+ setIsDraggingNudge(false);
324
+ }, []);
325
+ useEffect(() => {
326
+ const stopOnWindowBlur = () => stopDragNudge();
327
+ window.addEventListener("blur", stopOnWindowBlur);
328
+ return () => {
329
+ window.removeEventListener("blur", stopOnWindowBlur);
330
+ stopDragNudge();
331
+ };
332
+ }, [stopDragNudge]);
333
+ function handleDragNudgePointerDown(event) {
334
+ if (disabled || !supportsDragNudge(property))
335
+ return;
336
+ if (!canNudgeCssValueByDrag(property, rawValue))
337
+ return;
338
+ stopDragNudge();
339
+ const handle = event.currentTarget;
340
+ const drag = {
341
+ handle,
342
+ pointerId: event.pointerId,
343
+ lastClientX: event.clientX,
344
+ deltaX: 0,
345
+ startValue: rawValue,
346
+ lastValue: rawValue,
347
+ shiftActive: event.shiftKey,
348
+ shiftSnapPending: event.shiftKey,
349
+ };
350
+ dragNudgeRef.current = drag;
351
+ if (typeof handle.setPointerCapture === "function")
352
+ handle.setPointerCapture(event.pointerId);
353
+ setIsDraggingNudge(true);
354
+ event.preventDefault();
355
+ event.stopPropagation();
356
+ }
357
+ function handleDragNudgePointerMove(event) {
358
+ const drag = dragNudgeRef.current;
359
+ if (!drag || drag.pointerId !== event.pointerId)
360
+ return;
361
+ const movementX = event.clientX - drag.lastClientX;
362
+ drag.lastClientX = event.clientX;
363
+ if (event.shiftKey !== drag.shiftActive) {
364
+ drag.shiftActive = event.shiftKey;
365
+ drag.startValue = drag.lastValue;
366
+ drag.deltaX = 0;
367
+ drag.shiftSnapPending = event.shiftKey;
368
+ }
369
+ drag.deltaX += movementX;
370
+ const next = nudgeCssValueByDrag(property, drag.startValue, drag.deltaX, drag.shiftActive, drag.shiftActive && drag.shiftSnapPending);
371
+ if (next === null || next === drag.lastValue)
372
+ return;
373
+ drag.lastValue = next;
374
+ if (drag.shiftActive && drag.shiftSnapPending) {
375
+ drag.startValue = next;
376
+ drag.deltaX = 0;
377
+ drag.shiftSnapPending = false;
378
+ }
379
+ event.preventDefault();
380
+ event.stopPropagation();
381
+ setRawValue(next);
382
+ setActiveTokenName(null);
383
+ onCommitRaw(next);
384
+ }
385
+ function handleDragNudgePointerEnd(event) {
386
+ if (dragNudgeRef.current?.pointerId !== event.pointerId)
387
+ return;
388
+ stopDragNudge();
389
+ }
390
+ function renderLeading() {
391
+ if (!leading)
392
+ return null;
393
+ const canDrag = !disabled
394
+ && supportsDragNudge(property)
395
+ && canNudgeCssValueByDrag(property, rawValue);
396
+ if (!canDrag)
397
+ return _jsx("span", { className: "token-field__leading", children: leading });
398
+ 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 }));
399
+ }
304
400
  function commitOpacityValue(value = opacityValue) {
305
401
  if (!showOpacity || !onCommitOpacity)
306
402
  return;
@@ -343,12 +439,12 @@ export function TokenValueField(props) {
343
439
  if (activeToken) {
344
440
  const chipValue = chipVariant === "small" ? stripCssUnit(activeToken.value) : activeToken.name;
345
441
  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: [leading ? _jsx("span", { className: "token-field__leading", children: leading }) : null, 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) => {
442
+ 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
443
  handleSuggestionSelect(value);
348
444
  } }), _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
445
  }
350
446
  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: [leading ? _jsx("span", { className: "token-field__leading", children: leading }) : null, colorControlEl, _jsx(PopoverListbox, { query: rawValue, value: null, open: showPopover, placeholder: property, inputRef: inputRef, inputAppearance: "embedded", inputDataTest: inputDataTest, inputOnFocus: () => {
447
+ 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
448
  setIsFocused(true);
353
449
  if (mixed && rawValue.trim().toLowerCase() === "mixed")
354
450
  setRawValue("");
@@ -417,7 +513,15 @@ export function TokenField(props) {
417
513
  const currentToken = activeTokenName
418
514
  ? entries.find((entry) => entry.name === activeTokenName) ?? null
419
515
  : null;
420
- return (_jsx(TokenValueField, { property: property, domElement: el, semanticSlot: semanticSlot, committedValue: committedValue, resolvedValue: tokenRow?.propertyOpacity?.value ?? tokenRow?.resolvedValue ?? committedValue, activeTokenName: activeTokenName, attributionTokens: attributionTokens
516
+ let resolvedValue = tokenRow?.propertyOpacity?.value ?? tokenRow?.resolvedValue ?? committedValue;
517
+ if (property === "background-color") {
518
+ // Background rows can contain the complete computed shorthand. Extract
519
+ // its color before passing it to the color control, preserving alpha.
520
+ const style = el.ownerDocument.createElement("span").style;
521
+ style.background = resolvedValue;
522
+ resolvedValue = style.backgroundColor || resolvedValue;
523
+ }
524
+ return (_jsx(TokenValueField, { property: property, domElement: el, semanticSlot: semanticSlot, committedValue: committedValue, resolvedValue: resolvedValue, activeTokenName: activeTokenName, attributionTokens: attributionTokens
421
525
  ?? (selectedProperty?.token.kind === "mixed" ? ["Mixed tokens"] : undefined)
422
526
  ?? (expression
423
527
  ? tokenRow?.tokens?.filter((token) => token.name !== tokenRow.opacity?.tokenName).map((token) => token.name)
@@ -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 tokens/resolution.ts
58
- // (stableTokenCache, stateResolutionSnapshots, tokenEntriesCache,
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 {};