nudge-ui 0.2.2 → 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.
- package/README.md +164 -46
- package/dist/client.mjs +252 -61
- package/dist/css/value-semantics/colorSemantics.d.ts +4 -0
- package/dist/css/value-semantics/colorSemantics.js +17 -0
- package/dist/hosts/astro/astroRuntimeConfig.js +1 -0
- package/dist/hosts/astro/clientTransport.js +38 -32
- package/dist/hosts/astro/integration.js +5 -1
- package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
- package/dist/hosts/astro/markdownIdentity.js +81 -0
- package/dist/hosts/next/manifest.js +1 -1
- package/dist/hosts/next/sidecar.js +5 -1
- package/dist/hosts/static/manifest.js +1 -1
- package/dist/hosts/static/server.js +3 -0
- package/dist/hosts/vite/vite.d.ts +3 -0
- package/dist/hosts/vite/vite.js +24 -4
- package/dist/inspector/agent/McpConnectionDialog.js +13 -19
- package/dist/inspector/agent/activity.d.ts +18 -0
- package/dist/inspector/agent/activity.js +70 -0
- package/dist/inspector/agent/client.d.ts +2 -0
- package/dist/inspector/agent/client.js +29 -1
- package/dist/inspector/agent/connectionStatus.js +1 -1
- package/dist/inspector/agent/httpTransport.js +9 -2
- package/dist/inspector/agent/protocol.d.ts +6 -3
- package/dist/inspector/agent/protocol.js +1 -1
- package/dist/inspector/agent/verification.d.ts +11 -1
- package/dist/inspector/agent/verification.js +53 -25
- package/dist/inspector/canvas/AgentActivityOverlay.d.ts +13 -0
- package/dist/inspector/canvas/AgentActivityOverlay.js +111 -0
- package/dist/inspector/canvas/CanvasCard.d.ts +9 -2
- package/dist/inspector/canvas/CanvasCard.js +133 -38
- package/dist/inspector/canvas/CanvasElementOverlay.js +152 -16
- package/dist/inspector/canvas/CanvasToolIcons.d.ts +10 -0
- package/dist/inspector/canvas/CanvasToolIcons.js +20 -0
- package/dist/inspector/canvas/CanvasToolbar.js +8 -4
- package/dist/inspector/canvas/CanvasWorkspace.js +225 -57
- package/dist/inspector/canvas/StaleChangeIndicator.js +3 -13
- package/dist/inspector/canvas/agentPresentation.d.ts +8 -8
- package/dist/inspector/canvas/agentPresentation.js +64 -52
- package/dist/inspector/canvas/canvasGestures.d.ts +1 -1
- package/dist/inspector/canvas/canvasGestures.js +1 -1
- package/dist/inspector/canvas/canvasStore.d.ts +46 -82
- package/dist/inspector/canvas/canvasStore.js +251 -284
- package/dist/inspector/canvas/frameContent.d.ts +21 -0
- package/dist/inspector/canvas/frameContent.js +44 -0
- package/dist/inspector/canvas/frameProtocol.d.ts +21 -4
- package/dist/inspector/canvas/frameProtocol.js +3 -3
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +3 -1
- package/dist/inspector/canvas/keyboardShortcuts.js +4 -4
- package/dist/inspector/canvas/layout.d.ts +52 -0
- package/dist/inspector/canvas/layout.js +106 -0
- package/dist/inspector/canvas/projection.d.ts +15 -5
- package/dist/inspector/canvas/projection.js +69 -13
- package/dist/inspector/canvas/rendererBootstrap.js +32 -4
- package/dist/inspector/canvas/rendererElementSelector.js +47 -6
- package/dist/inspector/canvas/rendererStylesheet.js +2 -2
- package/dist/inspector/canvas/resizeHandleScale.js +1 -1
- package/dist/inspector/canvas/sessionStore.d.ts +11 -26
- package/dist/inspector/canvas/sessionStore.js +43 -183
- package/dist/inspector/canvas/staleChangeDetector.js +9 -3
- package/dist/inspector/canvas/useCanvasLayoutAnimation.d.ts +5 -0
- package/dist/inspector/canvas/useCanvasLayoutAnimation.js +107 -0
- package/dist/inspector/canvas/viewStore.d.ts +38 -0
- package/dist/inspector/canvas/viewStore.js +104 -0
- package/dist/inspector/canvas/wheelPan.d.ts +8 -0
- package/dist/inspector/canvas/wheelPan.js +8 -0
- package/dist/inspector/changes/changesLog.d.ts +6 -5
- package/dist/inspector/changes/changesLog.js +40 -32
- package/dist/inspector/changes/draftChanges.d.ts +56 -0
- package/dist/inspector/changes/draftChanges.js +300 -0
- package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
- package/dist/inspector/changes/previewDiagnostics.js +11 -25
- package/dist/inspector/clientManifest.d.ts +1 -1
- package/dist/inspector/comments/CommentsOverlay.d.ts +2 -0
- package/dist/inspector/comments/CommentsOverlay.js +250 -0
- package/dist/inspector/comments/element.d.ts +6 -0
- package/dist/inspector/comments/element.js +47 -0
- package/dist/inspector/comments/store.d.ts +29 -0
- package/dist/inspector/comments/store.js +121 -0
- package/dist/inspector/comments/verification.d.ts +5 -0
- package/dist/inspector/comments/verification.js +52 -0
- package/dist/inspector/drafts/model.d.ts +35 -0
- package/dist/inspector/drafts/model.js +45 -0
- package/dist/inspector/drafts/store.d.ts +28 -0
- package/dist/inspector/drafts/store.js +231 -0
- package/dist/inspector/index.js +20 -27
- package/dist/inspector/inline-text/inlineTextEditor.js +7 -0
- package/dist/inspector/inspection/useBrowserCssInspection.js +15 -1
- package/dist/inspector/iterations/capture.d.ts +2 -0
- package/dist/inspector/iterations/capture.js +173 -0
- package/dist/inspector/iterations/client.d.ts +7 -0
- package/dist/inspector/iterations/client.js +52 -0
- package/dist/inspector/iterations/coordinator.d.ts +15 -0
- package/dist/inspector/iterations/coordinator.js +130 -0
- package/dist/inspector/iterations/prompt.d.ts +3 -0
- package/dist/inspector/iterations/prompt.js +26 -0
- package/dist/inspector/overlay/DomNavigator.js +21 -15
- package/dist/inspector/overlay/interactionStyles.js +3 -1
- package/dist/inspector/overlay/spacingGestures.d.ts +13 -1
- package/dist/inspector/overlay/spacingGestures.js +82 -5
- package/dist/inspector/projection/{workspaceProjection.d.ts → draftProjection.d.ts} +6 -6
- package/dist/inspector/projection/{workspaceProjection.js → draftProjection.js} +4 -4
- package/dist/inspector/projection/renderedInstance.d.ts +2 -1
- package/dist/inspector/projection/renderedInstance.js +9 -5
- package/dist/inspector/projection/structuralProjection.d.ts +2 -1
- package/dist/inspector/projection/structuralProjection.js +19 -15
- package/dist/inspector/projection/textProjection.d.ts +2 -1
- package/dist/inspector/projection/textProjection.js +8 -4
- package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
- package/dist/inspector/prompt/clipboardHandoff.d.ts +10 -18
- package/dist/inspector/prompt/clipboardHandoff.js +92 -143
- package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
- package/dist/inspector/prompt/generatePrompt.js +17 -16
- package/dist/inspector/runtime/runtimeConfig.d.ts +9 -0
- package/dist/inspector/runtime/runtimeConfig.js +24 -0
- package/dist/inspector/settings/SettingsDialog.js +21 -8
- package/dist/inspector/shell/AgentStatusButton.d.ts +11 -0
- package/dist/inspector/shell/AgentStatusButton.js +36 -0
- package/dist/inspector/shell/AppShell.js +4 -2
- package/dist/inspector/shell/ChangesLog.js +46 -26
- package/dist/inspector/shell/CopyPromptButton.js +138 -89
- package/dist/inspector/shell/EmptyState.js +9 -8
- package/dist/inspector/shell/InspectorShell.js +13 -21
- package/dist/inspector/shell/PeekOriginalButton.js +24 -23
- package/dist/inspector/shell/originalPreview.js +5 -5
- package/dist/inspector/shell/shortcuts.d.ts +3 -0
- package/dist/inspector/shell/shortcuts.js +11 -0
- package/dist/inspector/sketch/SketchEditor.js +14 -14
- package/dist/inspector/sketch/SketchEntryButton.js +1 -1
- package/dist/inspector/sketch/SketchFrameOverlay.d.ts +3 -1
- package/dist/inspector/sketch/SketchFrameOverlay.js +11 -8
- package/dist/inspector/sketch/SketchLayersPanel.js +13 -5
- package/dist/inspector/sketch/SketchOverlay.js +7 -7
- package/dist/inspector/sketch/SketchWorkspace.js +18 -12
- package/dist/inspector/sketch/interaction.d.ts +1 -0
- package/dist/inspector/sketch/interaction.js +8 -4
- package/dist/inspector/sketch/model.d.ts +5 -0
- package/dist/inspector/sketch/model.js +6 -2
- package/dist/inspector/sketch/raster.d.ts +1 -2
- package/dist/inspector/sketch/raster.js +68 -4
- package/dist/inspector/styleEditors/BackgroundEditor.d.ts +4 -0
- package/dist/inspector/styleEditors/BackgroundEditor.js +195 -0
- package/dist/inspector/styleEditors/BorderEditor.js +49 -78
- package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -1
- package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +1 -2
- package/dist/inspector/styleEditors/BoxShadowEditor.js +132 -4
- package/dist/inspector/styleEditors/ColorPicker.d.ts +5 -1
- package/dist/inspector/styleEditors/ColorPicker.js +10 -4
- package/dist/inspector/styleEditors/GapField.js +3 -5
- package/dist/inspector/styleEditors/GridChildSection.d.ts +1 -1
- package/dist/inspector/styleEditors/GridChildSection.js +18 -9
- package/dist/inspector/styleEditors/GridPicker.d.ts +1 -1
- package/dist/inspector/styleEditors/GridPicker.js +8 -2
- package/dist/inspector/styleEditors/GridSection.js +1 -1
- package/dist/inspector/styleEditors/GridValueField.js +19 -14
- package/dist/inspector/styleEditors/ImageBackgroundEditor.d.ts +18 -0
- package/dist/inspector/styleEditors/ImageBackgroundEditor.js +118 -0
- package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +2 -2
- package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +3 -3
- package/dist/inspector/styleEditors/LayoutComboField.js +6 -4
- package/dist/inspector/styleEditors/LayoutDropdown.js +6 -3
- package/dist/inspector/styleEditors/LayoutSection.js +32 -11
- package/dist/inspector/styleEditors/SpacingBox.js +7 -5
- package/dist/inspector/styleEditors/Typography.js +11 -3
- package/dist/inspector/styleEditors/backgroundLayers.d.ts +24 -0
- package/dist/inspector/styleEditors/backgroundLayers.js +51 -0
- package/dist/inspector/styleEditors/gradientValue.d.ts +17 -0
- package/dist/inspector/styleEditors/gradientValue.js +114 -0
- package/dist/inspector/styleEditors/inlineAuthored.d.ts +10 -0
- package/dist/inspector/styleEditors/inlineAuthored.js +114 -0
- package/dist/inspector/styleEditors/layoutValue.d.ts +0 -8
- package/dist/inspector/styleEditors/layoutValue.js +0 -42
- package/dist/inspector/styleEditors/nudgeValue.d.ts +2 -2
- package/dist/inspector/styleEditors/nudgeValue.js +36 -8
- package/dist/inspector/tokens/TokenField.d.ts +7 -0
- package/dist/inspector/tokens/TokenField.js +29 -21
- package/dist/inspector/tokens/TokenLabel.js +5 -14
- package/dist/inspector/tokens/editActions.d.ts +1 -1
- package/dist/inspector/tokens/editActions.js +1 -1
- package/dist/inspector/ui/AtRuleContext.js +4 -6
- package/dist/inspector/ui/Button.d.ts +6 -2
- package/dist/inspector/ui/Button.js +4 -3
- package/dist/inspector/ui/ControlSurface.d.ts +2 -2
- package/dist/inspector/ui/ControlSurface.js +4 -3
- package/dist/inspector/ui/InlineStyleWarning.d.ts +11 -0
- package/dist/inspector/ui/InlineStyleWarning.js +13 -0
- package/dist/inspector/ui/InspectorPopover.d.ts +2 -1
- package/dist/inspector/ui/InspectorPopover.js +4 -5
- package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
- package/dist/inspector/ui/PopoverListbox.js +8 -7
- package/dist/inspector/ui/SegmentedControl.d.ts +2 -1
- package/dist/inspector/ui/SegmentedControl.js +2 -2
- package/dist/inspector/ui/Select.d.ts +6 -1
- package/dist/inspector/ui/Select.js +7 -11
- package/dist/inspector/ui/SideValuesField.js +1 -1
- package/dist/inspector/ui/Tooltip.d.ts +26 -0
- package/dist/inspector/ui/Tooltip.js +32 -0
- package/dist/inspector/ui/classNames.d.ts +2 -0
- package/dist/inspector/ui/classNames.js +4 -0
- package/dist/inspector/ui/customCursors.d.ts +23 -0
- package/dist/inspector/ui/customCursors.js +122 -0
- package/dist/inspector/ui/dragCursor.d.ts +0 -2
- package/dist/inspector/ui/dragCursor.js +2 -10
- package/dist/inspector/ui/portalContainer.d.ts +2 -0
- package/dist/inspector/ui/portalContainer.js +6 -0
- package/dist/inspector/ui/styles.js +29 -21
- package/dist/inspector/workspace/commands.d.ts +9 -0
- package/dist/inspector/workspace/commands.js +82 -0
- package/dist/inspector/workspace/controller.d.ts +4 -0
- package/dist/inspector/workspace/controller.js +66 -0
- package/dist/inspector/workspace/handoff.d.ts +42 -0
- package/dist/inspector/workspace/handoff.js +115 -0
- package/dist/inspector/workspace/timeline.d.ts +30 -0
- package/dist/inspector/workspace/timeline.js +108 -0
- package/dist/internal/agent-protocol.d.ts +19 -2
- package/dist/internal/agent-protocol.js +13 -0
- package/dist/nudge-ui.mjs +558 -311
- package/dist/project/artifacts.d.ts +13 -0
- package/dist/project/artifacts.js +253 -0
- package/dist/transport/artifacts.d.ts +8 -0
- package/dist/transport/artifacts.js +9 -0
- package/dist/transport/editor.js +3 -1
- package/dist/transport/routes.d.ts +2 -0
- package/dist/transport/routes.js +2 -0
- package/package.json +6 -2
- package/dist/inspector/changes/workspaceChanges.d.ts +0 -47
- package/dist/inspector/changes/workspaceChanges.js +0 -265
|
@@ -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 {
|
|
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 {
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
return
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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 =
|
|
212
|
-
|
|
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",
|
|
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",
|
|
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
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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
|
|
264
|
-
return
|
|
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
|
|
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 {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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
|
-
|
|
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
|
}
|
|
@@ -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 (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
}
|