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
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from "react";
3
- import { IconBorderBottom, IconBorderLeft, IconBorderRight, IconBorderSides, IconBorderStyle2, IconBorderTop, IconCheck, IconMinus, IconPlus, } from "@tabler/icons-react";
3
+ import { IconBorderSides, IconBorderStyle2, IconCheck, IconMinus, IconPlus, } from "@tabler/icons-react";
4
4
  import { findTokenRow } from "./rowLookup.js";
5
5
  import { TokenField } from "../tokens/TokenField.js";
6
6
  import { setStyle, setStyles } from "../tokens/editActions.js";
@@ -13,8 +13,11 @@ import { getStateStyleValue } from "../shell/stateValue.js";
13
13
  import { PopoverListbox } from "../ui/PopoverListbox.js";
14
14
  import { ControlSurface } from "../ui/ControlSurface.js";
15
15
  import { getNudgeUiTokenEntries } from "../runtime/runtimeConfig.js";
16
- import { hasAuthoredProperty, hasAuthoredStyle, isZeroCssValue } from "./stylePresence.js";
16
+ import { isZeroCssValue } from "./stylePresence.js";
17
17
  import { useFieldVisibility } from "./useFieldVisibility.js";
18
+ import { Tooltip } from "../ui/Tooltip.js";
19
+ import { inlineStyleWarningContent } from "../ui/InlineStyleWarning.js";
20
+ import { inlineBlockedBy } from "./inlineAuthored.js";
18
21
  const BORDER_STYLES = ["none", "hidden", "solid", "dashed", "dotted", "double", "groove", "ridge", "inset", "outset"];
19
22
  const INVISIBLE_BORDER_STYLES = new Set(["none", "hidden"]);
20
23
  const BORDER_SIDES = SIDE_NAMES.map((side) => `border-${side}`);
@@ -96,67 +99,15 @@ function valuesAreLinked(el, rows, shorthand, sideProperties) {
96
99
  const signatures = sideProperties.map((property) => sideComponentSignature(el, rows, property));
97
100
  return new Set(signatures).size === 1;
98
101
  }
