nudge-ui 0.2.1 → 0.2.3

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 (258) hide show
  1. package/README.md +164 -46
  2. package/dist/client.mjs +252 -54
  3. package/dist/css/value-semantics/colorSemantics.d.ts +4 -0
  4. package/dist/css/value-semantics/colorSemantics.js +17 -0
  5. package/dist/hosts/astro/astroRuntimeConfig.js +1 -0
  6. package/dist/hosts/astro/clientTransport.js +41 -32
  7. package/dist/hosts/astro/integration.d.ts +2 -2
  8. package/dist/hosts/astro/integration.js +9 -4
  9. package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
  10. package/dist/hosts/astro/markdownIdentity.js +81 -0
  11. package/dist/hosts/environment.d.ts +15 -0
  12. package/dist/hosts/environment.js +16 -0
  13. package/dist/hosts/next/manifest.js +1 -1
  14. package/dist/hosts/next/sidecar.js +12 -2
  15. package/dist/hosts/next/wrapper.d.ts +2 -0
  16. package/dist/hosts/next/wrapper.js +2 -1
  17. package/dist/hosts/projectBridge.d.ts +1 -0
  18. package/dist/hosts/projectBridge.js +1 -0
  19. package/dist/hosts/static/manifest.js +3 -1
  20. package/dist/hosts/static/server.js +4 -0
  21. package/dist/hosts/vite/vite.d.ts +4 -0
  22. package/dist/hosts/vite/vite.js +28 -5
  23. package/dist/inspector/agent/McpConnectionDialog.d.ts +3 -2
  24. package/dist/inspector/agent/McpConnectionDialog.js +23 -22
  25. package/dist/inspector/agent/activity.d.ts +18 -0
  26. package/dist/inspector/agent/activity.js +70 -0
  27. package/dist/inspector/agent/client.d.ts +8 -0
  28. package/dist/inspector/agent/client.js +65 -5
  29. package/dist/inspector/agent/connectionStatus.d.ts +3 -3
  30. package/dist/inspector/agent/connectionStatus.js +9 -2
  31. package/dist/inspector/agent/httpTransport.d.ts +6 -0
  32. package/dist/inspector/agent/httpTransport.js +50 -3
  33. package/dist/inspector/agent/protocol.d.ts +9 -3
  34. package/dist/inspector/agent/protocol.js +1 -1
  35. package/dist/inspector/agent/verification.d.ts +11 -1
  36. package/dist/inspector/agent/verification.js +53 -25
  37. package/dist/inspector/canvas/AgentActivityOverlay.d.ts +13 -0
  38. package/dist/inspector/canvas/AgentActivityOverlay.js +111 -0
  39. package/dist/inspector/canvas/CanvasCard.d.ts +9 -2
  40. package/dist/inspector/canvas/CanvasCard.js +133 -38
  41. package/dist/inspector/canvas/CanvasElementOverlay.js +200 -22
  42. package/dist/inspector/canvas/CanvasToolIcons.d.ts +10 -0
  43. package/dist/inspector/canvas/CanvasToolIcons.js +20 -0
  44. package/dist/inspector/canvas/CanvasToolbar.js +8 -4
  45. package/dist/inspector/canvas/CanvasWorkspace.js +243 -56
  46. package/dist/inspector/canvas/StaleChangeIndicator.js +3 -13
  47. package/dist/inspector/canvas/agentPresentation.d.ts +8 -8
  48. package/dist/inspector/canvas/agentPresentation.js +64 -52
  49. package/dist/inspector/canvas/canvasGestures.d.ts +1 -1
  50. package/dist/inspector/canvas/canvasGestures.js +1 -1
  51. package/dist/inspector/canvas/canvasStore.d.ts +46 -82
  52. package/dist/inspector/canvas/canvasStore.js +251 -284
  53. package/dist/inspector/canvas/frameContent.d.ts +21 -0
  54. package/dist/inspector/canvas/frameContent.js +44 -0
  55. package/dist/inspector/canvas/frameProtocol.d.ts +34 -4
  56. package/dist/inspector/canvas/frameProtocol.js +9 -2
  57. package/dist/inspector/canvas/keyboardShortcuts.d.ts +4 -1
  58. package/dist/inspector/canvas/keyboardShortcuts.js +5 -3
  59. package/dist/inspector/canvas/layout.d.ts +52 -0
  60. package/dist/inspector/canvas/layout.js +106 -0
  61. package/dist/inspector/canvas/linkEligibility.d.ts +0 -5
  62. package/dist/inspector/canvas/linkEligibility.js +0 -29
  63. package/dist/inspector/canvas/projection.d.ts +15 -5
  64. package/dist/inspector/canvas/projection.js +69 -13
  65. package/dist/inspector/canvas/rendererBootstrap.js +45 -4
  66. package/dist/inspector/canvas/rendererElementSelector.d.ts +1 -1
  67. package/dist/inspector/canvas/rendererElementSelector.js +102 -45
  68. package/dist/inspector/canvas/rendererStylesheet.js +2 -2
  69. package/dist/inspector/canvas/resizeHandleScale.js +1 -1
  70. package/dist/inspector/canvas/sessionStore.d.ts +11 -26
  71. package/dist/inspector/canvas/sessionStore.js +43 -183
  72. package/dist/inspector/canvas/staleChangeDetector.js +9 -3
  73. package/dist/inspector/canvas/useCanvasLayoutAnimation.d.ts +5 -0
  74. package/dist/inspector/canvas/useCanvasLayoutAnimation.js +107 -0
  75. package/dist/inspector/canvas/viewStore.d.ts +38 -0
  76. package/dist/inspector/canvas/viewStore.js +104 -0
  77. package/dist/inspector/canvas/wheelPan.d.ts +8 -0
  78. package/dist/inspector/canvas/wheelPan.js +8 -0
  79. package/dist/inspector/changes/changesLog.d.ts +6 -5
  80. package/dist/inspector/changes/changesLog.js +40 -32
  81. package/dist/inspector/changes/draftChanges.d.ts +56 -0
  82. package/dist/inspector/changes/draftChanges.js +300 -0
  83. package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
  84. package/dist/inspector/changes/previewDiagnostics.js +11 -25
  85. package/dist/inspector/clientManifest.d.ts +3 -1
  86. package/dist/inspector/clientManifest.js +1 -0
  87. package/dist/inspector/comments/CommentsOverlay.d.ts +2 -0
  88. package/dist/inspector/comments/CommentsOverlay.js +250 -0
  89. package/dist/inspector/comments/element.d.ts +6 -0
  90. package/dist/inspector/comments/element.js +47 -0
  91. package/dist/inspector/comments/store.d.ts +29 -0
  92. package/dist/inspector/comments/store.js +121 -0
  93. package/dist/inspector/comments/verification.d.ts +5 -0
  94. package/dist/inspector/comments/verification.js +52 -0
  95. package/dist/inspector/drafts/model.d.ts +35 -0
  96. package/dist/inspector/drafts/model.js +45 -0
  97. package/dist/inspector/drafts/store.d.ts +28 -0
  98. package/dist/inspector/drafts/store.js +231 -0
  99. package/dist/inspector/index.js +26 -35
  100. package/dist/inspector/inline-text/inlineTextEditor.js +7 -0
  101. package/dist/inspector/inspection/useBrowserCssInspection.js +15 -1
  102. package/dist/inspector/iterations/capture.d.ts +2 -0
  103. package/dist/inspector/iterations/capture.js +173 -0
  104. package/dist/inspector/iterations/client.d.ts +7 -0
  105. package/dist/inspector/iterations/client.js +52 -0
  106. package/dist/inspector/iterations/coordinator.d.ts +15 -0
  107. package/dist/inspector/iterations/coordinator.js +130 -0
  108. package/dist/inspector/iterations/prompt.d.ts +3 -0
  109. package/dist/inspector/iterations/prompt.js +26 -0
  110. package/dist/inspector/overlay/DomNavigator.d.ts +10 -0
  111. package/dist/inspector/overlay/DomNavigator.js +46 -0
  112. package/dist/inspector/overlay/InspectorOverlay.js +6 -2
  113. package/dist/inspector/overlay/clickPolicy.d.ts +18 -2
  114. package/dist/inspector/overlay/clickPolicy.js +34 -3
  115. package/dist/inspector/overlay/elementSelector.d.ts +1 -1
  116. package/dist/inspector/overlay/elementSelector.js +18 -7
  117. package/dist/inspector/overlay/interactionStyles.js +3 -1
  118. package/dist/inspector/overlay/spacingGestures.d.ts +15 -3
  119. package/dist/inspector/overlay/spacingGestures.js +88 -13
  120. package/dist/inspector/projection/{workspaceProjection.d.ts → draftProjection.d.ts} +6 -6
  121. package/dist/inspector/projection/{workspaceProjection.js → draftProjection.js} +4 -4
  122. package/dist/inspector/projection/renderedInstance.d.ts +2 -1
  123. package/dist/inspector/projection/renderedInstance.js +9 -5
  124. package/dist/inspector/projection/structuralProjection.d.ts +2 -1
  125. package/dist/inspector/projection/structuralProjection.js +19 -15
  126. package/dist/inspector/projection/textProjection.d.ts +2 -1
  127. package/dist/inspector/projection/textProjection.js +8 -4
  128. package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
  129. package/dist/inspector/prompt/clipboardHandoff.d.ts +10 -18
  130. package/dist/inspector/prompt/clipboardHandoff.js +92 -143
  131. package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
  132. package/dist/inspector/prompt/generatePrompt.js +17 -16
  133. package/dist/inspector/runtime/runtimeConfig.d.ts +10 -1
  134. package/dist/inspector/runtime/runtimeConfig.js +24 -0
  135. package/dist/inspector/selection/hierarchy.d.ts +6 -0
  136. package/dist/inspector/selection/hierarchy.js +8 -0
  137. package/dist/inspector/settings/SettingsDialog.d.ts +1 -1
  138. package/dist/inspector/settings/SettingsDialog.js +22 -9
  139. package/dist/inspector/shell/AgentStatusButton.d.ts +11 -0
  140. package/dist/inspector/shell/AgentStatusButton.js +36 -0
  141. package/dist/inspector/shell/AppShell.js +4 -2
  142. package/dist/inspector/shell/ChangesLog.js +47 -27
  143. package/dist/inspector/shell/CopyPromptButton.js +146 -90
  144. package/dist/inspector/shell/EmptyState.js +9 -8
  145. package/dist/inspector/shell/InspectorShell.js +14 -25
  146. package/dist/inspector/shell/PeekOriginalButton.js +24 -23
  147. package/dist/inspector/shell/originalPreview.js +5 -5
  148. package/dist/inspector/shell/shortcuts.d.ts +3 -0
  149. package/dist/inspector/shell/shortcuts.js +11 -0
  150. package/dist/inspector/sketch/SketchEditor.js +14 -14
  151. package/dist/inspector/sketch/SketchEntryButton.js +1 -1
  152. package/dist/inspector/sketch/SketchFrameOverlay.d.ts +3 -1
  153. package/dist/inspector/sketch/SketchFrameOverlay.js +11 -8
  154. package/dist/inspector/sketch/SketchLayersPanel.js +13 -5
  155. package/dist/inspector/sketch/SketchOverlay.js +7 -7
  156. package/dist/inspector/sketch/SketchWorkspace.js +18 -12
  157. package/dist/inspector/sketch/interaction.d.ts +1 -0
  158. package/dist/inspector/sketch/interaction.js +8 -4
  159. package/dist/inspector/sketch/model.d.ts +5 -0
  160. package/dist/inspector/sketch/model.js +6 -2
  161. package/dist/inspector/sketch/raster.d.ts +1 -2
  162. package/dist/inspector/sketch/raster.js +68 -4
  163. package/dist/inspector/sketch/store.js +48 -23
  164. package/dist/inspector/styleEditors/BackgroundEditor.d.ts +4 -0
  165. package/dist/inspector/styleEditors/BackgroundEditor.js +195 -0
  166. package/dist/inspector/styleEditors/BorderEditor.js +49 -78
  167. package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -1
  168. package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +1 -2
  169. package/dist/inspector/styleEditors/BoxShadowEditor.js +132 -4
  170. package/dist/inspector/styleEditors/ColorPicker.d.ts +5 -1
  171. package/dist/inspector/styleEditors/ColorPicker.js +10 -4
  172. package/dist/inspector/styleEditors/GapField.js +3 -5
  173. package/dist/inspector/styleEditors/GridChildSection.d.ts +1 -1
  174. package/dist/inspector/styleEditors/GridChildSection.js +18 -9
  175. package/dist/inspector/styleEditors/GridPicker.d.ts +1 -1
  176. package/dist/inspector/styleEditors/GridPicker.js +8 -2
  177. package/dist/inspector/styleEditors/GridSection.js +1 -1
  178. package/dist/inspector/styleEditors/GridValueField.js +19 -14
  179. package/dist/inspector/styleEditors/ImageBackgroundEditor.d.ts +18 -0
  180. package/dist/inspector/styleEditors/ImageBackgroundEditor.js +118 -0
  181. package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +2 -2
  182. package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +3 -3
  183. package/dist/inspector/styleEditors/LayoutComboField.js +6 -4
  184. package/dist/inspector/styleEditors/LayoutDropdown.js +6 -3
  185. package/dist/inspector/styleEditors/LayoutSection.js +32 -11
  186. package/dist/inspector/styleEditors/SpacingBox.js +16 -9
  187. package/dist/inspector/styleEditors/Typography.js +11 -3
  188. package/dist/inspector/styleEditors/backgroundLayers.d.ts +24 -0
  189. package/dist/inspector/styleEditors/backgroundLayers.js +51 -0
  190. package/dist/inspector/styleEditors/gradientValue.d.ts +17 -0
  191. package/dist/inspector/styleEditors/gradientValue.js +114 -0
  192. package/dist/inspector/styleEditors/inlineAuthored.d.ts +10 -0
  193. package/dist/inspector/styleEditors/inlineAuthored.js +114 -0
  194. package/dist/inspector/styleEditors/layoutValue.d.ts +0 -8
  195. package/dist/inspector/styleEditors/layoutValue.js +0 -42
  196. package/dist/inspector/styleEditors/nudgeValue.d.ts +4 -4
  197. package/dist/inspector/styleEditors/nudgeValue.js +41 -11
  198. package/dist/inspector/tokens/TokenField.d.ts +7 -0
  199. package/dist/inspector/tokens/TokenField.js +49 -22
  200. package/dist/inspector/tokens/TokenLabel.js +5 -14
  201. package/dist/inspector/tokens/TokensPanel.js +2 -1
  202. package/dist/inspector/tokens/dragPointerLock.d.ts +8 -0
  203. package/dist/inspector/tokens/dragPointerLock.js +70 -0
  204. package/dist/inspector/tokens/editActions.d.ts +1 -1
  205. package/dist/inspector/tokens/editActions.js +1 -1
  206. package/dist/inspector/ui/AtRuleContext.js +4 -6
  207. package/dist/inspector/ui/Button.d.ts +6 -2
  208. package/dist/inspector/ui/Button.js +4 -3
  209. package/dist/inspector/ui/ControlSurface.d.ts +2 -2
  210. package/dist/inspector/ui/ControlSurface.js +4 -3
  211. package/dist/inspector/ui/Disclosure.d.ts +22 -0
  212. package/dist/inspector/ui/Disclosure.js +13 -0
  213. package/dist/inspector/ui/InlineStyleWarning.d.ts +11 -0
  214. package/dist/inspector/ui/InlineStyleWarning.js +13 -0
  215. package/dist/inspector/ui/InspectorPopover.d.ts +2 -1
  216. package/dist/inspector/ui/InspectorPopover.js +4 -5
  217. package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
  218. package/dist/inspector/ui/PopoverListbox.js +8 -7
  219. package/dist/inspector/ui/SegmentedControl.d.ts +2 -1
  220. package/dist/inspector/ui/SegmentedControl.js +2 -2
  221. package/dist/inspector/ui/Select.d.ts +6 -1
  222. package/dist/inspector/ui/Select.js +7 -11
  223. package/dist/inspector/ui/SideValuesField.js +1 -1
  224. package/dist/inspector/ui/Tooltip.d.ts +26 -0
  225. package/dist/inspector/ui/Tooltip.js +32 -0
  226. package/dist/inspector/ui/classNames.d.ts +2 -0
  227. package/dist/inspector/ui/classNames.js +4 -0
  228. package/dist/inspector/ui/customCursors.d.ts +23 -0
  229. package/dist/inspector/ui/customCursors.js +122 -0
  230. package/dist/inspector/ui/dragCursor.d.ts +6 -0
  231. package/dist/inspector/ui/dragCursor.js +13 -0
  232. package/dist/inspector/ui/portalContainer.d.ts +2 -0
  233. package/dist/inspector/ui/portalContainer.js +6 -0
  234. package/dist/inspector/ui/styles.js +34 -24
  235. package/dist/inspector/workspace/commands.d.ts +9 -0
  236. package/dist/inspector/workspace/commands.js +82 -0
  237. package/dist/inspector/workspace/controller.d.ts +4 -0
  238. package/dist/inspector/workspace/controller.js +66 -0
  239. package/dist/inspector/workspace/handoff.d.ts +42 -0
  240. package/dist/inspector/workspace/handoff.js +115 -0
  241. package/dist/inspector/workspace/timeline.d.ts +30 -0
  242. package/dist/inspector/workspace/timeline.js +108 -0
  243. package/dist/internal/agent-protocol.d.ts +19 -2
  244. package/dist/internal/agent-protocol.js +13 -0
  245. package/dist/nudge-ui.mjs +560 -299
  246. package/dist/project/artifacts.d.ts +13 -0
  247. package/dist/project/artifacts.js +253 -0
  248. package/dist/transport/artifacts.d.ts +8 -0
  249. package/dist/transport/artifacts.js +9 -0
  250. package/dist/transport/editor.d.ts +20 -1
  251. package/dist/transport/editor.js +44 -11
  252. package/dist/transport/routes.d.ts +6 -1
  253. package/dist/transport/routes.js +6 -1
  254. package/package.json +6 -2
  255. package/dist/inspector/changes/workspaceChanges.d.ts +0 -43
  256. package/dist/inspector/changes/workspaceChanges.js +0 -239
  257. package/dist/inspector/shell/DomNavigation.d.ts +0 -8
  258. package/dist/inspector/shell/DomNavigation.js +0 -30
