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.
- package/README.md +164 -46
- package/dist/client.mjs +252 -54
- 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 +41 -32
- package/dist/hosts/astro/integration.d.ts +2 -2
- package/dist/hosts/astro/integration.js +9 -4
- package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
- package/dist/hosts/astro/markdownIdentity.js +81 -0
- package/dist/hosts/environment.d.ts +15 -0
- package/dist/hosts/environment.js +16 -0
- package/dist/hosts/next/manifest.js +1 -1
- package/dist/hosts/next/sidecar.js +12 -2
- package/dist/hosts/next/wrapper.d.ts +2 -0
- package/dist/hosts/next/wrapper.js +2 -1
- package/dist/hosts/projectBridge.d.ts +1 -0
- package/dist/hosts/projectBridge.js +1 -0
- package/dist/hosts/static/manifest.js +3 -1
- package/dist/hosts/static/server.js +4 -0
- package/dist/hosts/vite/vite.d.ts +4 -0
- package/dist/hosts/vite/vite.js +28 -5
- package/dist/inspector/agent/McpConnectionDialog.d.ts +3 -2
- package/dist/inspector/agent/McpConnectionDialog.js +23 -22
- package/dist/inspector/agent/activity.d.ts +18 -0
- package/dist/inspector/agent/activity.js +70 -0
- package/dist/inspector/agent/client.d.ts +8 -0
- package/dist/inspector/agent/client.js +65 -5
- package/dist/inspector/agent/connectionStatus.d.ts +3 -3
- package/dist/inspector/agent/connectionStatus.js +9 -2
- package/dist/inspector/agent/httpTransport.d.ts +6 -0
- package/dist/inspector/agent/httpTransport.js +50 -3
- package/dist/inspector/agent/protocol.d.ts +9 -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 +200 -22
- 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 +243 -56
- 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 +34 -4
- package/dist/inspector/canvas/frameProtocol.js +9 -2
- package/dist/inspector/canvas/keyboardShortcuts.d.ts +4 -1
- package/dist/inspector/canvas/keyboardShortcuts.js +5 -3
- package/dist/inspector/canvas/layout.d.ts +52 -0
- package/dist/inspector/canvas/layout.js +106 -0
- package/dist/inspector/canvas/linkEligibility.d.ts +0 -5
- package/dist/inspector/canvas/linkEligibility.js +0 -29
- package/dist/inspector/canvas/projection.d.ts +15 -5
- package/dist/inspector/canvas/projection.js +69 -13
- package/dist/inspector/canvas/rendererBootstrap.js +45 -4
- package/dist/inspector/canvas/rendererElementSelector.d.ts +1 -1
- package/dist/inspector/canvas/rendererElementSelector.js +102 -45
- 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 +3 -1
- package/dist/inspector/clientManifest.js +1 -0
- 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 +26 -35
- 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.d.ts +10 -0
- package/dist/inspector/overlay/DomNavigator.js +46 -0
- package/dist/inspector/overlay/InspectorOverlay.js +6 -2
- package/dist/inspector/overlay/clickPolicy.d.ts +18 -2
- package/dist/inspector/overlay/clickPolicy.js +34 -3
- package/dist/inspector/overlay/elementSelector.d.ts +1 -1
- package/dist/inspector/overlay/elementSelector.js +18 -7
- package/dist/inspector/overlay/interactionStyles.js +3 -1
- package/dist/inspector/overlay/spacingGestures.d.ts +15 -3
- package/dist/inspector/overlay/spacingGestures.js +88 -13
- 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 +10 -1
- package/dist/inspector/runtime/runtimeConfig.js +24 -0
- package/dist/inspector/selection/hierarchy.d.ts +6 -0
- package/dist/inspector/selection/hierarchy.js +8 -0
- package/dist/inspector/settings/SettingsDialog.d.ts +1 -1
- package/dist/inspector/settings/SettingsDialog.js +22 -9
- 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 +47 -27
- package/dist/inspector/shell/CopyPromptButton.js +146 -90
- package/dist/inspector/shell/EmptyState.js +9 -8
- package/dist/inspector/shell/InspectorShell.js +14 -25
- 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/sketch/store.js +48 -23
- 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 +16 -9
- 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 +4 -4
- package/dist/inspector/styleEditors/nudgeValue.js +41 -11
- package/dist/inspector/tokens/TokenField.d.ts +7 -0
- package/dist/inspector/tokens/TokenField.js +49 -22
- package/dist/inspector/tokens/TokenLabel.js +5 -14
- package/dist/inspector/tokens/TokensPanel.js +2 -1
- package/dist/inspector/tokens/dragPointerLock.d.ts +8 -0
- package/dist/inspector/tokens/dragPointerLock.js +70 -0
- package/dist/inspector/tokens/editActions.d.ts +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/Disclosure.d.ts +22 -0
- package/dist/inspector/ui/Disclosure.js +13 -0
- 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 +6 -0
- package/dist/inspector/ui/dragCursor.js +13 -0
- package/dist/inspector/ui/portalContainer.d.ts +2 -0
- package/dist/inspector/ui/portalContainer.js +6 -0
- package/dist/inspector/ui/styles.js +34 -24
- 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 +560 -299
- 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.d.ts +20 -1
- package/dist/transport/editor.js +44 -11
- package/dist/transport/routes.d.ts +6 -1
- package/dist/transport/routes.js +6 -1
- package/package.json +6 -2
- package/dist/inspector/changes/workspaceChanges.d.ts +0 -43
- package/dist/inspector/changes/workspaceChanges.js +0 -239
- package/dist/inspector/shell/DomNavigation.d.ts +0 -8
- package/dist/inspector/shell/DomNavigation.js +0 -30
|
@@ -2,12 +2,16 @@ import { completeCssValue, CSS_NUMBER_SOURCE } from "./completeCssValue.js";
|
|
|
2
2
|
import { valuePolicyFor } from "./valuePolicy.js";
|
|
3
3
|
const CSS_NUMBER = new RegExp(`^(?:${CSS_NUMBER_SOURCE})$`, "i");
|
|
4
4
|
const CSS_NUMERIC_LITERAL = new RegExp(`^(${CSS_NUMBER_SOURCE})(px|rem|em|%)?$`, "i");
|
|
5
|
-
const
|
|
5
|
+
const DRAG_PIXELS_PER_STEP = 16;
|
|
6
|
+
const LARGE_DRAG_PIXELS_PER_STEP = 8;
|
|
7
|
+
const DRAG_NUDGE_PROPERTY = /^(?:(?:padding|margin)-(?:top|right|bottom|left|horizontal|vertical)|(?:top|right|bottom|left|inset|inset-(?:horizontal|vertical))|(?:row|column)-gap|(?:font-size|letter-spacing|line-height|opacity)|border-radius|border-(?:top-left|top-right|bottom-right|bottom-left)-radius)$/;
|
|
6
8
|
/**
|
|
7
9
|
* Returns a nudged CSS numeric literal, or null when the value is not a
|
|
8
10
|
* standalone number that the inspector can safely edit.
|
|
9
11
|
*/
|
|
10
12
|
export function nudgeCssValue(property, rawValue, direction, large = false) {
|
|
13
|
+
if (property === "opacity")
|
|
14
|
+
return nudgeOpacityValue(rawValue, direction, large);
|
|
11
15
|
const normalised = normaliseForNudge(property, rawValue);
|
|
12
16
|
const parsed = parseNumericLiteral(normalised);
|
|
13
17
|
if (!parsed)
|
|
@@ -23,13 +27,13 @@ export function supportsDragNudge(property) {
|
|
|
23
27
|
return DRAG_NUDGE_PROPERTY.test(property);
|
|
24
28
|
}
|
|
25
29
|
/**
|
|
26
|
-
* Applies one nudge per
|
|
27
|
-
*
|
|
28
|
-
* value, the first step snaps to the next large-step boundary in the
|
|
29
|
-
* direction.
|
|
30
|
+
* Applies one regular nudge per sixteen horizontal pointer pixels and one large
|
|
31
|
+
* nudge per eight horizontal pointer pixels. When a large drag starts from an
|
|
32
|
+
* off-grid value, the first step snaps to the next large-step boundary in the
|
|
33
|
+
* drag direction.
|
|
30
34
|
*/
|
|
31
35
|
export function nudgeCssValueByDrag(property, rawValue, deltaX, large = false, snapToLargeStep = false) {
|
|
32
|
-
const steps = Math.trunc(Math.abs(deltaX) / (large ?
|
|
36
|
+
const steps = Math.trunc(Math.abs(deltaX) / (large ? LARGE_DRAG_PIXELS_PER_STEP : DRAG_PIXELS_PER_STEP));
|
|
33
37
|
if (steps === 0)
|
|
34
38
|
return null;
|
|
35
39
|
const direction = deltaX < 0 ? -1 : 1;
|
|
@@ -52,16 +56,16 @@ export function nudgeCssValueByDrag(property, rawValue, deltaX, large = false, s
|
|
|
52
56
|
}
|
|
53
57
|
/** Returns whether a field has a numeric value that can respond to dragging. */
|
|
54
58
|
export function canNudgeCssValueByDrag(property, rawValue) {
|
|
55
|
-
return nudgeCssValueByDrag(property, rawValue,
|
|
56
|
-
|| nudgeCssValueByDrag(property, rawValue, -
|
|
59
|
+
return nudgeCssValueByDrag(property, rawValue, DRAG_PIXELS_PER_STEP) !== null
|
|
60
|
+
|| nudgeCssValueByDrag(property, rawValue, -DRAG_PIXELS_PER_STEP) !== null;
|
|
57
61
|
}
|
|
58
62
|
/** Returns a clamped opacity percentage nudged by 1%, or 10% with Shift. */
|
|
59
63
|
export function nudgeOpacityValue(rawValue, direction, large = false) {
|
|
60
|
-
const
|
|
61
|
-
if (
|
|
64
|
+
const percent = parseOpacityPercent(rawValue);
|
|
65
|
+
if (percent === null)
|
|
62
66
|
return null;
|
|
63
67
|
const step = large ? 10 : 1;
|
|
64
|
-
const next = Math.min(100, Math.max(0,
|
|
68
|
+
const next = Math.min(100, Math.max(0, percent + direction * step));
|
|
65
69
|
return `${formatNumber(next)}%`;
|
|
66
70
|
}
|
|
67
71
|
function normaliseForNudge(property, rawValue) {
|
|
@@ -116,6 +120,8 @@ function snapCssValueToLargeStep(property, rawValue, direction) {
|
|
|
116
120
|
return snappedParts.join(", ");
|
|
117
121
|
}
|
|
118
122
|
function snapNumericValueToLargeStep(property, rawValue, direction) {
|
|
123
|
+
if (property === "opacity")
|
|
124
|
+
return snapOpacityValueToLargeStep(rawValue, direction);
|
|
119
125
|
const normalised = normaliseForNudge(property, rawValue);
|
|
120
126
|
const parsed = parseNumericLiteral(normalised);
|
|
121
127
|
if (!parsed)
|
|
@@ -132,6 +138,30 @@ function snapNumericValueToLargeStep(property, rawValue, direction) {
|
|
|
132
138
|
next = clampNudgeNumber(property, next);
|
|
133
139
|
return `${formatNumber(next)}${parsed.unit}`;
|
|
134
140
|
}
|
|
141
|
+
function snapOpacityValueToLargeStep(rawValue, direction) {
|
|
142
|
+
const percent = parseOpacityPercent(rawValue);
|
|
143
|
+
if (percent === null)
|
|
144
|
+
return null;
|
|
145
|
+
const step = 10;
|
|
146
|
+
let next = direction > 0
|
|
147
|
+
? Math.ceil(percent / step) * step
|
|
148
|
+
: Math.floor(percent / step) * step;
|
|
149
|
+
if ((direction > 0 && next <= percent) || (direction < 0 && next >= percent)) {
|
|
150
|
+
next += direction * step;
|
|
151
|
+
}
|
|
152
|
+
next = Math.min(100, Math.max(0, next));
|
|
153
|
+
return `${formatNumber(next)}%`;
|
|
154
|
+
}
|
|
155
|
+
function parseOpacityPercent(rawValue) {
|
|
156
|
+
const parsed = parseNumericLiteral(rawValue);
|
|
157
|
+
if (!parsed)
|
|
158
|
+
return null;
|
|
159
|
+
if (parsed.unit === "%")
|
|
160
|
+
return parsed.number;
|
|
161
|
+
if (parsed.unit === "" && parsed.number >= 0 && parsed.number <= 1)
|
|
162
|
+
return parsed.number * 100;
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
135
165
|
function isLineHeight(property) {
|
|
136
166
|
return property === "line-height" || property.includes("line-height");
|
|
137
167
|
}
|
|
@@ -7,6 +7,8 @@ import { type EditTarget } from "../selection/editTarget.js";
|
|
|
7
7
|
import type { StyleSelection } from "../selection/styleSelection.js";
|
|
8
8
|
export interface TokenValueFieldProps {
|
|
9
9
|
property: string;
|
|
10
|
+
/** Numeric editing policy for a scalar slot inside a composite property. */
|
|
11
|
+
nudgeProperty?: string;
|
|
10
12
|
domElement?: HTMLElement;
|
|
11
13
|
semanticSlot?: TokenSemanticSlot;
|
|
12
14
|
committedValue: string;
|
|
@@ -34,6 +36,9 @@ export interface TokenValueFieldProps {
|
|
|
34
36
|
onCommitOpacity?(value: string): boolean | void;
|
|
35
37
|
atRules?: readonly AtRuleContext[];
|
|
36
38
|
chipVariant?: "default" | "small";
|
|
39
|
+
blockedBy?: string | null;
|
|
40
|
+
inlineWarningDataTest?: string;
|
|
41
|
+
inlineWarningTooltipDataTest?: string;
|
|
37
42
|
}
|
|
38
43
|
export interface TokenFieldProps {
|
|
39
44
|
property: string;
|
|
@@ -62,6 +67,8 @@ export interface TokenFieldProps {
|
|
|
62
67
|
mixed?: boolean;
|
|
63
68
|
/** Referenced tokens used for raw color-field behavior; not rendered inline. */
|
|
64
69
|
attributionTokens?: string[];
|
|
70
|
+
inlineWarningDataTest?: string;
|
|
71
|
+
inlineWarningTooltipDataTest?: string;
|
|
65
72
|
}
|
|
66
73
|
export declare function colorValueToHex(value: string): string | null;
|
|
67
74
|
export declare function TokenValueField(props: TokenValueFieldProps): ReactElement;
|
|
@@ -12,8 +12,14 @@ import { PopoverListbox } from "../ui/PopoverListbox.js";
|
|
|
12
12
|
import { ColorSwatch } from "../ui/ColorSwatch.js";
|
|
13
13
|
import { getStateStyleValue } from "../shell/stateValue.js";
|
|
14
14
|
import { AtRuleIndicator, useFieldAtRules } from "../ui/AtRuleContext.js";
|
|
15
|
+
import { Tooltip } from "../ui/Tooltip.js";
|
|
16
|
+
import { cx } from "../ui/classNames.js";
|
|
15
17
|
import { TokenChip } from "./TokenChip.js";
|
|
18
|
+
import { startDragPointerLock } from "./dragPointerLock.js";
|
|
19
|
+
import { createChangeHistoryGroup } from "../changes/draftChanges.js";
|
|
16
20
|
import { isMultiTarget } from "../selection/editTarget.js";
|
|
21
|
+
import { inlineBlockedBy } from "../styleEditors/inlineAuthored.js";
|
|
22
|
+
import { InlineStyleWarning } from "../ui/InlineStyleWarning.js";
|
|
17
23
|
const NON_COLOR_FACTS = { hasEmbeddedAlpha: false, isExpression: false, opacityEditable: false };
|
|
18
24
|
function colorFacts(value) {
|
|
19
25
|
return selectTokens({
|
|
@@ -153,7 +159,8 @@ function NativeColorSwatch({ value, onChange, disabled, }) {
|
|
|
153
159
|
return (_jsxs("label", { className: "token-color-control", "data-resolved": hasRenderableColor ? "true" : "false", children: [_jsx(ColorSwatch, { color: cssColor ?? "transparent", "data-test": "token-color-swatch" }), _jsx("input", { className: "token-color-control__input", "data-test": "token-color-input", type: "color", value: hex, disabled: disabled, "aria-label": "Choose color", onChange: (event) => onChange(event.target.value) })] }));
|
|
154
160
|
}
|
|
155
161
|
export function TokenValueField(props) {
|
|
156
|
-
const { property, domElement, semanticSlot, committedValue, resolvedValue = committedValue, activeTokenName: controlledTokenName = null, entries, suggestions = [], inputDataTest = "raw-input", allowedTokenNames, isColor = false, disabled = false, mixed = false, formatRawValue = (value) => value.trim(), onCommitRaw, onSelectToken, onUnlink, attributionTokens = [], leading, trailing, className, label, opacity, color, onCommitOpacity, atRules, chipVariant = "default", } = props;
|
|
162
|
+
const { property, nudgeProperty = property, domElement, semanticSlot, committedValue, resolvedValue = committedValue, activeTokenName: controlledTokenName = null, entries, suggestions = [], inputDataTest = "raw-input", allowedTokenNames, isColor = false, disabled = false, mixed = false, formatRawValue = (value) => value.trim(), onCommitRaw, onSelectToken, onUnlink, attributionTokens = [], leading, trailing, className, label, opacity, color, onCommitOpacity, atRules, chipVariant = "default", blockedBy = null, inlineWarningDataTest, inlineWarningTooltipDataTest, } = props;
|
|
163
|
+
const fieldDisabled = disabled || blockedBy !== null;
|
|
157
164
|
const inheritedAtRules = useFieldAtRules(property);
|
|
158
165
|
const fieldAtRules = atRules ?? inheritedAtRules;
|
|
159
166
|
const controlledToken = controlledTokenName ? entries.find((entry) => entry.name === controlledTokenName) : null;
|
|
@@ -241,6 +248,8 @@ export function TokenValueField(props) {
|
|
|
241
248
|
handleTokenSelect(chosen);
|
|
242
249
|
}
|
|
243
250
|
function commitRawValue(value = rawValue) {
|
|
251
|
+
if (fieldDisabled)
|
|
252
|
+
return;
|
|
244
253
|
if (mixed && value.trim().toLowerCase() === "mixed")
|
|
245
254
|
return;
|
|
246
255
|
const formatted = formatRawValue(value);
|
|
@@ -284,7 +293,7 @@ export function TokenValueField(props) {
|
|
|
284
293
|
if (direction && !event.altKey && !event.ctrlKey && !event.metaKey) {
|
|
285
294
|
const next = property === "opacity"
|
|
286
295
|
? nudgeOpacityValue(rawValue, direction, event.shiftKey)
|
|
287
|
-
: nudgeCssValue(
|
|
296
|
+
: nudgeCssValue(nudgeProperty, rawValue, direction, event.shiftKey);
|
|
288
297
|
if (next) {
|
|
289
298
|
event.preventDefault();
|
|
290
299
|
event.stopPropagation();
|
|
@@ -318,8 +327,9 @@ export function TokenValueField(props) {
|
|
|
318
327
|
const drag = dragNudgeRef.current;
|
|
319
328
|
if (!drag)
|
|
320
329
|
return;
|
|
321
|
-
releasePointerCapture(drag);
|
|
322
330
|
dragNudgeRef.current = null;
|
|
331
|
+
drag.pointerLock?.stop();
|
|
332
|
+
releasePointerCapture(drag);
|
|
323
333
|
setIsDraggingNudge(false);
|
|
324
334
|
}, []);
|
|
325
335
|
useEffect(() => {
|
|
@@ -331,13 +341,16 @@ export function TokenValueField(props) {
|
|
|
331
341
|
};
|
|
332
342
|
}, [stopDragNudge]);
|
|
333
343
|
function handleDragNudgePointerDown(event) {
|
|
334
|
-
if (
|
|
344
|
+
if (event.button !== 0)
|
|
335
345
|
return;
|
|
336
|
-
if (!
|
|
346
|
+
if (fieldDisabled || !supportsDragNudge(nudgeProperty))
|
|
347
|
+
return;
|
|
348
|
+
if (!canNudgeCssValueByDrag(nudgeProperty, rawValue))
|
|
337
349
|
return;
|
|
338
350
|
stopDragNudge();
|
|
339
351
|
const handle = event.currentTarget;
|
|
340
352
|
const drag = {
|
|
353
|
+
commit: createChangeHistoryGroup(),
|
|
341
354
|
handle,
|
|
342
355
|
pointerId: event.pointerId,
|
|
343
356
|
lastClientX: event.clientX,
|
|
@@ -350,6 +363,11 @@ export function TokenValueField(props) {
|
|
|
350
363
|
dragNudgeRef.current = drag;
|
|
351
364
|
if (typeof handle.setPointerCapture === "function")
|
|
352
365
|
handle.setPointerCapture(event.pointerId);
|
|
366
|
+
if (event.pointerType === "mouse") {
|
|
367
|
+
drag.pointerLock = startDragPointerLock(handle, { x: event.clientX, y: event.clientY }, (mouseEvent) => {
|
|
368
|
+
updateDragNudge(mouseEvent, mouseEvent.movementX);
|
|
369
|
+
}, stopDragNudge);
|
|
370
|
+
}
|
|
353
371
|
setIsDraggingNudge(true);
|
|
354
372
|
event.preventDefault();
|
|
355
373
|
event.stopPropagation();
|
|
@@ -358,8 +376,16 @@ export function TokenValueField(props) {
|
|
|
358
376
|
const drag = dragNudgeRef.current;
|
|
359
377
|
if (!drag || drag.pointerId !== event.pointerId)
|
|
360
378
|
return;
|
|
379
|
+
if (drag.pointerLock?.isLocked())
|
|
380
|
+
return;
|
|
361
381
|
const movementX = event.clientX - drag.lastClientX;
|
|
362
382
|
drag.lastClientX = event.clientX;
|
|
383
|
+
updateDragNudge(event, movementX);
|
|
384
|
+
}
|
|
385
|
+
function updateDragNudge(event, movementX) {
|
|
386
|
+
const drag = dragNudgeRef.current;
|
|
387
|
+
if (!drag)
|
|
388
|
+
return;
|
|
363
389
|
if (event.shiftKey !== drag.shiftActive) {
|
|
364
390
|
drag.shiftActive = event.shiftKey;
|
|
365
391
|
drag.startValue = drag.lastValue;
|
|
@@ -367,7 +393,7 @@ export function TokenValueField(props) {
|
|
|
367
393
|
drag.shiftSnapPending = event.shiftKey;
|
|
368
394
|
}
|
|
369
395
|
drag.deltaX += movementX;
|
|
370
|
-
const next = nudgeCssValueByDrag(
|
|
396
|
+
const next = nudgeCssValueByDrag(nudgeProperty, drag.startValue, drag.deltaX, drag.shiftActive, drag.shiftActive && drag.shiftSnapPending);
|
|
371
397
|
if (next === null || next === drag.lastValue)
|
|
372
398
|
return;
|
|
373
399
|
drag.lastValue = next;
|
|
@@ -380,7 +406,7 @@ export function TokenValueField(props) {
|
|
|
380
406
|
event.stopPropagation();
|
|
381
407
|
setRawValue(next);
|
|
382
408
|
setActiveTokenName(null);
|
|
383
|
-
onCommitRaw(next);
|
|
409
|
+
drag.commit(() => onCommitRaw(next));
|
|
384
410
|
}
|
|
385
411
|
function handleDragNudgePointerEnd(event) {
|
|
386
412
|
if (dragNudgeRef.current?.pointerId !== event.pointerId)
|
|
@@ -390,15 +416,15 @@ export function TokenValueField(props) {
|
|
|
390
416
|
function renderLeading() {
|
|
391
417
|
if (!leading)
|
|
392
418
|
return null;
|
|
393
|
-
const canDrag = !
|
|
394
|
-
&& supportsDragNudge(
|
|
395
|
-
&& canNudgeCssValueByDrag(
|
|
419
|
+
const canDrag = !fieldDisabled
|
|
420
|
+
&& supportsDragNudge(nudgeProperty)
|
|
421
|
+
&& canNudgeCssValueByDrag(nudgeProperty, rawValue);
|
|
396
422
|
if (!canDrag)
|
|
397
423
|
return _jsx("span", { className: "token-field__leading", children: leading });
|
|
398
|
-
return (_jsx("span", { className: "token-field__leading token-field__leading--nudge", "data-test": "nudge-handle", "data-dragging": isDraggingNudge ? "true" : undefined,
|
|
424
|
+
return (_jsx("span", { className: "token-field__leading token-field__leading--nudge", "data-test": "nudge-handle", "data-dragging": isDraggingNudge ? "true" : undefined, onPointerDown: handleDragNudgePointerDown, onPointerMove: handleDragNudgePointerMove, onPointerUp: handleDragNudgePointerEnd, onPointerCancel: handleDragNudgePointerEnd, onBlur: stopDragNudge, children: leading }));
|
|
399
425
|
}
|
|
400
426
|
function commitOpacityValue(value = opacityValue) {
|
|
401
|
-
if (!showOpacity || !onCommitOpacity)
|
|
427
|
+
if (fieldDisabled || !showOpacity || !onCommitOpacity)
|
|
402
428
|
return;
|
|
403
429
|
const normalized = normalizeOpacityPercent(value);
|
|
404
430
|
if (normalized === null) {
|
|
@@ -411,7 +437,7 @@ export function TokenValueField(props) {
|
|
|
411
437
|
}
|
|
412
438
|
setOpacityValue(normalized);
|
|
413
439
|
}
|
|
414
|
-
const opacityControl = showOpacity ? (_jsx("input", { className: "token-opacity-input", "data-test": "color-opacity-input", type: "text", inputMode: "decimal", value: opacityValue, disabled:
|
|
440
|
+
const opacityControl = showOpacity ? (_jsx("input", { className: "token-opacity-input", "data-test": "color-opacity-input", type: "text", inputMode: "decimal", value: opacityValue, disabled: fieldDisabled || !onCommitOpacity, "aria-label": `Opacity for ${property}`, onChange: (event) => setOpacityValue(event.target.value), onBlur: () => commitOpacityValue(), onKeyDown: (event) => {
|
|
415
441
|
const direction = arrowDirection(event.key);
|
|
416
442
|
if (direction && !event.altKey && !event.ctrlKey && !event.metaKey) {
|
|
417
443
|
const next = nudgeOpacityValue(opacityValue, direction, event.shiftKey);
|
|
@@ -434,17 +460,17 @@ export function TokenValueField(props) {
|
|
|
434
460
|
}
|
|
435
461
|
} })) : null;
|
|
436
462
|
const colorPreview = activeToken ? resolvedValue || activeToken.value : resolvedValue || rawValue;
|
|
437
|
-
const colorControlEl = isColor ? (_jsx(NativeColorSwatch, { value: colorPreview, disabled:
|
|
463
|
+
const colorControlEl = isColor ? (_jsx(NativeColorSwatch, { value: colorPreview, disabled: fieldDisabled, onChange: (value) => commitRawValue(value) })) : null;
|
|
438
464
|
const rawSuggestionItems = availableSuggestions.map(rawSuggestion);
|
|
439
465
|
if (activeToken) {
|
|
440
466
|
const chipValue = chipVariant === "small" ? stripCssUnit(activeToken.value) : activeToken.name;
|
|
441
467
|
const embedColorSwatch = isColor && chipVariant !== "small";
|
|
442
|
-
return (_jsxs("span", { className:
|
|
468
|
+
return (_jsxs("span", { className: cx("token-field", isColor && "token-field--color", embedColorSwatch && "token-field--color-chip", blockedBy !== null && "token-field--blocked", className), "data-test": "token-field", "data-property": property, "aria-disabled": fieldDisabled || undefined, "aria-label": label, children: [renderLeading(), embedColorSwatch ? null : colorControlEl, _jsxs(TokenChip, { size: chipVariant, "data-group": groupByTokenName.get(activeToken.name) ?? tokenGroup(activeToken), children: [_jsx(PopoverListbox, { query: "", value: activeToken.name, open: isTokenPickerOpen, trigger: (_jsxs(TokenChip.Picker, { children: [embedColorSwatch ? colorControlEl : null, _jsx(TokenChip.Label, { title: chipVariant === "small" ? activeToken.name : undefined, children: chipValue })] })), triggerClassName: "token-chip__trigger", triggerDataTest: "token-chip", triggerAriaLabel: `Change ${property} token`, searchable: true, searchPlaceholder: "Search tokens\u2026", searchAriaLabel: "Search tokens", items: [...rawSuggestionItems, ...relevantTokens.map((entry) => tokenSuggestion(entry, groupByTokenName))], onQueryChange: () => undefined, onOpenChange: setTokenPickerOpen, disabled: fieldDisabled, onSelect: (value) => {
|
|
443
469
|
handleSuggestionSelect(value);
|
|
444
|
-
} }), _jsx(TokenChip.Action, { children: _jsx(IconButton, { variant: "quiet", size: "compact", style: { borderRadius: "var(--radius-4)" }, label: "Replace with raw value", "data-test": "delink-btn", disabled:
|
|
470
|
+
} }), _jsx(TokenChip.Action, { children: _jsx(Tooltip, { stableTrigger: true, children: _jsx(IconButton, { variant: "quiet", size: "compact", style: { borderRadius: "var(--radius-4)" }, label: "Replace with raw value", "data-test": "delink-btn", disabled: fieldDisabled, onClick: handleDelink, children: _jsx(IconLinkOff, { size: chipVariant === "small" ? 12 : 14, stroke: 1.75, "aria-hidden": "true" }) }) }) })] }), opacityControl, _jsx(AtRuleIndicator, { atRules: fieldAtRules }), trailing ? _jsx("span", { className: "token-field__trailing", children: trailing }) : null, _jsx(InlineStyleWarning, { blockedBy: blockedBy, dataTest: inlineWarningDataTest, tooltipDataTest: inlineWarningTooltipDataTest })] }));
|
|
445
471
|
}
|
|
446
472
|
const showPopover = isFocused && (filteredTokens.length > 0 || availableSuggestions.length > 0);
|
|
447
|
-
return (_jsxs("span", { className:
|
|
473
|
+
return (_jsxs("span", { className: cx("token-field", "token-field--raw", isColor && "token-field--color", blockedBy !== null && "token-field--blocked", className), "data-test": "token-field", "data-property": property, "aria-disabled": fieldDisabled || undefined, "aria-label": label, children: [renderLeading(), colorControlEl, _jsx(PopoverListbox, { query: rawValue, value: null, open: showPopover, placeholder: property, inputRef: inputRef, inputAppearance: "embedded", inputDataTest: inputDataTest, inputOnFocus: () => {
|
|
448
474
|
setIsFocused(true);
|
|
449
475
|
if (mixed && rawValue.trim().toLowerCase() === "mixed")
|
|
450
476
|
setRawValue("");
|
|
@@ -454,9 +480,9 @@ export function TokenValueField(props) {
|
|
|
454
480
|
], onQueryChange: (value) => {
|
|
455
481
|
isNavigatingSuggestions.current = false;
|
|
456
482
|
setRawValue(value);
|
|
457
|
-
}, onOpenChange: setIsFocused, disabled:
|
|
483
|
+
}, onOpenChange: setIsFocused, disabled: fieldDisabled, onSelect: (value) => {
|
|
458
484
|
handleSuggestionSelect(value);
|
|
459
|
-
} }), opacityControl, _jsx(AtRuleIndicator, { atRules: fieldAtRules }), trailing ? _jsx("span", { className: "token-field__trailing", children: trailing }) : null] }));
|
|
485
|
+
} }), opacityControl, _jsx(AtRuleIndicator, { atRules: fieldAtRules }), trailing ? _jsx("span", { className: "token-field__trailing", children: trailing }) : null, _jsx(InlineStyleWarning, { blockedBy: blockedBy, dataTest: inlineWarningDataTest, tooltipDataTest: inlineWarningTooltipDataTest })] }));
|
|
460
486
|
}
|
|
461
487
|
function arrowDirection(key) {
|
|
462
488
|
if (key === "ArrowUp")
|
|
@@ -466,7 +492,7 @@ function arrowDirection(key) {
|
|
|
466
492
|
return null;
|
|
467
493
|
}
|
|
468
494
|
export function TokenField(props) {
|
|
469
|
-
const { property, semanticSlot, tokenRow, selection, initialValue, displayValue, domElement: el, editTarget, entries, suggestions, inputDataTest, onAfterEdit, editMetadata, leading, trailing, className, label, chipVariant, formatRawValue: formatRawValueProp, disabled = false, mixed = false, attributionTokens, } = props;
|
|
495
|
+
const { property, semanticSlot, tokenRow, selection, initialValue, displayValue, domElement: el, editTarget, entries, suggestions, inputDataTest, onAfterEdit, editMetadata, leading, trailing, className, label, chipVariant, formatRawValue: formatRawValueProp, disabled = false, mixed = false, attributionTokens, inlineWarningDataTest, inlineWarningTooltipDataTest, } = props;
|
|
470
496
|
const selectedProperty = selection && selection.elements.length > 1
|
|
471
497
|
? selection.getProperty(property)
|
|
472
498
|
: null;
|
|
@@ -476,6 +502,7 @@ export function TokenField(props) {
|
|
|
476
502
|
? selectedProperty.value.value
|
|
477
503
|
: undefined;
|
|
478
504
|
const effectiveMetadata = editTarget && isMultiTarget(editTarget) ? undefined : editMetadata;
|
|
505
|
+
const blockedBy = inlineBlockedBy(selection?.domElements ?? [el], property);
|
|
479
506
|
const tokenBackedOpacityName = tokenRow?.tokenName
|
|
480
507
|
&& tokenRow.opacity
|
|
481
508
|
&& tokenRow.opacity.tokenName !== tokenRow.tokenName
|
|
@@ -525,7 +552,7 @@ export function TokenField(props) {
|
|
|
525
552
|
?? (selectedProperty?.token.kind === "mixed" ? ["Mixed tokens"] : undefined)
|
|
526
553
|
?? (expression
|
|
527
554
|
? tokenRow?.tokens?.filter((token) => token.name !== tokenRow.opacity?.tokenName).map((token) => token.name)
|
|
528
|
-
: undefined), opacity: tokenRow?.opacity, color: tokenRow?.color, entries: entries, suggestions: suggestions, inputDataTest: inputDataTest, disabled: disabled, mixed: effectiveMixed, isColor: selectTokens({ property, slot: semanticSlot, entries: [] }).preferredGroup === "color", formatRawValue: (value) => {
|
|
555
|
+
: undefined), opacity: tokenRow?.opacity, color: tokenRow?.color, entries: entries, suggestions: suggestions, inputDataTest: inputDataTest, disabled: disabled, blockedBy: blockedBy, mixed: effectiveMixed, isColor: selectTokens({ property, slot: semanticSlot, entries: [] }).preferredGroup === "color", formatRawValue: (value) => {
|
|
529
556
|
if (formatRawValueProp)
|
|
530
557
|
return formatRawValueProp(value);
|
|
531
558
|
return completeCssValue(value.trim(), valuePolicyFor(property));
|
|
@@ -563,7 +590,7 @@ export function TokenField(props) {
|
|
|
563
590
|
}, onUnlink: (value) => {
|
|
564
591
|
setStyle(editTarget ?? el, property, value, effectiveMetadata);
|
|
565
592
|
onAfterEdit?.();
|
|
566
|
-
}, leading: leading, trailing: trailing, className: className, label: label, chipVariant: chipVariant }));
|
|
593
|
+
}, leading: leading, trailing: trailing, className: className, label: label, chipVariant: chipVariant, inlineWarningDataTest: inlineWarningDataTest, inlineWarningTooltipDataTest: inlineWarningTooltipDataTest }));
|
|
567
594
|
}
|
|
568
595
|
function tokenSuggestion(entry, groups) {
|
|
569
596
|
return {
|
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
return "";
|
|
5
|
-
if (typeof children === "string" || typeof children === "number" || typeof children === "bigint") {
|
|
6
|
-
return String(children);
|
|
7
|
-
}
|
|
8
|
-
if (Array.isArray(children))
|
|
9
|
-
return children.map(textContent).join("");
|
|
10
|
-
return "";
|
|
11
|
-
}
|
|
2
|
+
import { cx } from "../ui/classNames.js";
|
|
3
|
+
import { Tooltip } from "../ui/Tooltip.js";
|
|
12
4
|
export function TokenLabel({ as = "span", className, children, title, ...props }) {
|
|
13
|
-
const childText = textContent(children);
|
|
14
5
|
const labelProps = {
|
|
15
6
|
...props,
|
|
16
|
-
className:
|
|
17
|
-
title: title ?? childText,
|
|
7
|
+
className: cx("token-label", className),
|
|
18
8
|
};
|
|
19
9
|
const content = _jsx("span", { className: "token-label__content", children: children });
|
|
20
|
-
|
|
10
|
+
const label = as === "code"
|
|
21
11
|
? _jsx("code", { ...labelProps, children: content })
|
|
22
12
|
: _jsx("span", { ...labelProps, children: content });
|
|
13
|
+
return title === undefined ? label : _jsx(Tooltip, { content: title, children: label });
|
|
23
14
|
}
|
|
@@ -3,6 +3,7 @@ import { useMemo, useState } from "react";
|
|
|
3
3
|
import { isTokenChange, useChanges } from "../changes/changesLog.js";
|
|
4
4
|
import { TextInput } from "../ui/TextInput.js";
|
|
5
5
|
import { ControlSurface } from "../ui/ControlSurface.js";
|
|
6
|
+
import { Disclosure } from "../ui/Disclosure.js";
|
|
6
7
|
import { TokenValueField } from "./TokenField.js";
|
|
7
8
|
import { TOKEN_GROUP_LABELS, TOKEN_GROUP_ORDER, aliasName, compatibleTokenNames, contextLabel, filterTokenRows, } from "./catalog.js";
|
|
8
9
|
import { setGlobalTokenValue } from "./tokenEdits.js";
|
|
@@ -43,5 +44,5 @@ function TokenCatalogItem({ row, rows, entries, }) {
|
|
|
43
44
|
const allowed = compatibleTokenNames(effectiveRow, effectiveRows);
|
|
44
45
|
const variants = row.definition.declarations.filter((declaration) => declaration !== row.activeDeclaration);
|
|
45
46
|
const tokenName = row.definition.name || row.definition.cssName;
|
|
46
|
-
return (_jsxs("article", { className: "token-row", "data-test": "global-token-row", "data-token-name": row.definition.cssName, "data-active": row.activeDeclaration ? "true" : "false", children: [_jsxs("div", { className: "token-row__inline", children: [_jsx(TokenLabel, { as: "code", className: "token-row__name", title: tokenName, children: tokenName }), row.activeDeclaration ? (_jsx(ControlSurface, { children: _jsx(TokenValueField, { property: row.definition.cssName, committedValue: committedValue, resolvedValue: row.resolvedValue || committedValue, activeTokenName: activeAlias, entries: entries, allowedTokenNames: allowed, isColor: row.group === "color", onCommitRaw: (value) => setGlobalTokenValue(row, value), onSelectToken: (token) => { setGlobalTokenValue(row, `var(${token.name})`); }, onUnlink: (value) => setGlobalTokenValue(row, value) }) })) : (_jsx(TextInput, { disabled: true, value: "Inactive in current theme", "aria-label": `${row.definition.cssName} inactive` }))] }), variants.length > 0 ? (
|
|
47
|
+
return (_jsxs("article", { className: "token-row", "data-test": "global-token-row", "data-token-name": row.definition.cssName, "data-active": row.activeDeclaration ? "true" : "false", children: [_jsxs("div", { className: "token-row__inline", children: [_jsx(TokenLabel, { as: "code", className: "token-row__name", title: tokenName, children: tokenName }), row.activeDeclaration ? (_jsx(ControlSurface, { children: _jsx(TokenValueField, { property: row.definition.cssName, committedValue: committedValue, resolvedValue: row.resolvedValue || committedValue, activeTokenName: activeAlias, entries: entries, allowedTokenNames: allowed, isColor: row.group === "color", onCommitRaw: (value) => setGlobalTokenValue(row, value), onSelectToken: (token) => { setGlobalTokenValue(row, `var(${token.name})`); }, onUnlink: (value) => setGlobalTokenValue(row, value) }) })) : (_jsx(TextInput, { disabled: true, value: "Inactive in current theme", "aria-label": `${row.definition.cssName} inactive` }))] }), variants.length > 0 ? (_jsx(Disclosure, { className: "token-variants", "data-test": "token-variants", title: `Variants (${variants.length})`, panelClassName: "token-variants__list", children: variants.map((declaration) => (_jsxs("div", { className: "token-variant", children: [_jsx("span", { className: "token-variant__context", children: contextLabel(declaration.context) }), _jsx("code", { children: declaration.value }), _jsx("span", { children: declaration.source })] }, `${declaration.source}-${contextLabel(declaration.context)}`))) })) : null] }));
|
|
47
48
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Keeps mouse drags relative, including when the handle is inside a shadow root. */
|
|
2
|
+
export declare function startDragPointerLock(handle: HTMLElement, point: {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
}, onMove: (event: MouseEvent) => void, onEnd: () => void): {
|
|
6
|
+
isLocked: () => boolean;
|
|
7
|
+
stop: () => void;
|
|
8
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { showLockedDragCursor } from "../ui/dragCursor.js";
|
|
2
|
+
/** Keeps mouse drags relative, including when the handle is inside a shadow root. */
|
|
3
|
+
export function startDragPointerLock(handle, point, onMove, onEnd) {
|
|
4
|
+
const doc = handle.ownerDocument;
|
|
5
|
+
const root = handle.getRootNode();
|
|
6
|
+
const isLocked = () => root.pointerLockElement === handle;
|
|
7
|
+
let stopped = false;
|
|
8
|
+
let pending = true;
|
|
9
|
+
let acquired = false;
|
|
10
|
+
let removeCursor;
|
|
11
|
+
function removeLockListeners() {
|
|
12
|
+
doc.removeEventListener("pointerlockchange", onLockChange);
|
|
13
|
+
doc.removeEventListener("pointerlockerror", onLockError);
|
|
14
|
+
}
|
|
15
|
+
function onLockChange() {
|
|
16
|
+
if (isLocked()) {
|
|
17
|
+
pending = false;
|
|
18
|
+
acquired = true;
|
|
19
|
+
if (stopped) {
|
|
20
|
+
doc.exitPointerLock();
|
|
21
|
+
removeLockListeners();
|
|
22
|
+
}
|
|
23
|
+
else if (!removeCursor) {
|
|
24
|
+
removeCursor = showLockedDragCursor(doc, point);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else if (acquired) {
|
|
28
|
+
onEnd();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function onLockError() {
|
|
32
|
+
pending = false;
|
|
33
|
+
removeLockListeners();
|
|
34
|
+
}
|
|
35
|
+
function onMouseMove(event) {
|
|
36
|
+
if (!stopped && isLocked())
|
|
37
|
+
onMove(event);
|
|
38
|
+
}
|
|
39
|
+
function onMouseUp(event) {
|
|
40
|
+
if (event.button === 0)
|
|
41
|
+
onEnd();
|
|
42
|
+
}
|
|
43
|
+
doc.addEventListener("mousemove", onMouseMove);
|
|
44
|
+
doc.addEventListener("mouseup", onMouseUp);
|
|
45
|
+
doc.addEventListener("pointerlockchange", onLockChange);
|
|
46
|
+
doc.addEventListener("pointerlockerror", onLockError);
|
|
47
|
+
try {
|
|
48
|
+
// Older implementations return void. Rejections retain pointer-capture dragging.
|
|
49
|
+
const request = handle.requestPointerLock();
|
|
50
|
+
if (request)
|
|
51
|
+
void request.catch(onLockError);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
onLockError();
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
isLocked,
|
|
58
|
+
stop() {
|
|
59
|
+
stopped = true;
|
|
60
|
+
removeCursor?.();
|
|
61
|
+
doc.removeEventListener("mousemove", onMouseMove);
|
|
62
|
+
doc.removeEventListener("mouseup", onMouseUp);
|
|
63
|
+
if (isLocked())
|
|
64
|
+
doc.exitPointerLock();
|
|
65
|
+
// A request can finish after mouse-up or unmount. Release that late lock too.
|
|
66
|
+
if (!pending)
|
|
67
|
+
removeLockListeners();
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -2,7 +2,7 @@ import type { TokenEntry } from "../../css/model/index.js";
|
|
|
2
2
|
import type { ElementChangeRecord } from "../changes/changesLog.js";
|
|
3
3
|
import { type EditTarget } from "../selection/editTarget.js";
|
|
4
4
|
export type { ChangeRecord } from "../changes/changesLog.js";
|
|
5
|
-
export { getPendingRules, getChangesList as getChangeRecords,
|
|
5
|
+
export { getPendingRules, getChangesList as getChangeRecords, clearActiveDraft as resetPendingRules } from "../changes/changesLog.js";
|
|
6
6
|
export interface StyleEditMetadata {
|
|
7
7
|
sourceProperty?: string;
|
|
8
8
|
sourceAuthoredValue?: string;
|
|
@@ -44,7 +44,7 @@ function sourceFields(el) {
|
|
|
44
44
|
column: parsed.column,
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
|
-
export { getPendingRules, getChangesList as getChangeRecords,
|
|
47
|
+
export { getPendingRules, getChangesList as getChangeRecords, clearActiveDraft as resetPendingRules } from "../changes/changesLog.js";
|
|
48
48
|
/** Returns whether a style write can address every element in the target safely. */
|
|
49
49
|
export function canEditStyles(target) {
|
|
50
50
|
return canPlanBatchEditScopes(targetElements(target));
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, useContext, useMemo } from "react";
|
|
3
|
-
import { Tooltip } from "
|
|
3
|
+
import { Tooltip } from "./Tooltip.js";
|
|
4
|
+
import { cx } from "./classNames.js";
|
|
4
5
|
const EMPTY_AT_RULES = [];
|
|
5
6
|
const FieldAtRuleContext = createContext(new Map());
|
|
6
7
|
/**
|
|
@@ -40,9 +41,6 @@ function countLabel(label, count) {
|
|
|
40
41
|
const noun = label.toLowerCase().replace(/query$/, count === 1 ? "query" : "queries");
|
|
41
42
|
return `${count} ${noun}`;
|
|
42
43
|
}
|
|
43
|
-
function portalContainer() {
|
|
44
|
-
return document.getElementById("nudge-ui-root")?.shadowRoot ?? document.body;
|
|
45
|
-
}
|
|
46
44
|
/** Compact, field-level attribution for the conditional rule that currently wins. */
|
|
47
45
|
export function AtRuleIndicator({ atRules = EMPTY_AT_RULES, className }) {
|
|
48
46
|
if (atRules.length === 0)
|
|
@@ -50,5 +48,5 @@ export function AtRuleIndicator({ atRules = EMPTY_AT_RULES, className }) {
|
|
|
50
48
|
const label = labelFor(atRules);
|
|
51
49
|
const activeCount = atRules.filter((atRule) => !("active" in atRule) || atRule.active).length;
|
|
52
50
|
const count = countLabel(label, atRules.length);
|
|
53
|
-
return (_jsx(Tooltip
|
|
51
|
+
return (_jsx(Tooltip, { content: (_jsx("div", { className: "at-rule-tooltip__rules", children: atRules.map((atRule, index) => (_jsx("div", { className: cx("at-rule-tooltip__rule", (!("active" in atRule) || atRule.active) && "at-rule-tooltip__rule--active"), "data-active": !("active" in atRule) || atRule.active ? "true" : "false", children: _jsx("code", { children: atRule.params }) }, `${atRule.kind}-${atRule.params}-${index}`))) })), delay: 0, positionerClassName: "at-rule-tooltip-positioner", popupClassName: "at-rule-tooltip", "data-test": "at-rule-tooltip", children: _jsx("button", { type: "button", className: cx("at-rule-indicator", className), "data-test": "at-rule-indicator", "aria-label": activeCount > 0 ? `Active ${count}` : count, children: _jsx("span", { className: "at-rule-indicator__symbol", "aria-hidden": "true", children: atRules.length }) }) }));
|
|
54
52
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ButtonHTMLAttributes
|
|
1
|
+
import type { ButtonHTMLAttributes } from "react";
|
|
2
2
|
export type ButtonVariant = "primary" | "secondary" | "quiet" | "danger" | "disabled";
|
|
3
3
|
export type ButtonSize = "default" | "compact" | "large";
|
|
4
4
|
export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
@@ -6,4 +6,8 @@ export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
|
6
6
|
size?: ButtonSize;
|
|
7
7
|
"data-test"?: string;
|
|
8
8
|
};
|
|
9
|
-
export declare
|
|
9
|
+
export declare const Button: import("react").ForwardRefExoticComponent<ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
10
|
+
variant?: ButtonVariant;
|
|
11
|
+
size?: ButtonSize;
|
|
12
|
+
"data-test"?: string;
|
|
13
|
+
} & import("react").RefAttributes<HTMLButtonElement>>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
export const Button = forwardRef(function Button({ variant = "secondary", size = "default", className, ...props }, ref) {
|
|
4
|
+
return (_jsx("button", { ref: ref, ...props, className: `button button--${variant} button--${size}${className ? ` ${className}` : ""}` }));
|
|
5
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HTMLAttributes,
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
2
2
|
/**
|
|
3
3
|
* Visual boundary for an inspector control. It owns the shared control chrome
|
|
4
4
|
* while the child owns its particular input or selection behaviour.
|
|
@@ -11,4 +11,4 @@ export interface ControlSurfaceProps extends HTMLAttributes<HTMLSpanElement> {
|
|
|
11
11
|
"data-test"?: string;
|
|
12
12
|
children?: ReactNode;
|
|
13
13
|
}
|
|
14
|
-
export declare
|
|
14
|
+
export declare const ControlSurface: import("react").ForwardRefExoticComponent<ControlSurfaceProps & import("react").RefAttributes<HTMLSpanElement>>;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
export const ControlSurface = forwardRef(function ControlSurface({ appearance = "default", density = "default", className, children, ...props }, ref) {
|
|
3
4
|
const classes = [
|
|
4
5
|
"control-surface",
|
|
5
6
|
appearance === "embedded" ? "control-surface--embedded" : "",
|
|
6
7
|
density === "compact" ? "control-surface--compact" : "",
|
|
7
8
|
className ?? "",
|
|
8
9
|
].filter(Boolean).join(" ");
|
|
9
|
-
return _jsx("span", { ...props, className: classes, children: children });
|
|
10
|
-
}
|
|
10
|
+
return _jsx("span", { ref: ref, ...props, className: classes, children: children });
|
|
11
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from "react";
|
|
2
|
+
export interface DisclosureProps {
|
|
3
|
+
readonly title: ReactNode;
|
|
4
|
+
/** Optional accessory rendered between the label and the chevron (e.g. a count badge). */
|
|
5
|
+
readonly badge?: ReactNode;
|
|
6
|
+
readonly children: ReactNode;
|
|
7
|
+
readonly className?: string;
|
|
8
|
+
readonly triggerClassName?: string;
|
|
9
|
+
readonly panelClassName?: string;
|
|
10
|
+
readonly defaultOpen?: boolean;
|
|
11
|
+
readonly open?: boolean;
|
|
12
|
+
readonly onOpenChange?: (open: boolean) => void;
|
|
13
|
+
/** Keeps panel content in the DOM while collapsed, matching native details behavior. */
|
|
14
|
+
readonly keepMounted?: boolean;
|
|
15
|
+
readonly "data-test"?: string;
|
|
16
|
+
readonly triggerDataTest?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A single collapsible disclosure built on Base UI Collapsible.
|
|
20
|
+
* Replaces native details/summary for consistent 12px label styling and chevron.
|
|
21
|
+
*/
|
|
22
|
+
export declare function Disclosure({ title, badge, children, className, triggerClassName, panelClassName, defaultOpen, open, onOpenChange, keepMounted, "data-test": dataTest, triggerDataTest, }: DisclosureProps): ReactElement;
|