99
- function isBorderFaceProperty(property) {
100
- const p = property.toLowerCase();
101
- return p === "border"
102
- || p === "border-width"
103
- || p === "border-style"
104
- || p === "border-color"
105
- || /^border-(top|right|bottom|left)(?:-(?:width|style|color))?$/.test(p);
106
- }
107
- function isZeroWidthValue(value) {
108
- const trimmed = value.trim().toLowerCase();
109
- if (isZeroCssValue(trimmed))
110
- return true;
111
- // Structured/preflight authored forms like `0 solid` / `0px solid currentcolor`.
112
- const first = trimmed.split(/\s+/)[0] ?? "";
113
- return isZeroCssValue(first);
114
- }
115
- /** True when a face paints: drawn style and non-zero width. */
116
- function sidePaints(el, rows, side) {
117
- const style = borderStyleValue(el, rows, `border-${side}-style`);
118
- if (INVISIBLE_BORDER_STYLES.has(style))
119
- return false;
120
- return !isZeroWidthValue(borderWidthValue(el, rows, `border-${side}-width`));
121
- }
122
- /**
123
- * Show border controls for intentional / painted borders only.
124
- *
125
- * Tailwind preflight authors `border: 0 solid` on `*`. That is cascade
126
- * evidence but not a visible border — hide controls and show + instead.
127
- *
128
- * Counts as presence:
129
- * - any painted face (drawn style + non-zero width)
130
- * - a direct width or disabling style, including zero
131
- */
132
- function hasBorderPresence(el, rows) {
133
- if (SIDE_NAMES.some((side) => sidePaints(el, rows, side)))
134
- return true;
135
- for (const row of rows) {
136
- if (!isBorderFaceProperty(row.property) && !row.structure)
137
- continue;
138
- if (!hasAuthoredStyle(row))
139
- continue;
140
- const property = row.property.toLowerCase();
141
- const authored = (row.authored ?? row.declaredValue ?? "").trim().toLowerCase();
142
- const structuredStyle = row.structure?.style?.trim().toLowerCase() ?? "";
143
- const structuredWidth = row.structure?.width?.trim() ?? "";
144
- if (INVISIBLE_BORDER_STYLES.has(structuredStyle) || INVISIBLE_BORDER_STYLES.has(authored)) {
145
- return true;
146
- }
147
- if (structuredWidth)
148
- return true;
149
- if ((property === "border-width" || property.endsWith("-width")) && authored) {
150
- return true;
151
- }
152
- }
153
- // Computed non-zero width without cascade rows (inline / inaccessible sheets).
154
- if (!isZeroWidthValue(borderWidthValue(el, rows, "border-width")))
155
- return true;
156
- if (SIDE_NAMES.some((side) => !isZeroWidthValue(borderWidthValue(el, rows, `border-${side}-width`)))) {
157
- return true;
158
- }
159
- return false;
102
+ /** Initial visibility follows the effective border, including stylesheet resets. */
103
+ function hasBorderPresence(el) {
104
+ return SIDE_NAMES.some((side) => {
105
+ const style = getStateStyleValue(el, `border-${side}-style`, "none").toLowerCase();
106
+ if (INVISIBLE_BORDER_STYLES.has(style))
107
+ return false;
108
+ const width = getStateStyleValue(el, `border-${side}-width`, "0px");
109
+ return !isZeroCssValue(width);
110
+ });
160
111
  }
161
112
  /**
162
113
  * Linked presentation from cascade data + optional user toggle.
@@ -192,12 +143,14 @@ function useBorderLinkedState(dataLinked, resetKey) {
192
143
  export function BorderEditor(props) {
193
144
  const { element, selection, entries, tokenRows = [], onAfterEdit } = props;
194
145
  const el = element.domElement;
146
+ const selectedElements = selection?.domElements ?? [el];
195
147
  const editTarget = selection?.target ?? el;
196
148
  const isGroup = Boolean(selection && selection.elements.length > 1);
197
149
  const allEntries = entries ?? getNudgeUiTokenEntries();
198
150
  const borderWidthProperties = BORDER_SIDES.map((side) => `${side}-width`);
199
151
  const borderStyleProperties = BORDER_SIDES.map((side) => `${side}-style`);
200
152
  const borderColorProperties = BORDER_SIDES.map((side) => `${side}-color`);
153
+ const borderBlockedBy = inlineBlockedBy(selectedElements, "border", "border-width", "border-style", "border-color");
201
154
  const borderWidthDataLinked = valuesAreLinked(el, tokenRows, "border-width", borderWidthProperties);
202
155
  const borderStyleDataLinked = valuesAreLinked(el, tokenRows, "border-style", borderStyleProperties);
203
156
  const borderColorDataLinked = valuesAreLinked(el, tokenRows, "border-color", borderColorProperties);
@@ -208,18 +161,19 @@ export function BorderEditor(props) {
208
161
  const rawBorderFallback = !isGroup && Boolean(borderRow && !borderRow.structure && !hasStructuredBorderRows);
209
162
  const linkedBorderStyle = borderStyleValue(el, tokenRows, "border-style");
210
163
  const showWidthAndColor = !(borderLinked && INVISIBLE_BORDER_STYLES.has(linkedBorderStyle));
211
- const hasBorder = isGroup
212
- ? (selection?.domElements.some((candidate) => hasBorderPresence(candidate, [])) ?? false)
213
- || borderWidthProperties.some((property) => hasAuthoredProperty(selection, property))
214
- : hasBorderPresence(el, tokenRows);
215
- const visibility = useFieldVisibility(selection?.domElements ?? [el], "border", hasBorder || rawBorderFallback);
164
+ const hasBorder = selectedElements.some(hasBorderPresence);
165
+ const visibility = useFieldVisibility(selectedElements, "border", hasBorder);
216
166
  const showBorderControls = visibility.visible;
217
167
  function handleAddBorder() {
168
+ if (borderBlockedBy)
169
+ return;
218
170
  setStyle(editTarget, "border", "1px solid");
219
171
  visibility.show();
220
172
  onAfterEdit?.();
221
173
  }
222
174
  function handleRemoveBorder() {
175
+ if (borderBlockedBy)
176
+ return;
223
177
  setStyle(editTarget, "border", "0 solid");
224
178
  visibility.hide();
225
179
  onAfterEdit?.();
@@ -228,6 +182,8 @@ export function BorderEditor(props) {
228
182
  setBorderLinked(false);
229
183
  }
230
184
  function handleCollapse() {
185
+ if (borderBlockedBy)
186
+ return;
231
187
  setBorderLinked(true);
232
188
  const declarations = [
233
189
  borderLinkDeclaration(el, tokenRows, "border-style", borderStyleProperties),
@@ -245,29 +201,42 @@ export function BorderEditor(props) {
245
201
  width: (_jsx(ControlSurface, { children: _jsx(TokenField, { property: borderWidthProperties[index], selection: selection, tokenRow: findTokenRow(tokenRows, borderWidthProperties[index]), domElement: el, editTarget: editTarget, entries: allEntries, onAfterEdit: onAfterEdit, chipVariant: "small" }) })),
246
202
  style: (_jsx(BorderStyleSettingsMenu, { property: borderStyleProperties[index], tokenRow: findTokenRow(tokenRows, borderStyleProperties[index]), domElement: el, editTarget: editTarget, selection: selection, dataTest: `border-style-${side}`, onAfterEdit: onAfterEdit })),
247
203
  }));
248
- return (_jsxs("div", { className: `editor`, "data-test": "border-editor", children: [_jsxs("div", { className: "editor__title-row", children: [_jsx("div", { className: "editor__title", children: "Border" }), showBorderControls ? (_jsx(IconButton, { variant: "quiet", label: "Remove Border", "data-test": "remove-border", className: "border__remove", onClick: handleRemoveBorder, children: _jsx(IconMinus, { size: 16, "aria-hidden": "true" }) })) : (_jsx(IconButton, { variant: "quiet", label: "Add Border", "data-test": "add-border", className: "border__add", onClick: handleAddBorder, children: _jsx(IconPlus, { size: 16, "aria-hidden": "true" }) }))] }), showBorderControls && (_jsx("div", { className: "border", "data-expanded": borderLinked ? "false" : "true", children: rawBorderFallback ? (_jsx(FieldRow, { label: "Border", children: _jsx(ControlSurface, { children: _jsx(TokenField, { property: "border", selection: selection, tokenRow: borderRow, domElement: el, editTarget: editTarget, entries: allEntries, onAfterEdit: onAfterEdit }) }) })) : borderLinked ? (_jsxs("div", { className: "border__linked-row", children: [showWidthAndColor ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "border__linked-control border__linked-control--color", children: _jsx(ControlSurface, { children: _jsx(TokenField, { property: "border-color", selection: selection, tokenRow: linkedTokenRow(tokenRows, "border-color", borderColorProperties), domElement: el, editTarget: editTarget, entries: allEntries, onAfterEdit: onAfterEdit }) }) }), _jsx("div", { className: "border__linked-control border__linked-control--width", children: _jsx(ControlSurface, { children: _jsx(TokenField, { property: "border-width", selection: selection, tokenRow: linkedTokenRow(tokenRows, "border-width", borderWidthProperties), domElement: el, editTarget: editTarget, entries: allEntries, onAfterEdit: onAfterEdit, chipVariant: "small" }) }) })] })) : null, _jsx(BorderStyleSettingsMenu, { property: "border-style", tokenRow: linkedTokenRow(tokenRows, "border-style", borderStyleProperties), domElement: el, editTarget: editTarget, selection: selection, onAfterEdit: onAfterEdit }), _jsx(ToggleButton, { variant: "quiet", size: "default", "data-test": "border-expand", label: "Edit Individual Border Sides", title: "Edit Individual Border Sides", pressed: !borderLinked, onPressedChange: (pressed) => {
204
+ return (_jsxs("div", { className: `editor`, "data-test": "border-editor", children: [_jsxs("div", { className: "editor__title-row", children: [_jsx("div", { className: "editor__title", children: "Border" }), showBorderControls ? (_jsx(Tooltip, { content: inlineStyleWarningContent(borderBlockedBy), children: _jsx(IconButton, { variant: "quiet", label: "Remove Border", "data-test": "remove-border", className: "border__remove", disabled: borderBlockedBy !== null, onClick: handleRemoveBorder, children: _jsx(IconMinus, { size: 16, "aria-hidden": "true" }) }) })) : (_jsx(IconButton, { variant: "quiet", label: "Add Border", "data-test": "add-border", className: "border__add", disabled: borderBlockedBy !== null, onClick: handleAddBorder, children: _jsx(IconPlus, { size: 16, "aria-hidden": "true" }) }))] }), showBorderControls && (_jsx("div", { className: "border", "data-expanded": borderLinked ? "false" : "true", children: rawBorderFallback ? (_jsx(FieldRow, { label: "Border", children: _jsx(ControlSurface, { children: _jsx(TokenField, { property: "border", selection: selection, tokenRow: borderRow, domElement: el, editTarget: editTarget, entries: allEntries, onAfterEdit: onAfterEdit }) }) })) : borderLinked ? (_jsxs("div", { className: "border__linked-row", children: [showWidthAndColor ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "border__linked-control border__linked-control--color", children: _jsx(ControlSurface, { children: _jsx(TokenField, { property: "border-color", selection: selection, tokenRow: linkedTokenRow(tokenRows, "border-color", borderColorProperties), domElement: el, editTarget: editTarget, entries: allEntries, onAfterEdit: onAfterEdit }) }) }), _jsx("div", { className: "border__linked-control border__linked-control--width", children: _jsx(ControlSurface, { children: _jsx(TokenField, { property: "border-width", selection: selection, tokenRow: linkedTokenRow(tokenRows, "border-width", borderWidthProperties), domElement: el, editTarget: editTarget, entries: allEntries, onAfterEdit: onAfterEdit, chipVariant: "small" }) }) })] })) : null, _jsx(BorderStyleSettingsMenu, { property: "border-style", tokenRow: linkedTokenRow(tokenRows, "border-style", borderStyleProperties), domElement: el, editTarget: editTarget, selection: selection, onAfterEdit: onAfterEdit }), _jsx(ToggleButton, { variant: "quiet", size: "default", "data-test": "border-expand", label: "Edit Individual Border Sides", pressed: !borderLinked, onPressedChange: (pressed) => {
249
205
  if (pressed)
250
206
  handleExpand();
251
- }, children: _jsx(IconBorderSides, { size: 16, "aria-hidden": "true" }) })] })) : (_jsxs("div", { className: "border__expanded", children: [_jsxs("div", { className: "border__expanded-header", children: [_jsx("span", { className: "side-values__label", children: formatInspectorLabel("Individual Sides") }), _jsx(ToggleButton, { variant: "quiet", size: "default", "data-test": "border-collapse", label: "Link All Border Sides", title: "Link All Border Sides", pressed: !borderLinked, onPressedChange: (pressed) => {
207
+ }, children: _jsx(IconBorderSides, { size: 16, "aria-hidden": "true" }) })] })) : (_jsxs("div", { className: "border__expanded", children: [_jsxs("div", { className: "border__expanded-header", children: [_jsx("span", { className: "side-values__label", children: formatInspectorLabel("Individual Sides") }), _jsx(ToggleButton, { variant: "quiet", size: "default", "data-test": "border-collapse", label: "Link All Border Sides", pressed: !borderLinked, disabled: borderBlockedBy !== null, onPressedChange: (pressed) => {
252
208
  if (!pressed)
253
209
  handleCollapse();
254
210
  }, children: _jsx(IconBorderSides, { size: 16, "aria-hidden": "true" }) })] }), showWidthAndColor ? (_jsx("div", { className: "border__side-rows", "data-test": "border-side-rows", children: sideRows.map(({ side, color, width, style }) => (_jsxs("div", { className: "border__side-row", "data-side": side, "aria-label": `Border ${formatInspectorLabel(side)}`, children: [_jsx(BorderSideIndicator, { side: side }), _jsx("div", { className: "border__side-control border__side-control--color", children: color }), _jsx("div", { className: "border__side-control border__side-control--width", children: width }), style] }, side))) })) : null] })) }))] }));
255
211
  }
256
- const BORDER_SIDE_ICONS = {
257
- top: IconBorderTop,
258
- right: IconBorderRight,
259
- bottom: IconBorderBottom,
260
- left: IconBorderLeft,
212
+ const BORDER_SIDE_ICON_PATHS = {
213
+ left: {
214
+ outline: "M20 3H4v18h16a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1Z",
215
+ emphasis: { x1: "3.5", y1: "3.5", x2: "3.5", y2: "20.5" },
216
+ },
217
+ right: {
218
+ outline: "M4 3a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h16V3H4Z",
219
+ emphasis: { x1: "20.5", y1: "3.5", x2: "20.5", y2: "20.5" },
220
+ },
221
+ top: {
222
+ outline: "M21 20a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4h18v16Z",
223
+ emphasis: { x1: "3.5", y1: "3.5", x2: "20.5", y2: "3.5" },
224
+ },
225
+ bottom: {
226
+ outline: "M3 4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v17H3V4Z",
227
+ emphasis: { x1: "3.5", y1: "20.5", x2: "20.5", y2: "20.5" },
228
+ },
261
229
  };
262
230
  function BorderSideIndicator({ side }) {
263
- const Icon = BORDER_SIDE_ICONS[side];
264
- return _jsx(Icon, { className: "side-values__icon side-values__side-icon", size: 16, "aria-hidden": "true" });
231
+ const { outline, emphasis } = BORDER_SIDE_ICON_PATHS[side];
232
+ return (_jsxs("svg", { className: "side-values__icon side-values__side-icon", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [_jsx("path", { d: outline, stroke: "currentColor", strokeWidth: "var(--icon-stroke-width)", strokeLinecap: "square", strokeOpacity: "0.2" }), _jsx("line", { ...emphasis, stroke: "currentColor", strokeWidth: "var(--icon-stroke-width)", strokeLinecap: "round" })] }));
265
233
  }
266
234
  function BorderStyleSettingsMenu({ property, tokenRow, domElement: el, editTarget, selection, dataTest = "border-style-settings", onAfterEdit }) {
267
235
  const structured = tokenRow?.structure?.style?.trim().toLowerCase() ?? "";
268
236
  const selectedValue = selection?.getProperty(property)?.value;
269
237
  const mixed = selectedValue?.kind === "mixed";
270
238
  const commonValue = selectedValue?.kind === "common" ? selectedValue.value : "";
239
+ const blockedBy = inlineBlockedBy(selection?.domElements ?? [el], property);
271
240
  const initial = mixed ? "Mixed" : commonValue || structured || getStateStyleValue(el, property, "none") || "none";
272
241
  const [value, setValue] = useState(initial);
273
242
  const [open, setOpen] = useState(false);
@@ -275,6 +244,8 @@ function BorderStyleSettingsMenu({ property, tokenRow, domElement: el, editTarge
275
244
  setValue(mixed ? "Mixed" : commonValue || structured || getStateStyleValue(el, property, "none") || "none");
276
245
  }, [commonValue, el, mixed, property, structured]);
277
246
  function handleChange(next) {
247
+ if (blockedBy)
248
+ return;
278
249
  if (!BORDER_STYLES.includes(next))
279
250
  return;
280
251
  setValue(next);
@@ -282,7 +253,7 @@ function BorderStyleSettingsMenu({ property, tokenRow, domElement: el, editTarge
282
253
  setOpen(false);
283
254
  onAfterEdit?.();
284
255
  }
285
- return (_jsx(PopoverListbox, { query: "", value: null, open: open, triggerElement: (_jsx(IconButton, { variant: "quiet", size: "default", label: `Border style: ${formatInspectorLabel(value)}`, "data-test": dataTest, "data-current-style": value, children: _jsx(IconBorderStyle2, { size: 16, "aria-hidden": "true" }) })), triggerDataTest: dataTest, triggerAriaLabel: "Border style settings", items: BORDER_STYLES.map((style) => ({
256
+ return (_jsx(PopoverListbox, { query: "", value: null, open: open, triggerElement: (_jsx(IconButton, { variant: "quiet", size: "default", label: `Border style: ${formatInspectorLabel(value)}`, "data-test": dataTest, "data-current-style": value, children: _jsx(IconBorderStyle2, { size: 16, "aria-hidden": "true" }) })), triggerDataTest: dataTest, triggerAriaLabel: "Border style settings", triggerTooltip: inlineStyleWarningContent(blockedBy), disabled: blockedBy !== null, items: BORDER_STYLES.map((style) => ({
286
257
  value: style,
287
258
  label: formatInspectorLabel(style),
288
259
  leading: style === value ? _jsx(IconCheck, { size: 14, stroke: 2, "aria-hidden": "true" }) : undefined,
@@ -10,6 +10,7 @@ import { ControlSurface } from "../ui/ControlSurface.js";
10
10
  import { getNudgeUiTokenEntries } from "../runtime/runtimeConfig.js";
11
11
  import { completeCssValue } from "./completeCssValue.js";
12
12
  import { valuePolicyFor } from "./valuePolicy.js";
13
+ import { inlineBlockedBy } from "./inlineAuthored.js";
13
14
  const BORDER_RADIUS_CORNERS = [
14
15
  "border-top-left-radius",
15
16
  "border-top-right-radius",
@@ -52,6 +53,7 @@ export function BorderRadiusEditor(props) {
52
53
  const isGroup = Boolean(selection && selection.elements.length > 1);
53
54
  const allEntries = entries ?? getNudgeUiTokenEntries();
54
55
  const dataLinked = !isGroup && cornersAreLinked(tokenRows);
56
+ const blockedBy = inlineBlockedBy(selection?.domElements ?? [el], "border-radius");
55
57
  const [userUnlinked, setUserUnlinked] = useState(false);
56
58
  const [userLinked, setUserLinked] = useState(false);
57
59
  useEffect(() => {
@@ -70,6 +72,8 @@ export function BorderRadiusEditor(props) {
70
72
  setUserLinked(false);
71
73
  }
72
74
  function handleCollapse() {
75
+ if (blockedBy)
76
+ return;
73
77
  setUserLinked(true);
74
78
  setUserUnlinked(false);
75
79
  linkAllCorners(editTarget, tokenRows, selection, onAfterEdit);
@@ -94,7 +98,8 @@ export function BorderRadiusEditor(props) {
94
98
  const groupedControl = (_jsx(ControlSurface, { children: _jsx(TokenField, { property: "border-radius", selection: selection, tokenRow: mixed ? null : borderRadiusRow, initialValue: mixed ? "Mix" : undefined, displayValue: mixed ? "Mix" : undefined, domElement: el, editTarget: editTarget, entries: allEntries, editMetadata: metadataFor(borderRadiusRow), mixed: mixed, formatRawValue: (value) => mixed && value.trim().toLowerCase() === "mix"
95
99
  ? ""
96
100
  : completeCssValue(value.trim(), valuePolicyFor("border-radius")), onAfterEdit: onAfterEdit, chipVariant: "small", leading: _jsx(IconBorderCorners, { className: "side-values__icon side-values__side-icon", size: 16, "aria-hidden": "true" }) }) }));
97
- const toggleButton = (_jsx(ToggleButton, { className: embedded ? "border-radius-editor__toggle" : undefined, variant: "quiet", size: "default", "data-test": isLinked ? "border-radius-expand" : "border-radius-collapse", label: isLinked ? "Edit Individual Corners" : "Link All Corners", title: isLinked ? "Edit Individual Corners" : "Link All Corners", pressed: !isLinked, onPressedChange: (pressed) => {
101
+ const toggleBlocked = !isLinked && blockedBy !== null;
102
+ const toggleButton = (_jsx(ToggleButton, { className: embedded ? "border-radius-editor__toggle" : undefined, variant: "quiet", size: "default", "data-test": isLinked ? "border-radius-expand" : "border-radius-collapse", label: isLinked ? "Edit Individual Corners" : "Link All Corners", pressed: !isLinked, disabled: toggleBlocked, onPressedChange: (pressed) => {
98
103
  if (pressed)
99
104
  handleExpand();
100
105
  else
@@ -1,6 +1,5 @@
1
1
  import type { ReactElement } from "react";
2
- import type { TokenEntry } from "../../css/model/index.js";
3
- import type { ResolvedProperty } from "../../css/model/index.js";
2
+ import type { TokenEntry, ResolvedProperty } from "../../css/model/index.js";
4
3
  import type { SelectedElement } from "../selection/selectionStore.js";
5
4
  import type { StyleSelection } from "../selection/styleSelection.js";
6
5
  export interface BoxShadowEditorProps {
@@ -1,13 +1,66 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { IconPlus } from "@tabler/icons-react";
3
- import { TokenField } from "../tokens/TokenField.js";
4
- import { FieldRow } from "../ui/FieldRow.js";
2
+ import { useEffect, useState } from "react";
3
+ import { IconBoxMargin, IconLetterX, IconLetterY, IconMinus, IconPlus } from "@tabler/icons-react";
4
+ import { splitTopLevel, splitTopLevelWhitespace } from "../../css/value-semantics/cssSyntax.js";
5
+ import { interpretTokenValue } from "../../css/value-semantics/tokenInterpretation.js";
6
+ import { applyColorOpacity, replaceColorPreservingOpacity, withColorOpacity } from "../../css/value-semantics/colorSemantics.js";
7
+ import { colorValueToHex, TokenField, TokenValueField } from "../tokens/TokenField.js";
8
+ import { setStyle } from "../tokens/editActions.js";
5
9
  import { ControlSurface } from "../ui/ControlSurface.js";
6
10
  import { getNudgeUiTokenEntries } from "../runtime/runtimeConfig.js";
7
11
  import { IconButton } from "../ui/IconButton.js";
12
+ import { Tooltip } from "../ui/Tooltip.js";
8
13
  import { getStateStyleValue } from "../shell/stateValue.js";
9
14
  import { hasAuthoredProperty } from "./stylePresence.js";
10
15
  import { useFieldVisibility } from "./useFieldVisibility.js";
16
+ import { inlineBlockedBy } from "./inlineAuthored.js";
17
+ import { metadataFor } from "./rowLookup.js";
18
+ import { completeCssValue } from "./completeCssValue.js";
19
+ import { valuePolicyFor } from "./valuePolicy.js";
20
+ const LENGTH = /^(?:[+-]?(?:\d*\.)?\d+(?:e[+-]?\d+)?(?:[a-z]+)?|(?:calc|min|max|clamp)\(.+\))$/i;
21
+ const DIMENSIONS = [
22
+ { label: "X Offset", description: "X offset", Icon: IconLetterX },
23
+ { label: "Y Offset", description: "Y offset", Icon: IconLetterY },
24
+ { label: "Blur", description: "Blur", Icon: ShadowBlurIcon },
25
+ { label: "Spread", description: "Spread", Icon: IconBoxMargin },
26
+ ];
27
+ function ShadowBlurIcon({ size = 16 }) {
28
+ return (_jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "currentColor", stroke: "none", "aria-hidden": "true", children: [_jsx("circle", { opacity: "0.5", cx: "7.55555", cy: "3.11111", r: "1.11111" }), _jsx("circle", { cx: "7.55555", cy: "7.55555", r: "1.11111" }), _jsx("circle", { cx: "7.55555", cy: "12", r: "1.11111" }), _jsx("circle", { opacity: "0.5", cx: "7.55555", cy: "16.4444", r: "1.11111" }), _jsx("circle", { opacity: "0.3", cx: "7.55555", cy: "20.8889", r: "1.11111" }), _jsx("circle", { opacity: "0.3", cx: "12", cy: "3.11111", r: "1.11111" }), _jsx("circle", { cx: "12", cy: "7.55555", r: "1.11111" }), _jsx("circle", { cx: "12", cy: "12", r: "1.11111" }), _jsx("circle", { cx: "12", cy: "16.4444", r: "1.11111" }), _jsx("circle", { opacity: "0.3", cx: "12", cy: "20.8889", r: "1.11111" }), _jsx("circle", { opacity: "0.3", cx: "16.4444", cy: "3.11111", r: "1.11111" }), _jsx("circle", { opacity: "0.5", cx: "16.4444", cy: "7.55555", r: "1.11111" }), _jsx("circle", { cx: "16.4444", cy: "12", r: "1.11111" }), _jsx("circle", { cx: "16.4444", cy: "16.4444", r: "1.11111" }), _jsx("circle", { opacity: "0.5", cx: "16.4444", cy: "20.8889", r: "1.11111" }), _jsx("circle", { opacity: "0.3", cx: "20.8889", cy: "3.11111", r: "1.11111" }), _jsx("circle", { opacity: "0.3", cx: "20.8889", cy: "7.55555", r: "1.11111" }), _jsx("circle", { opacity: "0.3", cx: "20.8889", cy: "12", r: "1.11111" }), _jsx("circle", { opacity: "0.5", cx: "20.8889", cy: "16.4444", r: "1.11111" }), _jsx("circle", { opacity: "0.5", cx: "20.8889", cy: "20.8889", r: "1.11111" }), _jsx("circle", { opacity: "0.5", cx: "3.11111", cy: "3.11111", r: "1.11111" }), _jsx("circle", { opacity: "0.5", cx: "3.11111", cy: "7.55555", r: "1.11111" }), _jsx("circle", { opacity: "0.3", cx: "3.11111", cy: "12", r: "1.11111" }), _jsx("circle", { opacity: "0.3", cx: "3.11111", cy: "16.4444", r: "1.11111" }), _jsx("circle", { opacity: "0.3", cx: "3.11111", cy: "20.8889", r: "1.11111" })] }));
29
+ }
30
+ function defaultShadow() {
31
+ return { lengths: ["0", "2px", "3px", "0"], color: "rgb(0 0 0 / 20%)", inset: false };
32
+ }
33
+ function parseShadows(value, entries) {
34
+ if (!value || value === "none")
35
+ return [];
36
+ const result = [];
37
+ for (const layer of splitTopLevel(value, ",")) {
38
+ const parts = splitTopLevelWhitespace(layer.trim());
39
+ const isLength = (part) => LENGTH.test(resolveToken(part, entries));
40
+ const lengths = parts.filter(isLength);
41
+ const colors = parts.filter((part) => part !== "inset" && !isLength(part));
42
+ if (lengths.length < 2 || lengths.length > 4 || colors.length > 1)
43
+ return null;
44
+ result.push({
45
+ lengths: [lengths[0], lengths[1], lengths[2] ?? "0", lengths[3] ?? "0"],
46
+ color: colors[0] ?? "currentColor",
47
+ inset: parts.includes("inset"),
48
+ });
49
+ }
50
+ return result.length ? result : null;
51
+ }
52
+ function tokenName(value) {
53
+ return /^var\((--[\w-]+)\)$/.exec(value)?.[1] ?? null;
54
+ }
55
+ function resolveToken(value, entries) {
56
+ const name = tokenName(value);
57
+ return entries.find((entry) => entry.name === name)?.value ?? value;
58
+ }
59
+ function serializeShadows(layers) {
60
+ if (layers.length === 0)
61
+ return "none";
62
+ return layers.map((layer) => `${layer.inset ? "inset " : ""}${layer.lengths.join(" ")} ${layer.color}`).join(", ");
63
+ }
11
64
  export function BoxShadowEditor(props) {
12
65
  const { element, selection, entries, tokenRows = [], onAfterEdit } = props;
13
66
  const el = element.domElement;
@@ -15,10 +68,85 @@ export function BoxShadowEditor(props) {
15
68
  const allEntries = entries ?? getNudgeUiTokenEntries();
16
69
  const tokenRow = tokenRows.find((row) => row.property === "box-shadow") ?? null;
17
70
  const elements = selection?.domElements ?? [el];
71
+ const colorContext = { tokenTable: Object.fromEntries(allEntries.map((entry) => [entry.name, entry])) };
72
+ const computed = getStateStyleValue(el, "box-shadow");
73
+ const source = tokenRow?.authored ?? tokenRow?.declaredValue ?? computed;
74
+ const [draft, setDraft] = useState(null);
75
+ useEffect(() => setDraft(null), [el, source]);
76
+ const activeDraft = draft?.element === el && draft.source === source ? draft : null;
77
+ const value = activeDraft?.value ?? source;
78
+ // A row can reference a color or length token without the entire shadow being token-backed.
79
+ const wholeShadowToken = tokenRow?.tokenName
80
+ && value.trim().startsWith("var(")
81
+ && splitTopLevelWhitespace(value.trim()).length === 1;
82
+ const selectedProperty = selection && selection.elements.length > 1 ? selection.getProperty("box-shadow") : null;
83
+ const mixed = selectedProperty?.value.kind === "mixed";
84
+ const layers = mixed ? null : parseShadows(value, allEntries)
85
+ ?? parseShadows(tokenRow?.resolvedValue ?? computed, allEntries);
86
+ const blockedBy = inlineBlockedBy(elements, "box-shadow");
18
87
  const hasShadow = hasAuthoredProperty(selection, "box-shadow", tokenRow) || elements.some((element) => {
19
88
  const value = getStateStyleValue(element, "box-shadow");
20
89
  return value !== "" && value !== "none";
21
90
  });
22
91
  const visibility = useFieldVisibility(elements, "box-shadow", hasShadow);
23
- return (_jsxs("div", { className: "editor", "data-test": "box-shadow-editor", children: [_jsxs("div", { className: "editor__title-row", children: [_jsx("div", { className: "editor__title", children: "Box Shadow" }), !visibility.visible ? (_jsx(IconButton, { variant: "quiet", label: "Add Box Shadow", "data-test": "add-shadow", onClick: visibility.show, children: _jsx(IconPlus, { size: 16, "aria-hidden": "true" }) })) : null] }), visibility.visible ? _jsx("div", { className: "property", children: _jsx(FieldRow, { label: "Box Shadow", children: _jsx(ControlSurface, { children: _jsx(TokenField, { property: "box-shadow", selection: selection, tokenRow: tokenRow, domElement: el, editTarget: editTarget, entries: allEntries, onAfterEdit: onAfterEdit }) }) }) }) : null] }));
92
+ function commitLayers(nextLayers) {
93
+ if (blockedBy)
94
+ return false;
95
+ const nextValue = serializeShadows(nextLayers);
96
+ if (!setStyle(editTarget, "box-shadow", nextValue, selection && selection.elements.length > 1 ? undefined : metadataFor(tokenRow)))
97
+ return false;
98
+ setDraft({ element: el, source, value: nextValue });
99
+ onAfterEdit?.();
100
+ return true;
101
+ }
102
+ function commitLayer(index, next) {
103
+ if (!layers)
104
+ return;
105
+ commitLayers(layers.map((layer, layerIndex) => layerIndex === index ? next : layer));
106
+ }
107
+ function addShadow() {
108
+ if (!layers)
109
+ return;
110
+ if (commitLayers([...layers, defaultShadow()]))
111
+ visibility.show();
112
+ }
113
+ function removeShadow(index) {
114
+ if (!layers)
115
+ return;
116
+ const remaining = layers.filter((_, layerIndex) => layerIndex !== index);
117
+ if (commitLayers(remaining) && remaining.length === 0)
118
+ visibility.hide();
119
+ }
120
+ function commitColor(index, layer, color) {
121
+ const result = replaceColorPreservingOpacity(layer.color, color, colorContext);
122
+ if (result.ok)
123
+ commitLayer(index, { ...layer, color: result.value });
124
+ }
125
+ return (_jsxs("div", { className: "editor box-shadow-editor", "data-test": "box-shadow-editor", children: [_jsxs("div", { className: "editor__title-row", children: [_jsx("div", { className: "editor__title", children: "Box Shadow" }), _jsx(IconButton, { variant: "quiet", label: "Add Box Shadow", "data-test": "add-shadow", disabled: blockedBy !== null || layers === null, onClick: addShadow, children: _jsx(IconPlus, { size: 16, "aria-hidden": "true" }) })] }), visibility.visible ? _jsxs("div", { className: "box-shadow-editor__layers", children: [!layers || (wholeShadowToken && !activeDraft) ? _jsx(ControlSurface, { children: _jsx(TokenField, { property: "box-shadow", selection: selection, tokenRow: tokenRow, domElement: el, editTarget: editTarget, entries: allEntries, onAfterEdit: onAfterEdit, editMetadata: metadataFor(tokenRow) }) }) : null, layers?.map((layer, index) => {
126
+ const color = interpretTokenValue(layer.color, { table: colorContext.tokenTable });
127
+ const hex = color.tokenName && color.opacity ? colorValueToHex(color.resolvedValue) : null;
128
+ const previewResult = hex && color.opacity ? withColorOpacity(hex, color.opacity.value) : null;
129
+ const preview = previewResult?.ok ? previewResult.value : color.resolvedValue;
130
+ return (_jsxs("div", { className: "box-shadow-editor__layer", role: "group", "aria-label": `Shadow ${index + 1}`, children: [_jsx("div", { className: "box-shadow-editor__dimensions", children: DIMENSIONS.map(({ label, description, Icon }, dimension) => (_jsx(Tooltip, { content: description, disableFocus: true, children: _jsx(ControlSurface, { children: _jsx(TokenValueField, { property: "box-shadow", semanticSlot: "length", nudgeProperty: dimension === 2 ? "padding-top" : "margin-left", domElement: el, committedValue: layer.lengths[dimension].replace(/px$/i, ""), activeTokenName: tokenName(layer.lengths[dimension]), resolvedValue: resolveToken(layer.lengths[dimension], allEntries), entries: allEntries, blockedBy: blockedBy, label: label, inputDataTest: `shadow-${index}-${dimension}`, chipVariant: "small", leading: _jsx(Icon, { size: 16, stroke: 1.8, "aria-hidden": "true" }), formatRawValue: (raw) => completeCssValue(raw, valuePolicyFor("border-width")), onCommitRaw: (input) => {
131
+ const raw = completeCssValue(input, valuePolicyFor("border-width"));
132
+ if (!LENGTH.test(raw) || (dimension === 2 && /^-/.test(raw)))
133
+ return;
134
+ const lengths = [...layer.lengths];
135
+ lengths[dimension] = raw;
136
+ commitLayer(index, { ...layer, lengths });
137
+ }, onSelectToken: (token) => {
138
+ const lengths = [...layer.lengths];
139
+ lengths[dimension] = `var(${token.name})`;
140
+ commitLayer(index, { ...layer, lengths });
141
+ }, onUnlink: (raw) => {
142
+ const lengths = [...layer.lengths];
143
+ lengths[dimension] = raw;
144
+ commitLayer(index, { ...layer, lengths });
145
+ } }) }) }, label))) }), _jsx(IconButton, { variant: "quiet", className: "box-shadow-editor__remove", label: `Remove Shadow ${index + 1}`, "data-test": `remove-shadow-${index}`, disabled: blockedBy !== null, onClick: () => removeShadow(index), children: _jsx(IconMinus, { size: 16, "aria-hidden": "true" }) }), _jsx(Tooltip, { content: "Color and opacity", disableFocus: true, children: _jsx(ControlSurface, { className: "box-shadow-editor__color", children: _jsx(TokenValueField, { property: "box-shadow", semanticSlot: "color", domElement: el, isColor: true, committedValue: tokenName(layer.color) || layer.color === "currentColor" ? layer.color : colorValueToHex(layer.color) ?? layer.color, activeTokenName: color.tokenName, resolvedValue: preview, entries: allEntries, blockedBy: blockedBy, label: "Shadow Color", inputDataTest: `shadow-${index}-color`, opacity: color.opacity, onCommitRaw: (color) => commitColor(index, layer, color), onSelectToken: (token) => commitColor(index, layer, `var(${token.name})`), onUnlink: (color) => commitLayer(index, { ...layer, color }), onCommitOpacity: (opacity) => {
146
+ const result = applyColorOpacity(layer.color, opacity);
147
+ if (!result.ok)
148
+ return false;
149
+ commitLayer(index, { ...layer, color: result.value });
150
+ } }) }) })] }, index));
151
+ })] }) : null] }));
24
152
  }
@@ -1,10 +1,14 @@
1
- import type { ReactElement } from "react";
1
+ import type { ReactElement, ReactNode } from "react";
2
2
  import type { TokenEntry } from "../../css/model/index.js";
3
3
  import type { SelectedElement } from "../selection/selectionStore.js";
4
4
  import type { ResolvedProperty } from "../../css/model/index.js";
5
5
  import type { StyleSelection } from "../selection/styleSelection.js";
6
6
  export interface ColorPickerProps {
7
7
  element: SelectedElement;
8
+ title?: string;
9
+ toolbar?: ReactNode;
10
+ /** Overrides initial presence for sections that use computed paint. */
11
+ present?: boolean;
8
12
  selection?: StyleSelection | null;
9
13
  property?: string;
10
14
  entries?: TokenEntry[];
@@ -5,10 +5,13 @@ import { TokenField } from "../tokens/TokenField.js";
5
5
  import { formatInspectorLabel } from "../ui/labels.js";
6
6
  import { IconButton } from "../ui/IconButton.js";
7
7
  import { ControlSurface } from "../ui/ControlSurface.js";
8
+ import { Tooltip } from "../ui/Tooltip.js";
8
9
  import { setStyle } from "../tokens/editActions.js";
9
10
  import { getNudgeUiTokenEntries } from "../runtime/runtimeConfig.js";
10
11
  import { hasAuthoredProperty, isZeroCssValue } from "./stylePresence.js";
11
12
  import { useFieldVisibility } from "./useFieldVisibility.js";
13
+ import { inlineBlockedBy } from "./inlineAuthored.js";
14
+ import { inlineStyleWarningContent } from "../ui/InlineStyleWarning.js";
12
15
  function colorSectionTitle(property) {
13
16
  if (property === "background-color")
14
17
  return "Background Color";
@@ -30,19 +33,22 @@ export function isEmptyColorValue(value) {
30
33
  && isZeroCssValue(components[3]);
31
34
  }
32
35
  export function ColorPicker(props) {
33
- const { element, selection, property = "color", entries, tokenRow, onAfterEdit } = props;
36
+ const { element, selection, property = "color", entries, tokenRow, onAfterEdit, title, toolbar, present } = props;
34
37
  const el = element.domElement;
35
38
  const selectedElements = selection?.domElements ?? [el];
36
39
  const target = selection?.target ?? el;
40
+ const blockedBy = inlineBlockedBy(selectedElements, property);
37
41
  const allEntries = entries ?? getNudgeUiTokenEntries();
38
- const hasColor = hasAuthoredProperty(selection, property, tokenRow)
39
- || selectedElements.some((selected) => !isEmptyColorValue(getStateStyleValue(selected, property)));
42
+ const hasColor = present ?? (hasAuthoredProperty(selection, property, tokenRow)
43
+ || selectedElements.some((selected) => !isEmptyColorValue(getStateStyleValue(selected, property))));
40
44
  const visibility = useFieldVisibility(selectedElements, property, hasColor);
41
45
  const showTokenField = visibility.visible;
42
46
  function handleRemoveColor() {
47
+ if (blockedBy)
48
+ return;
43
49
  setStyle(target, property, "transparent");
44
50
  visibility.hide();
45
51
  onAfterEdit?.();
46
52
  }
47
- return (_jsxs("div", { className: `editor`, "data-test": "color-picker", "data-property": property, children: [_jsxs("div", { className: "editor__title-row", children: [_jsx("div", { className: "editor__title", children: colorSectionTitle(property) }), showTokenField ? (_jsx(IconButton, { variant: "quiet", label: `Remove ${colorSectionTitle(property)}`, "data-test": "remove-color", className: "color__remove", onClick: handleRemoveColor, children: _jsx(IconMinus, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" }) })) : (_jsx(IconButton, { variant: "quiet", label: `Add ${colorSectionTitle(property)}`, "data-test": "add-color", className: "color__add", onClick: visibility.show, children: _jsx(IconPlus, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" }) }))] }), showTokenField && (_jsx("div", { className: "color", children: _jsx(ControlSurface, { children: _jsx(TokenField, { property: property, tokenRow: tokenRow, selection: selection, domElement: el, editTarget: target, entries: allEntries, onAfterEdit: onAfterEdit }) }) }))] }));
53
+ return (_jsxs("div", { className: `editor`, "data-test": "color-picker", "data-property": property, children: [_jsxs("div", { className: "editor__title-row", children: [_jsx("div", { className: "editor__title", children: title ?? colorSectionTitle(property) }), showTokenField ? (_jsx(Tooltip, { content: inlineStyleWarningContent(blockedBy), children: _jsx(IconButton, { variant: "quiet", label: `Remove ${colorSectionTitle(property)}`, "data-test": "remove-color", className: "color__remove", disabled: blockedBy !== null, onClick: handleRemoveColor, children: _jsx(IconMinus, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" }) }) })) : (_jsx(IconButton, { variant: "quiet", label: `Add ${colorSectionTitle(property)}`, "data-test": "add-color", className: "color__add", onClick: visibility.show, children: _jsx(IconPlus, { size: "var(--icon-size-small)", stroke: 1.8, "aria-hidden": "true" }) }))] }), showTokenField && toolbar, showTokenField && (_jsx("div", { className: "color", children: _jsx(ControlSurface, { children: _jsx(TokenField, { property: property, tokenRow: tokenRow, selection: selection, domElement: el, editTarget: target, entries: allEntries, onAfterEdit: onAfterEdit }) }) }))] }));
48
54
  }
@@ -1,12 +1,10 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { TokenField } from "../tokens/TokenField.js";
3
3
  import { formatInspectorLabel } from "../ui/labels.js";
4
- import { inlineAuthoredValue, meaningfulLayoutValue } from "./layoutValue.js";
5
- import { LayoutBlockedIndicator } from "./LayoutBlockedIndicator.js";
4
+ import { meaningfulLayoutValue } from "./layoutValue.js";
6
5
  export const GAP_PRESETS = ["0", "0.25rem", "0.5rem", "0.75rem", "1rem", "1.5rem", "2rem", "3rem"];
7
6
  /** Renders a gap value with a token chip or the legacy raw-value fallback. */
8
7
  export function GapField({ property, domElement: el, editTarget, selection, entries, tokenRows, leading, onAfterEdit, }) {
9
8
  const tokenRow = tokenRows.find((row) => row.property === property) ?? null;
10
- const blockedBy = inlineAuthoredValue(el, property);
11
- return (_jsxs("span", { className: `layout-combo${blockedBy ? " layout-combo--blocked" : ""}`, "data-test": "layout-combo", "data-property": property, children: [_jsx(TokenField, { property: property, selection: selection, tokenRow: tokenRow, initialValue: meaningfulLayoutValue(el, property), domElement: el, editTarget: editTarget, entries: entries, suggestions: GAP_PRESETS, leading: leading, inputDataTest: `layout-combo-input-${property}`, label: formatInspectorLabel(property), chipVariant: "small", disabled: blockedBy !== null, onAfterEdit: onAfterEdit }), blockedBy ? _jsx(LayoutBlockedIndicator, { blockedBy: blockedBy }) : null] }));
9
+ return (_jsx("span", { className: "layout-combo", "data-test": "layout-combo", "data-property": property, children: _jsx(TokenField, { property: property, selection: selection, tokenRow: tokenRow, initialValue: meaningfulLayoutValue(el, property), domElement: el, editTarget: editTarget, entries: entries, suggestions: GAP_PRESETS, leading: leading, inputDataTest: `layout-combo-input-${property}`, label: formatInspectorLabel(property), chipVariant: "small", inlineWarningDataTest: "layout-combo-blocked", inlineWarningTooltipDataTest: "layout-combo-blocked-tooltip", onAfterEdit: onAfterEdit }) }));
12
10
  }
@@ -1,5 +1,5 @@
1
1
  import type { ReactElement } from "react";
2
- import type { EditTarget } from "../selection/editTarget.js";
2
+ import { type EditTarget } from "../selection/editTarget.js";
3
3
  export interface GridChildSectionProps {
4
4
  domElement: HTMLElement;
5
5
  editTarget?: EditTarget;
@@ -5,11 +5,15 @@ import { ControlSurface } from "../ui/ControlSurface.js";
5
5
  import { FieldRow } from "../ui/FieldRow.js";
6
6
  import { SegmentedControl } from "../ui/SegmentedControl.js";
7
7
  import { TextInput } from "../ui/TextInput.js";
8
+ import { InlineStyleWarning } from "../ui/InlineStyleWarning.js";
8
9
  import { commitGridAxisPlacement, commitGridChildAlignment, readGridAxisPlacement, readGridChildAlignment, } from "./gridChildModel.js";
10
+ import { targetElements } from "../selection/editTarget.js";
11
+ import { inlineBlockedBy } from "./inlineAuthored.js";
9
12
  function readAxis(el, axis) {
10
13
  return { placement: readGridAxisPlacement(el, axis) };
11
14
  }
12
- function AxisPlacementRow({ axis, label, state, onStart }) {
15
+ function AxisPlacementRow({ axis, label, state, elements, onStart }) {
16
+ const blockedBy = inlineBlockedBy(elements, `grid-${axis}-start`, `grid-${axis}-end`);
13
17
  const [draft, setDraft] = useState(state.placement.start);
14
18
  const draftRef = useRef(draft);
15
19
  useEffect(() => {
@@ -21,13 +25,15 @@ function AxisPlacementRow({ axis, label, state, onStart }) {
21
25
  setDraft(next);
22
26
  }
23
27
  function commit() {
28
+ if (blockedBy)
29
+ return;
24
30
  const next = draftRef.current.trim() || "auto";
25
31
  updateDraft(next);
26
32
  if (next !== state.placement.start)
27
33
  onStart(next);
28
34
  }
29
35
  const AxisIcon = axis === "column" ? IconColumns2 : IconLayoutRows;
30
- return (_jsx(FieldRow, { label: label, className: `field-row--stacked layout__grid-child-placement layout__grid-child-placement--${axis}`, "data-test": `layout-grid-child-${axis}`, children: _jsxs(ControlSurface, { children: [_jsx(AxisIcon, { className: "layout__grid-child-placement-icon", size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }), _jsx(TextInput, { appearance: "embedded", value: draft, "data-test": `layout-grid-child-${axis}-start`, "aria-label": label, onChange: (event) => updateDraft(event.target.value), onBlur: commit, onKeyDown: (event) => {
36
+ return (_jsx(FieldRow, { label: label, className: `field-row--stacked layout__grid-child-placement layout__grid-child-placement--${axis}`, "data-test": `layout-grid-child-${axis}`, children: _jsxs(ControlSurface, { children: [_jsx(AxisIcon, { className: "layout__grid-child-placement-icon", size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }), _jsx(TextInput, { appearance: "embedded", value: draft, "data-test": `layout-grid-child-${axis}-start`, "aria-label": label, disabled: blockedBy !== null, onChange: (event) => updateDraft(event.target.value), onBlur: commit, onKeyDown: (event) => {
31
37
  if (event.key === "Escape") {
32
38
  event.preventDefault();
33
39
  updateDraft(state.placement.start);
@@ -37,10 +43,12 @@ function AxisPlacementRow({ axis, label, state, onStart }) {
37
43
  event.preventDefault();
38
44
  event.currentTarget.blur();
39
45
  }
40
- } })] }) }));
46
+ } }), _jsx(InlineStyleWarning, { blockedBy: blockedBy })] }) }));
41
47
  }
42
- function AlignmentControl({ axis, value, onChange }) {
48
+ function AlignmentControl({ axis, value, elements, onChange }) {
43
49
  const horizontal = axis === "h";
50
+ const property = horizontal ? "justify-self" : "align-self";
51
+ const blockedBy = inlineBlockedBy(elements, property);
44
52
  const options = horizontal
45
53
  ? [
46
54
  { value: "start", label: "Align left", icon: _jsx(IconAlignBoxLeftMiddle, { size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }) },
@@ -54,10 +62,10 @@ function AlignmentControl({ axis, value, onChange }) {
54
62
  { value: "end", label: "Align bottom", icon: _jsx(IconAlignBoxCenterBottom, { size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }) },
55
63
  { value: "stretch", label: "Stretch vertically", icon: _jsx(IconAlignBoxCenterStretch, { size: "var(--icon-size-small)", stroke: "var(--icon-stroke-width)", "aria-hidden": "true" }) },
56
64
  ];
57
- return (_jsx(FieldRow, { label: horizontal ? "Horizontal alignment" : "Vertical alignment", hideLabel: true, className: `field-row--stacked layout__grid-child-alignment layout__grid-child-alignment--${axis}`, "data-test": `layout-grid-child-align-${axis}`, children: _jsx(SegmentedControl, { value: value === "auto" ? null : value, "aria-label": horizontal ? "Horizontal alignment" : "Vertical alignment", "data-test": `layout-grid-child-select-${horizontal ? "justify-self" : "align-self"}`, className: "layout__grid-child-alignment-control", options: options.map((option) => ({
58
- ...option,
59
- testId: `layout-grid-child-align-${axis}-${option.value}`,
60
- })), onChange: onChange, allowDeselect: true, onDeselect: () => onChange("auto") }) }));
65
+ return (_jsxs(FieldRow, { label: horizontal ? "Horizontal alignment" : "Vertical alignment", hideLabel: true, className: `field-row--stacked layout__grid-child-alignment layout__grid-child-alignment--${axis}`, "data-test": `layout-grid-child-align-${axis}`, children: [_jsx(SegmentedControl, { value: value === "auto" ? null : value, "aria-label": horizontal ? "Horizontal alignment" : "Vertical alignment", "data-test": `layout-grid-child-select-${property}`, className: "layout__grid-child-alignment-control", disabled: blockedBy !== null, options: options.map((option) => ({
66
+ ...option,
67
+ testId: `layout-grid-child-align-${axis}-${option.value}`,
68
+ })), onChange: onChange, allowDeselect: true, onDeselect: () => onChange("auto") }), _jsx(InlineStyleWarning, { blockedBy: blockedBy })] }));
61
69
  }
62
70
  /**
63
71
  * Grid child controls expose only placement starts and per-axis alignment.
@@ -66,6 +74,7 @@ function AlignmentControl({ axis, value, onChange }) {
66
74
  */
67
75
  export function GridChildSection({ domElement: el, editTarget, revision = 0, onAfterEdit, }) {
68
76
  const target = editTarget ?? el;
77
+ const elements = targetElements(target);
69
78
  const [column, setColumn] = useState(() => readAxis(el, "column"));
70
79
  const [row, setRow] = useState(() => readAxis(el, "row"));
71
80
  const [alignH, setAlignH] = useState(() => readGridChildAlignment(el, "h"));
@@ -87,5 +96,5 @@ export function GridChildSection({ domElement: el, editTarget, revision = 0, onA
87
96
  if (commitGridChildAlignment(target, axis, value).length > 0)
88
97
  handleAfterEdit();
89
98
  }
90
- return (_jsxs("div", { className: "layout__group layout__grid-child", "data-test": "layout-grid-child", children: [_jsx("div", { className: "editor__title", children: "Grid Child" }), _jsxs("div", { className: "layout__grid-child-fields", "data-test": "layout-grid-child-fields", children: [_jsx(AxisPlacementRow, { axis: "column", label: "Column", state: column, onStart: (start) => handleStart("column", start) }), _jsx(AxisPlacementRow, { axis: "row", label: "Row", state: row, onStart: (start) => handleStart("row", start) }), _jsx(AlignmentControl, { axis: "v", value: alignV, onChange: (value) => handleAlignment("v", value) }), _jsx(AlignmentControl, { axis: "h", value: alignH, onChange: (value) => handleAlignment("h", value) })] })] }));
99
+ return (_jsxs("div", { className: "layout__group layout__grid-child", "data-test": "layout-grid-child", children: [_jsx("div", { className: "editor__title", children: "Grid Child" }), _jsxs("div", { className: "layout__grid-child-fields", "data-test": "layout-grid-child-fields", children: [_jsx(AxisPlacementRow, { axis: "column", label: "Column", state: column, elements: elements, onStart: (start) => handleStart("column", start) }), _jsx(AxisPlacementRow, { axis: "row", label: "Row", state: row, elements: elements, onStart: (start) => handleStart("row", start) }), _jsx(AlignmentControl, { axis: "v", value: alignV, elements: elements, onChange: (value) => handleAlignment("v", value) }), _jsx(AlignmentControl, { axis: "h", value: alignH, elements: elements, onChange: (value) => handleAlignment("h", value) })] })] }));
91
100
  }