@@ -11,6 +11,7 @@ import { projectInspectorValues, projectInspectorValuesForSelection, } from "../
11
11
  import { getStateStyleValue } from "../shell/stateValue.js";
12
12
  import { isZeroCssValue } from "./stylePresence.js";
13
13
  import { useFieldVisibility } from "./useFieldVisibility.js";
14
+ import { inlineBlockedBy } from "./inlineAuthored.js";
14
15
  export function SpacingBox(props) {
15
16
  const { element, selection, entries, tokenRows = [], onAfterEdit } = props;
16
17
  const el = element.domElement;
@@ -35,10 +36,11 @@ export function SpacingField({ property, projection: spacingProjection, domEleme
35
36
  const sideSlots = SIDE_NAMES.map((side) => {
36
37
  const icon = property === "padding" ? _jsx(PaddingSideIndicator, { side: side }) : _jsx(MarginSideIndicator, { side: side });
37
38
  const sideName = sideProperty(property, side);
39
+ const field = spacingProjection.fields[side];
38
40
  return {
39
41
  side,
40
42
  icon: null,
41
- control: (_jsx(TokenField, { property: sideName, selection: selection, tokenRow: findTokenRow(tokenRows, sideName), domElement: el, editTarget: editTarget, entries: entries, suggestions: suggestions, editMetadata: metadataFor(findTokenRow(tokenRows, sideName)), onAfterEdit: onAfterEdit, chipVariant: "small", leading: icon })),
43
+ control: (_jsx(TokenField, { property: sideName, selection: selection, tokenRow: findTokenRow(tokenRows, sideName), domElement: el, editTarget: editTarget, entries: entries, suggestions: suggestions, displayValue: isCalcValue(field.authoredValue) && field.value ? field.value : undefined, editMetadata: metadataFor(findTokenRow(tokenRows, sideName)), onAfterEdit: onAfterEdit, chipVariant: "small", leading: icon })),
42
44
  };
43
45
  });
44
46
  const hasSpacing = SIDE_NAMES.some((side) => {
@@ -51,9 +53,9 @@ export function SpacingField({ property, projection: spacingProjection, domEleme
51
53
  const pairSlots = pairDefinitions.map(({ axis, sideProperties }) => ({
52
54
  axis,
53
55
  icon: null,
54
- control: (_jsx(PairedTokenField, { displayProperty: `${property}-${axis}`, sideProperties: sideProperties, domElement: el, editTarget: editTarget, axisProjection: spacingProjection.axes[axis], entries: entries, suggestions: suggestions, onAfterEdit: onAfterEdit, chipVariant: "small", leading: _jsx(SpacingAxisIndicator, { property: property, axis: axis }) })),
56
+ control: (_jsx(PairedTokenField, { displayProperty: `${property}-${axis}`, sideProperties: sideProperties, domElement: el, editTarget: editTarget, selection: selection, axisProjection: spacingProjection.axes[axis], entries: entries, suggestions: suggestions, onAfterEdit: onAfterEdit, chipVariant: "small", leading: _jsx(SpacingAxisIndicator, { property: property, axis: axis }) })),
55
57
  }));
56
- return (_jsx(SideValuesField, { label: property, "data-test": property === "inset" ? "layout-inset" : `spacing-${property}`, "data-property": property, resetKey: el, pairedControls: pairSlots, showLabel: showLabel, empty: showEmptyState && !visibility.visible, onAdd: visibility.show, emptyAction: property === "inset" ? (_jsx(IconButton, { variant: "quiet", size: "default", "data-test": "add-inset", label: "Add Inset Values", title: "Add Inset Values", onClick: visibility.show, children: _jsx(IconPlus, { size: 16, "aria-hidden": "true" }) })) : undefined, sides: sideSlots }));
58
+ return (_jsx(SideValuesField, { label: property, "data-test": property === "inset" ? "layout-inset" : `spacing-${property}`, "data-property": property, resetKey: el, pairedControls: pairSlots, showLabel: showLabel, empty: showEmptyState && !visibility.visible, onAdd: visibility.show, emptyAction: property === "inset" ? (_jsx(IconButton, { variant: "quiet", size: "default", "data-test": "add-inset", label: "Add Inset Values", onClick: visibility.show, children: _jsx(IconPlus, { size: 16, "aria-hidden": "true" }) })) : undefined, sides: sideSlots }));
57
59
  }
58
60
  function sideProperty(property, side) {
59
61
  return property === "inset" ? side : `${property}-${side}`;
@@ -82,14 +84,15 @@ function SpacingAxisIndicator({ property, axis, }) {
82
84
  }
83
85
  return (_jsxs("svg", { className: "side-values__icon side-values__axis-icon", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [_jsx("rect", { x: "19", y: "6", width: "12", height: "14", rx: "2", transform: "rotate(90 19 6)", stroke: "currentColor", strokeWidth: "var(--icon-stroke-width)" }), _jsx("line", { x1: "19", y1: "2", x2: "5", y2: "2", stroke: "currentColor", strokeWidth: "var(--icon-stroke-width)", strokeLinecap: "round" }), _jsx("line", { x1: "19", y1: "22", x2: "5", y2: "22", stroke: "currentColor", strokeWidth: "var(--icon-stroke-width)", strokeLinecap: "round" })] }));
84
86
  }
85
- function PairedTokenField({ displayProperty, sideProperties, domElement: el, editTarget, axisProjection, entries, suggestions, onAfterEdit, chipVariant, leading, }) {
87
+ function PairedTokenField({ displayProperty, sideProperties, domElement: el, editTarget, selection, axisProjection, entries, suggestions, onAfterEdit, chipVariant, leading, }) {
86
88
  const row = pairTokenRow(displayProperty, axisProjection);
87
89
  const groupMixed = axisProjection.fields.some((field) => field.value === "Mixed");
88
90
  const valuesMatch = axisProjection.state === "shared" && !groupMixed;
89
91
  const expression = Boolean(row && (row.capability === "raw" || row.capability === "composite"
90
92
  || row.modifiers?.some((modifier) => modifier.kind === "alpha")));
91
93
  const calcAuthored = row?.authored ?? row?.declaredValue ?? "";
92
- const activeTokenName = !valuesMatch || expression || /\bcalc\s*\(/i.test(calcAuthored) ? null : row.tokenName;
94
+ const isCalcAuthored = isCalcValue(calcAuthored);
95
+ const activeTokenName = !valuesMatch || expression || isCalcAuthored ? null : row.tokenName;
93
96
  // Some browsers expose the used pixel size for horizontal auto margins.
94
97
  // Keep the authored keyword visible because replacing it with that transient
95
98
  // size would misrepresent the declaration and change the edit semantics.
@@ -98,7 +101,7 @@ function PairedTokenField({ displayProperty, sideProperties, domElement: el, edi
98
101
  : valuesMatch
99
102
  ? calcAuthored.trim().toLowerCase() === "auto"
100
103
  ? calcAuthored.trim()
101
- : expression ? row.authored || row.declaredValue || row.resolvedValue : row.resolvedValue
104
+ : isCalcAuthored ? row.resolvedValue : expression ? row.authored || row.declaredValue || row.resolvedValue : row.resolvedValue
102
105
  : axisProjection.fields.map(fieldDisplayValue).join(", ");
103
106
  const resolvedValue = valuesMatch
104
107
  ? row.resolvedValue
@@ -106,6 +109,7 @@ function PairedTokenField({ displayProperty, sideProperties, domElement: el, edi
106
109
  const currentToken = activeTokenName
107
110
  ? entries.find((entry) => entry.name === activeTokenName) ?? null
108
111
  : null;
112
+ const blockedBy = inlineBlockedBy(selection?.domElements ?? [el], ...sideProperties);
109
113
  function commitAxisValue(value) {
110
114
  const pair = splitAxisValue(value);
111
115
  const records = setStyles(editTarget ?? el, sideProperties.map((property, index) => ({
@@ -115,7 +119,7 @@ function PairedTokenField({ displayProperty, sideProperties, domElement: el, edi
115
119
  if (records.some(Boolean))
116
120
  onAfterEdit?.();
117
121
  }
118
- return (_jsx(TokenValueField, { property: displayProperty, committedValue: committedValue, resolvedValue: resolvedValue, activeTokenName: activeTokenName, mixed: groupMixed, atRules: row.atRuleCandidates ?? row.atRules, entries: entries, suggestions: suggestions, chipVariant: chipVariant, formatRawValue: (value) => formatAxisValue(value, displayProperty), onCommitRaw: commitAxisValue, onSelectToken: (chosen) => {
122
+ return (_jsx(TokenValueField, { property: displayProperty, domElement: el, committedValue: committedValue, resolvedValue: resolvedValue, activeTokenName: activeTokenName, mixed: groupMixed, atRules: row.atRuleCandidates ?? row.atRules, entries: entries, suggestions: suggestions, chipVariant: chipVariant, formatRawValue: (value) => formatAxisValue(value, displayProperty), onCommitRaw: commitAxisValue, onSelectToken: (chosen) => {
119
123
  const records = swapTokens(editTarget ?? el, sideProperties.map((property) => ({
120
124
  property,
121
125
  newToken: chosen,
@@ -123,10 +127,13 @@ function PairedTokenField({ displayProperty, sideProperties, domElement: el, edi
123
127
  })));
124
128
  if (records.some(Boolean))
125
129
  onAfterEdit?.();
126
- }, onUnlink: commitAxisValue, leading: leading }));
130
+ }, onUnlink: commitAxisValue, leading: leading, blockedBy: blockedBy }));
127
131
  }
128
132
  function fieldDisplayValue(field) {
129
- return field.authoredValue.trim() || field.value;
133
+ return isCalcValue(field.authoredValue) ? field.value : field.authoredValue.trim() || field.value;
134
+ }
135
+ function isCalcValue(value) {
136
+ return /\bcalc\s*\(/i.test(value);
130
137
  }
131
138
  function splitAxisValue(value) {
132
139
  let depth = 0;
@@ -9,6 +9,8 @@ import { getStateStyleValue } from "../shell/stateValue.js";
9
9
  import { setStyle, setStyles } from "../tokens/editActions.js";
10
10
  import { AtRuleIndicator, useFieldAtRules } from "../ui/AtRuleContext.js";
11
11
  import { ControlSurface } from "../ui/ControlSurface.js";
12
+ import { InlineStyleWarning } from "../ui/InlineStyleWarning.js";
13
+ import { inlineBlockedBy } from "./inlineAuthored.js";
12
14
  export function Typography(props) {
13
15
  const { element, selection, entries, tokenRows = [], onAfterEdit } = props;
14
16
  const el = element.domElement;
@@ -56,6 +58,7 @@ function FontStyleField({ element, elements, editTarget, fontStyleRow, fontWeigh
56
58
  const atRules = fontStyleRow?.atRuleCandidates ?? fontStyleRow?.atRules
57
59
  ?? fontWeightRow?.atRuleCandidates ?? fontWeightRow?.atRules
58
60
  ?? (fontStyleAtRules.length > 0 ? fontStyleAtRules : fontWeightAtRules);
61
+ const blockedBy = inlineBlockedBy(elements, "font-style", "font-weight");
59
62
  const readValue = () => readFontStyle(element);
60
63
  const values = elements.map(readFontStyle);
61
64
  const isMixed = values.some((value) => value.weight !== values[0]?.weight || value.style !== values[0]?.style);
@@ -72,6 +75,8 @@ function FontStyleField({ element, elements, editTarget, fontStyleRow, fontWeigh
72
75
  ? FONT_STYLE_OPTIONS
73
76
  : [...FONT_STYLE_OPTIONS, { value: currentKey, label: currentLabel, ...current }];
74
77
  function handleChange(value) {
78
+ if (blockedBy)
79
+ return;
75
80
  const option = options.find((candidate) => candidate.value === value);
76
81
  if (!option || option.value === "mixed" || !("weight" in option) || !("style" in option))
77
82
  return;
@@ -82,7 +87,7 @@ function FontStyleField({ element, elements, editTarget, fontStyleRow, fontWeigh
82
87
  ]);
83
88
  onAfterEdit?.();
84
89
  }
85
- return (_jsxs(ControlSurface, { className: "typography__field typography__field--font-style", "data-test": "typography-field", "data-property": "font-style", "aria-label": "Font style", title: "Font style", children: [_jsx("span", { className: "typography__field-icon", "aria-hidden": "true", children: _jsx(IconTypography, { size: "var(--icon-size-small)", stroke: 1.45 }) }), _jsx(Select, { appearance: "embedded", value: isMixed ? "mixed" : currentKey, options: options.map(({ value, label }) => ({ value, label })), onValueChange: handleChange, "data-test": "font-style-field" }), _jsx(AtRuleIndicator, { atRules: atRules })] }));
90
+ return (_jsxs(ControlSurface, { className: "typography__field typography__field--font-style", "data-test": "typography-field", "data-property": "font-style", "aria-label": "Font style", children: [_jsx("span", { className: "typography__field-icon", "aria-hidden": "true", children: _jsx(IconTypography, { size: "var(--icon-size-small)", stroke: 1.45 }) }), _jsx(Select, { appearance: "embedded", value: isMixed ? "mixed" : currentKey, options: options.map(({ value, label }) => ({ value, label })), onValueChange: handleChange, disabled: blockedBy !== null, "data-test": "font-style-field" }), _jsx(AtRuleIndicator, { atRules: atRules }), _jsx(InlineStyleWarning, { blockedBy: blockedBy })] }));
86
91
  }
87
92
  function readFontStyle(element) {
88
93
  return {
@@ -104,6 +109,7 @@ function formatCustomFontStyle(weight, style) {
104
109
  }
105
110
  function AlignmentField({ property, label, element, elements, editTarget, defaultValue, options, onAfterEdit }) {
106
111
  const atRules = useFieldAtRules(property);
112
+ const blockedBy = inlineBlockedBy(elements, property);
107
113
  const readValues = () => elements.map((target) => getStateStyleValue(target, property, defaultValue));
108
114
  const initialValues = readValues();
109
115
  const isMixed = initialValues.some((value) => value !== initialValues[0]);
@@ -115,16 +121,18 @@ function AlignmentField({ property, label, element, elements, editTarget, defaul
115
121
  setCurrent(values.some((value) => value !== values[0]) ? null : normalizeAlignment(property, next));
116
122
  }, [defaultValue, element, elements, property]);
117
123
  function handleChange(value) {
124
+ if (blockedBy)
125
+ return;
118
126
  setCurrent(value);
119
127
  setStyle(editTarget, property, value);
120
128
  onAfterEdit?.();
121
129
  }
122
- return (_jsxs("div", { className: "typography__alignment-field", children: [isMixed || current === null && elements.length > 1 ? (_jsx("span", { className: "typography__mixed", "data-test": `typography-mixed-${property}`, children: "Mixed" })) : null, _jsx(SegmentedControl, { value: current, "aria-label": label, "data-property": property, options: options.map((option) => ({
130
+ return (_jsxs("div", { className: "typography__alignment-field", children: [isMixed || current === null && elements.length > 1 ? (_jsx("span", { className: "typography__mixed", "data-test": `typography-mixed-${property}`, children: "Mixed" })) : null, _jsx(SegmentedControl, { value: current, "aria-label": label, "data-property": property, disabled: blockedBy !== null, options: options.map((option) => ({
123
131
  value: option.value,
124
132
  label: option.label,
125
133
  icon: option.icon,
126
134
  testId: `typography-align-${property}-${option.value}`,
127
- })), onChange: handleChange }), _jsx(AtRuleIndicator, { atRules: atRules })] }));
135
+ })), onChange: handleChange }), _jsx(AtRuleIndicator, { atRules: atRules }), _jsx(InlineStyleWarning, { blockedBy: blockedBy })] }));
128
136
  }
129
137
  function normalizeAlignment(property, value) {
130
138
  if (property !== "text-align")
@@ -0,0 +1,24 @@
1
+ import type { GradientValue } from "./gradientValue.js";
2
+ export type BackgroundMode = "solid" | "gradient" | "image";
3
+ export interface BackgroundLayer {
4
+ mode: BackgroundMode;
5
+ baseColor: boolean;
6
+ gradient?: GradientValue;
7
+ value: string;
8
+ blend: string;
9
+ size: string;
10
+ repeat: string;
11
+ position: string;
12
+ }
13
+ export declare const BACKGROUND_BLEND_MODES: {
14
+ value: string;
15
+ label: string;
16
+ }[];
17
+ export declare function backgroundMode(value: string): BackgroundMode;
18
+ export declare function newBackgroundLayer(): BackgroundLayer;
19
+ /** CSS repeats shorter background property lists to match the image count. */
20
+ export declare function readBackgroundLayers(read: (property: string, fallback: string) => string): BackgroundLayer[];
21
+ export declare function backgroundDeclarations(layers: BackgroundLayer[]): {
22
+ property: string;
23
+ value: string;
24
+ }[];
@@ -0,0 +1,51 @@
1
+ import { splitTopLevel } from "../../css/value-semantics/cssSyntax.js";
2
+ import { isEmptyColorValue } from "./ColorPicker.js";
3
+ export const BACKGROUND_BLEND_MODES = ["normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"]
4
+ .map((value) => ({ value, label: value.replace(/-/g, " ").replace(/^./, (letter) => letter.toUpperCase()) }));
5
+ export function backgroundMode(value) {
6
+ if (!value || value === "none")
7
+ return "solid";
8
+ return /(?:repeating-)?(?:linear|radial|conic)-gradient\(/.test(value) ? "gradient" : "image";
9
+ }
10
+ export function newBackgroundLayer() {
11
+ return { mode: "solid", baseColor: true, value: "#ffffff", blend: "normal", size: "auto", repeat: "repeat", position: "0% 0%" };
12
+ }
13
+ /** CSS repeats shorter background property lists to match the image count. */
14
+ export function readBackgroundLayers(read) {
15
+ const image = read("background-image", "none");
16
+ const images = image === "none" ? [] : splitTopLevel(image, ",").map((value) => value.trim());
17
+ const listValue = (property, fallback, index) => {
18
+ const values = splitTopLevel(read(property, fallback), ",");
19
+ return values[index % values.length]?.trim() || fallback;
20
+ };
21
+ const layers = images.map((value, index) => {
22
+ const flat = /^linear-gradient\((.*)\)$/s.exec(value);
23
+ const colors = flat ? splitTopLevel(flat[1], ",").map((color) => color.trim()) : [];
24
+ const solid = colors.length === 2 && colors[0] === colors[1];
25
+ return {
26
+ mode: solid ? "solid" : backgroundMode(value),
27
+ baseColor: false,
28
+ value: solid ? colors[0] : value,
29
+ blend: listValue("background-blend-mode", "normal", index),
30
+ size: listValue("background-size", "auto", index),
31
+ repeat: listValue("background-repeat", "repeat", index),
32
+ position: listValue("background-position", "0% 0%", index),
33
+ };
34
+ });
35
+ const color = read("background-color", "transparent");
36
+ if (!isEmptyColorValue(color))
37
+ layers.push({ ...newBackgroundLayer(), value: color });
38
+ return layers;
39
+ }
40
+ export function backgroundDeclarations(layers) {
41
+ const base = layers.at(-1)?.mode === "solid" && layers.at(-1)?.baseColor ? layers.at(-1) : undefined;
42
+ const images = base ? layers.slice(0, -1) : layers;
43
+ return [
44
+ { property: "background-color", value: base?.value ?? "transparent" },
45
+ { property: "background-image", value: images.map((layer) => layer.mode === "solid" ? `linear-gradient(${layer.value}, ${layer.value})` : layer.value).join(", ") || "none" },
46
+ ...["blend", "size", "repeat", "position"].map((field) => ({
47
+ property: field === "blend" ? "background-blend-mode" : `background-${field}`,
48
+ value: images.map((layer) => layer[field]).join(", ") || newBackgroundLayer()[field],
49
+ })),
50
+ ];
51
+ }
@@ -0,0 +1,17 @@
1
+ export type GradientType = "linear" | "radial" | "conic";
2
+ export interface GradientStop {
3
+ color: string;
4
+ position: number;
5
+ }
6
+ export interface GradientValue {
7
+ type: GradientType;
8
+ repeating: boolean;
9
+ angle: number;
10
+ /** Preserve the computed shape, origin, and interpolation method. */
11
+ prelude: string;
12
+ stops: GradientStop[];
13
+ }
14
+ export declare function defaultGradient(): GradientValue;
15
+ /** Parse editable computed gradients. Leave unsupported syntax in the CSS field. */
16
+ export declare function parseGradient(value: string): GradientValue | null;
17
+ export declare function serializeGradient(gradient: GradientValue): string;
@@ -0,0 +1,114 @@
1
+ import { splitTopLevel, splitTopLevelWhitespace } from "../../css/value-semantics/cssSyntax.js";
2
+ export function defaultGradient() {
3
+ return { type: "linear", repeating: false, angle: 90, prelude: "", stops: [
4
+ { color: "#dddddd", position: 0 }, { color: "#a4a4a4", position: 100 },
5
+ ] };
6
+ }
7
+ function angleDegrees(value) {
8
+ const match = /^([+-]?(?:\d*\.)?\d+)(deg|grad|rad|turn)$/.exec(value);
9
+ if (!match)
10
+ return null;
11
+ const number = Number(match[1]);
12
+ switch (match[2]) {
13
+ case "grad": return number * 0.9;
14
+ case "rad": return number * 180 / Math.PI;
15
+ case "turn": return number * 360;
16
+ default: return number;
17
+ }
18
+ }
19
+ /** Parse editable computed gradients. Leave unsupported syntax in the CSS field. */
20
+ export function parseGradient(value) {
21
+ if (splitTopLevel(value, ",").length !== 1)
22
+ return null;
23
+ const match = /^(repeating-)?(linear|radial|conic)-gradient\((.*)\)$/s.exec(value.trim());
24
+ if (!match)
25
+ return null;
26
+ const type = match[2];
27
+ const parts = splitTopLevel(match[3], ",").map((part) => part.trim());
28
+ let prelude = "";
29
+ let angle = type === "linear" ? 180 : 0;
30
+ const first = parts[0] ?? "";
31
+ if (/^(?:to\s|[+-]?(?:\d*\.)?\d+(?:deg|grad|rad|turn)\b|circle\b|ellipse\b|closest-|farthest-|at\s|from\s|in\s)/.test(first)
32
+ || (type === "radial" && /\b(?:px|%)\b/.test(first))) {
33
+ prelude = parts.shift();
34
+ if (type === "linear") {
35
+ const direction = /^(to\s+(?:(?:left|right|top|bottom)(?:\s+|$)){1,2})/.exec(prelude)?.[0]?.trim();
36
+ if (direction) {
37
+ const directions = { top: 0, "top right": 45, "right top": 45, right: 90, "bottom right": 135, "right bottom": 135, bottom: 180, "bottom left": 225, "left bottom": 225, left: 270, "top left": 315, "left top": 315 };
38
+ // Corner directions depend on the element's aspect ratio. Keep them as CSS.
39
+ if (direction.slice(3).includes(" "))
40
+ return null;
41
+ angle = directions[direction.slice(3)] ?? 180;
42
+ prelude = prelude.slice(direction.length).trim();
43
+ }
44
+ else if (!prelude.startsWith("in ")) {
45
+ const rawAngle = splitTopLevelWhitespace(prelude)[0];
46
+ const parsed = angleDegrees(rawAngle);
47
+ if (parsed === null)
48
+ return null;
49
+ angle = parsed;
50
+ prelude = prelude.slice(rawAngle.length).trim();
51
+ }
52
+ }
53
+ else if (type === "conic" && prelude.startsWith("from ")) {
54
+ const rawAngle = splitTopLevelWhitespace(prelude)[1];
55
+ const parsed = angleDegrees(rawAngle);
56
+ if (parsed === null)
57
+ return null;
58
+ angle = parsed;
59
+ prelude = prelude.slice(5 + rawAngle.length).trim();
60
+ }
61
+ }
62
+ const stops = [];
63
+ for (const part of parts) {
64
+ const words = splitTopLevelWhitespace(part);
65
+ const positions = [];
66
+ while (words.length > 1) {
67
+ const last = words[words.length - 1];
68
+ const percent = /^([+-]?(?:\d*\.)?\d+)%$/.exec(last);
69
+ const degrees = type === "conic" ? angleDegrees(last) : null;
70
+ if (!percent && degrees === null && last !== "0")
71
+ break;
72
+ positions.unshift(percent ? Number(percent[1]) : degrees !== null ? degrees / 3.6 : 0);
73
+ words.pop();
74
+ }
75
+ const color = words.join(" ");
76
+ // Length stops and color hints cannot be represented by a percentage slider.
77
+ if (!color || words.length !== 1 || /^([+-]?\d|calc\(|var\()/i.test(color) || positions.length > 2)
78
+ return null;
79
+ if (positions.length)
80
+ positions.forEach((position) => stops.push({ color, position }));
81
+ else
82
+ stops.push({ color, position: null });
83
+ }
84
+ if (stops.length < 2)
85
+ return null;
86
+ stops[0].position ??= 0;
87
+ stops[stops.length - 1].position ??= 100;
88
+ let previous = stops[0].position;
89
+ for (const stop of stops) {
90
+ if (stop.position !== null) {
91
+ stop.position = Math.max(previous, stop.position);
92
+ previous = stop.position;
93
+ }
94
+ }
95
+ let start = 0;
96
+ while (start < stops.length - 1) {
97
+ let end = start + 1;
98
+ while (stops[end].position === null)
99
+ end++;
100
+ for (let index = start + 1; index < end; index++) {
101
+ stops[index].position = stops[start].position + (stops[end].position - stops[start].position) * (index - start) / (end - start);
102
+ }
103
+ start = end;
104
+ }
105
+ return { type, repeating: Boolean(match[1]), angle, prelude, stops: stops };
106
+ }
107
+ export function serializeGradient(gradient) {
108
+ const prefix = gradient.type === "linear" ? `${gradient.angle}deg`
109
+ : gradient.type === "conic" ? `from ${gradient.angle}deg` : "";
110
+ const prelude = [prefix, gradient.prelude].filter(Boolean).join(" ");
111
+ const stops = [...gradient.stops].sort((a, b) => a.position - b.position)
112
+ .map((stop) => `${stop.color} ${Number(stop.position.toFixed(3))}%`).join(", ");
113
+ return `${gradient.repeating ? "repeating-" : ""}${gradient.type}-gradient(${prelude ? `${prelude}, ` : ""}${stops})`;
114
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Returns the inline-authored source when `el` carries the property — or a
3
+ * shorthand that sets it — in its `style` attribute. Managed previews can
4
+ * never beat inline styles in the cascade, so a non-null result means the
5
+ * field must present as blocked instead of accepting edits that silently
6
+ * revert (see `verifyPreview`'s "inline-style" conflict).
7
+ */
8
+ export declare function inlineAuthoredValue(el: HTMLElement, property: string): string | null;
9
+ /** First inline-authored source that blocks any of `properties` on any of `elements`. */
10
+ export declare function inlineBlockedBy(elements: readonly HTMLElement[], ...properties: readonly string[]): string | null;
@@ -0,0 +1,114 @@
1
+ import { isLayoutPreview } from "./layoutPreviewState.js";
2
+ /**
3
+ * Shorthands that also author the keyed longhand when present in a `style`
4
+ * attribute. Managed-stylesheet previews lose the cascade to any of these,
5
+ * so fields must treat the longhand as inline-blocked either way.
6
+ */
7
+ const SHORTHAND_SOURCES = {
8
+ "font-family": ["font"],
9
+ "font-style": ["font"],
10
+ "font-weight": ["font"],
11
+ "font-size": ["font"],
12
+ "line-height": ["font"],
13
+ "background-color": ["background"],
14
+ "background-image": ["background"],
15
+ "row-gap": ["gap"],
16
+ "column-gap": ["gap"],
17
+ "flex-grow": ["flex"],
18
+ "flex-shrink": ["flex"],
19
+ "flex-basis": ["flex"],
20
+ "flex-direction": ["flex-flow"],
21
+ "flex-wrap": ["flex-flow"],
22
+ "align-content": ["place-content"],
23
+ "justify-content": ["place-content"],
24
+ "align-items": ["place-items"],
25
+ "justify-items": ["place-items"],
26
+ "align-self": ["place-self"],
27
+ "justify-self": ["place-self"],
28
+ "border-width": ["border"],
29
+ "border-style": ["border"],
30
+ "border-color": ["border"],
31
+ "border-top-left-radius": ["border-radius"],
32
+ "border-top-right-radius": ["border-radius"],
33
+ "border-bottom-right-radius": ["border-radius"],
34
+ "border-bottom-left-radius": ["border-radius"],
35
+ "border-top-width": ["border-top", "border-width", "border"],
36
+ "border-right-width": ["border-right", "border-width", "border"],
37
+ "border-bottom-width": ["border-bottom", "border-width", "border"],
38
+ "border-left-width": ["border-left", "border-width", "border"],
39
+ "border-top-style": ["border-top", "border-style", "border"],
40
+ "border-right-style": ["border-right", "border-style", "border"],
41
+ "border-bottom-style": ["border-bottom", "border-style", "border"],
42
+ "border-left-style": ["border-left", "border-style", "border"],
43
+ "border-top-color": ["border-top", "border-color", "border"],
44
+ "border-right-color": ["border-right", "border-color", "border"],
45
+ "border-bottom-color": ["border-bottom", "border-color", "border"],
46
+ "border-left-color": ["border-left", "border-color", "border"],
47
+ "margin-top": ["margin", "margin-block", "margin-block-start", "margin-block-end"],
48
+ "margin-right": ["margin", "margin-inline", "margin-inline-start", "margin-inline-end"],
49
+ "margin-bottom": ["margin", "margin-block", "margin-block-start", "margin-block-end"],
50
+ "margin-left": ["margin", "margin-inline", "margin-inline-start", "margin-inline-end"],
51
+ "padding-top": ["padding", "padding-block", "padding-block-start", "padding-block-end"],
52
+ "padding-right": ["padding", "padding-inline", "padding-inline-start", "padding-inline-end"],
53
+ "padding-bottom": ["padding", "padding-block", "padding-block-start", "padding-block-end"],
54
+ "padding-left": ["padding", "padding-inline", "padding-inline-start", "padding-inline-end"],
55
+ top: ["inset", "inset-block", "inset-block-start", "inset-block-end"],
56
+ right: ["inset", "inset-inline", "inset-inline-start", "inset-inline-end"],
57
+ bottom: ["inset", "inset-block", "inset-block-start", "inset-block-end"],
58
+ left: ["inset", "inset-inline", "inset-inline-start", "inset-inline-end"],
59
+ "grid-template-columns": ["grid-template", "grid"],
60
+ "grid-template-rows": ["grid-template", "grid"],
61
+ "grid-template-areas": ["grid-template", "grid"],
62
+ "grid-auto-columns": ["grid-auto", "grid"],
63
+ "grid-auto-rows": ["grid-auto", "grid"],
64
+ "grid-auto-flow": ["grid-auto", "grid"],
65
+ "grid-row": ["grid-area", "grid"],
66
+ "grid-column": ["grid-area", "grid"],
67
+ "grid-row-start": ["grid-row", "grid-area", "grid"],
68
+ "grid-row-end": ["grid-row", "grid-area", "grid"],
69
+ "grid-column-start": ["grid-column", "grid-area", "grid"],
70
+ "grid-column-end": ["grid-column", "grid-area", "grid"],
71
+ };
72
+ /**
73
+ * Longhands edited together by one linked field. The field is blocked when
74
+ * any of them is inline-authored, even if the shorthand itself is not.
75
+ */
76
+ const LINKED_LONGHANDS = {
77
+ "border-width": ["border-top-width", "border-right-width", "border-bottom-width", "border-left-width"],
78
+ "border-style": ["border-top-style", "border-right-style", "border-bottom-style", "border-left-style"],
79
+ "border-color": ["border-top-color", "border-right-color", "border-bottom-color", "border-left-color"],
80
+ "border-radius": ["border-top-left-radius", "border-top-right-radius", "border-bottom-right-radius", "border-bottom-left-radius"],
81
+ };
82
+ /**
83
+ * Returns the inline-authored source when `el` carries the property — or a
84
+ * shorthand that sets it — in its `style` attribute. Managed previews can
85
+ * never beat inline styles in the cascade, so a non-null result means the
86
+ * field must present as blocked instead of accepting edits that silently
87
+ * revert (see `verifyPreview`'s "inline-style" conflict).
88
+ */
89
+ export function inlineAuthoredValue(el, property) {
90
+ if (isLayoutPreview(el, property))
91
+ return null;
92
+ for (const source of [property, ...(SHORTHAND_SOURCES[property] ?? [])]) {
93
+ const value = el.style.getPropertyValue(source).trim();
94
+ if (value)
95
+ return `${source}: ${value}`;
96
+ }
97
+ for (const longhand of LINKED_LONGHANDS[property] ?? []) {
98
+ const value = inlineAuthoredValue(el, longhand);
99
+ if (value)
100
+ return value;
101
+ }
102
+ return null;
103
+ }
104
+ /** First inline-authored source that blocks any of `properties` on any of `elements`. */
105
+ export function inlineBlockedBy(elements, ...properties) {
106
+ for (const property of properties) {
107
+ for (const el of elements) {
108
+ const value = inlineAuthoredValue(el, property);
109
+ if (value)
110
+ return value;
111
+ }
112
+ }
113
+ return null;
114
+ }
@@ -4,14 +4,6 @@
4
4
  */
5
5
  export declare function meaningfulLayoutValue(el: HTMLElement, property: string): string;
6
6
  export declare function readAuthoredStyleValue(el: HTMLElement, property: string): string | null;
7
- /**
8
- * Returns the inline-authored source when `el` carries the property — or a
9
- * shorthand that sets it — in its `style` attribute. Managed previews can
10
- * never beat inline styles in the cascade, so a non-null result means the
11
- * field must present as blocked instead of accepting edits that silently
12
- * revert (see `verifyPreview`'s "inline-style" conflict).
13
- */
14
- export declare function inlineAuthoredValue(el: HTMLElement, property: string): string | null;
15
7
  export interface LayoutValue {
16
8
  property: string;
17
9
  authored: string | null;
@@ -2,7 +2,6 @@ import { getActiveStyleState } from "../shell/styleState.js";
2
2
  import { getStateStyleValue } from "../shell/stateValue.js";
3
3
  import { getElementComputedStyle } from "../runtime/domRealm.js";
4
4
  import { getBrowserCssInspection } from "../inspection/browserCssInspectionRegistry.js";
5
- import { isLayoutPreview } from "./layoutPreviewState.js";
6
5
  const DEFAULT_LAYOUT_VALUES = {
7
6
  width: "auto",
8
7
  height: "auto",
@@ -48,47 +47,6 @@ export function readAuthoredStyleValue(el, property) {
48
47
  const inline = el.style.getPropertyValue(property).trim();
49
48
  return inline || null;
50
49
  }
51
- /**
52
- * Shorthands that also author the keyed longhand when present in a `style`
53
- * attribute. Managed-stylesheet previews lose the cascade to any of these,
54
- * so fields must treat the longhand as inline-blocked either way.
55
- */
56
- const INLINE_SHORTHAND_SOURCES = {
57
- "row-gap": ["gap"],
58
- "column-gap": ["gap"],
59
- "margin-top": ["margin"],
60
- "margin-right": ["margin"],
61
- "margin-bottom": ["margin"],
62
- "margin-left": ["margin"],
63
- "padding-top": ["padding"],
64
- "padding-right": ["padding"],
65
- "padding-bottom": ["padding"],
66
- "padding-left": ["padding"],
67
- top: ["inset"],
68
- right: ["inset"],
69
- bottom: ["inset"],
70
- left: ["inset"],
71
- };
72
- /**
73
- * Returns the inline-authored source when `el` carries the property — or a
74
- * shorthand that sets it — in its `style` attribute. Managed previews can
75
- * never beat inline styles in the cascade, so a non-null result means the
76
- * field must present as blocked instead of accepting edits that silently
77
- * revert (see `verifyPreview`'s "inline-style" conflict).
78
- */
79
- export function inlineAuthoredValue(el, property) {
80
- if (isLayoutPreview(el, property))
81
- return null;
82
- const direct = el.style.getPropertyValue(property).trim();
83
- if (direct)
84
- return `${property}: ${direct}`;
85
- for (const shorthand of INLINE_SHORTHAND_SOURCES[property] ?? []) {
86
- const value = el.style.getPropertyValue(shorthand).trim();
87
- if (value)
88
- return `${shorthand}: ${value}`;
89
- }
90
- return null;
91
- }
92
50
  /**
93
51
  * Reads both representations needed by a layout editor. Authored CSS is the
94
52
  * editable source of truth; computed CSS is only the browser preview/fallback.
@@ -7,10 +7,10 @@ export declare function nudgeCssValue(property: string, rawValue: string, direct
7
7
  /** Returns whether a style field exposes the horizontal drag nudge affordance. */
8
8
  export declare function supportsDragNudge(property: string): boolean;
9
9
  /**
10
- * Applies one nudge per two horizontal pointer pixels. Large nudges still use
11
- * one 8px step per pointer pixel. When a large drag starts from an off-grid
12
- * value, the first step snaps to the next large-step boundary in the drag
13
- * direction.
10
+ * Applies one regular nudge per sixteen horizontal pointer pixels and one large
11
+ * nudge per eight horizontal pointer pixels. When a large drag starts from an
12
+ * off-grid value, the first step snaps to the next large-step boundary in the
13
+ * drag direction.
14
14
  */
15
15
  export declare function nudgeCssValueByDrag(property: string, rawValue: string, deltaX: number, large?: boolean, snapToLargeStep?: boolean): string | null;
16
16
  /** Returns whether a field has a numeric value that can respond to dragging. */