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.
Files changed (226) hide show
  1. package/README.md +164 -46
  2. package/dist/client.mjs +252 -61
  3. package/dist/css/value-semantics/colorSemantics.d.ts +4 -0
  4. package/dist/css/value-semantics/colorSemantics.js +17 -0
  5. package/dist/hosts/astro/astroRuntimeConfig.js +1 -0
  6. package/dist/hosts/astro/clientTransport.js +38 -32
  7. package/dist/hosts/astro/integration.js +5 -1
  8. package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
  9. package/dist/hosts/astro/markdownIdentity.js +81 -0
  10. package/dist/hosts/next/manifest.js +1 -1
  11. package/dist/hosts/next/sidecar.js +5 -1
  12. package/dist/hosts/static/manifest.js +1 -1
  13. package/dist/hosts/static/server.js +3 -0
  14. package/dist/hosts/vite/vite.d.ts +3 -0
  15. package/dist/hosts/vite/vite.js +24 -4
  16. package/dist/inspector/agent/McpConnectionDialog.js +13 -19
  17. package/dist/inspector/agent/activity.d.ts +18 -0
  18. package/dist/inspector/agent/activity.js +70 -0
  19. package/dist/inspector/agent/client.d.ts +2 -0
  20. package/dist/inspector/agent/client.js +29 -1
  21. package/dist/inspector/agent/connectionStatus.js +1 -1
  22. package/dist/inspector/agent/httpTransport.js +9 -2
  23. package/dist/inspector/agent/protocol.d.ts +6 -3
  24. package/dist/inspector/agent/protocol.js +1 -1
  25. package/dist/inspector/agent/verification.d.ts +11 -1
  26. package/dist/inspector/agent/verification.js +53 -25
  27. package/dist/inspector/canvas/AgentActivityOverlay.d.ts +13 -0
  28. package/dist/inspector/canvas/AgentActivityOverlay.js +111 -0
  29. package/dist/inspector/canvas/CanvasCard.d.ts +9 -2
  30. package/dist/inspector/canvas/CanvasCard.js +133 -38
  31. package/dist/inspector/canvas/CanvasElementOverlay.js +152 -16
  32. package/dist/inspector/canvas/CanvasToolIcons.d.ts +10 -0
  33. package/dist/inspector/canvas/CanvasToolIcons.js +20 -0
  34. package/dist/inspector/canvas/CanvasToolbar.js +8 -4
  35. package/dist/inspector/canvas/CanvasWorkspace.js +225 -57
  36. package/dist/inspector/canvas/StaleChangeIndicator.js +3 -13
  37. package/dist/inspector/canvas/agentPresentation.d.ts +8 -8
  38. package/dist/inspector/canvas/agentPresentation.js +64 -52
  39. package/dist/inspector/canvas/canvasGestures.d.ts +1 -1
  40. package/dist/inspector/canvas/canvasGestures.js +1 -1
  41. package/dist/inspector/canvas/canvasStore.d.ts +46 -82
  42. package/dist/inspector/canvas/canvasStore.js +251 -284
  43. package/dist/inspector/canvas/frameContent.d.ts +21 -0
  44. package/dist/inspector/canvas/frameContent.js +44 -0
  45. package/dist/inspector/canvas/frameProtocol.d.ts +21 -4
  46. package/dist/inspector/canvas/frameProtocol.js +3 -3
  47. package/dist/inspector/canvas/keyboardShortcuts.d.ts +3 -1
  48. package/dist/inspector/canvas/keyboardShortcuts.js +4 -4
  49. package/dist/inspector/canvas/layout.d.ts +52 -0
  50. package/dist/inspector/canvas/layout.js +106 -0
  51. package/dist/inspector/canvas/projection.d.ts +15 -5
  52. package/dist/inspector/canvas/projection.js +69 -13
  53. package/dist/inspector/canvas/rendererBootstrap.js +32 -4
  54. package/dist/inspector/canvas/rendererElementSelector.js +47 -6
  55. package/dist/inspector/canvas/rendererStylesheet.js +2 -2
  56. package/dist/inspector/canvas/resizeHandleScale.js +1 -1
  57. package/dist/inspector/canvas/sessionStore.d.ts +11 -26
  58. package/dist/inspector/canvas/sessionStore.js +43 -183
  59. package/dist/inspector/canvas/staleChangeDetector.js +9 -3
  60. package/dist/inspector/canvas/useCanvasLayoutAnimation.d.ts +5 -0
  61. package/dist/inspector/canvas/useCanvasLayoutAnimation.js +107 -0
  62. package/dist/inspector/canvas/viewStore.d.ts +38 -0
  63. package/dist/inspector/canvas/viewStore.js +104 -0
  64. package/dist/inspector/canvas/wheelPan.d.ts +8 -0
  65. package/dist/inspector/canvas/wheelPan.js +8 -0
  66. package/dist/inspector/changes/changesLog.d.ts +6 -5
  67. package/dist/inspector/changes/changesLog.js +40 -32
  68. package/dist/inspector/changes/draftChanges.d.ts +56 -0
  69. package/dist/inspector/changes/draftChanges.js +300 -0
  70. package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
  71. package/dist/inspector/changes/previewDiagnostics.js +11 -25
  72. package/dist/inspector/clientManifest.d.ts +1 -1
  73. package/dist/inspector/comments/CommentsOverlay.d.ts +2 -0
  74. package/dist/inspector/comments/CommentsOverlay.js +250 -0
  75. package/dist/inspector/comments/element.d.ts +6 -0
  76. package/dist/inspector/comments/element.js +47 -0
  77. package/dist/inspector/comments/store.d.ts +29 -0
  78. package/dist/inspector/comments/store.js +121 -0
  79. package/dist/inspector/comments/verification.d.ts +5 -0
  80. package/dist/inspector/comments/verification.js +52 -0
  81. package/dist/inspector/drafts/model.d.ts +35 -0
  82. package/dist/inspector/drafts/model.js +45 -0
  83. package/dist/inspector/drafts/store.d.ts +28 -0
  84. package/dist/inspector/drafts/store.js +231 -0
  85. package/dist/inspector/index.js +20 -27
  86. package/dist/inspector/inline-text/inlineTextEditor.js +7 -0
  87. package/dist/inspector/inspection/useBrowserCssInspection.js +15 -1
  88. package/dist/inspector/iterations/capture.d.ts +2 -0
  89. package/dist/inspector/iterations/capture.js +173 -0
  90. package/dist/inspector/iterations/client.d.ts +7 -0
  91. package/dist/inspector/iterations/client.js +52 -0
  92. package/dist/inspector/iterations/coordinator.d.ts +15 -0
  93. package/dist/inspector/iterations/coordinator.js +130 -0
  94. package/dist/inspector/iterations/prompt.d.ts +3 -0
  95. package/dist/inspector/iterations/prompt.js +26 -0
  96. package/dist/inspector/overlay/DomNavigator.js +21 -15
  97. package/dist/inspector/overlay/interactionStyles.js +3 -1
  98. package/dist/inspector/overlay/spacingGestures.d.ts +13 -1
  99. package/dist/inspector/overlay/spacingGestures.js +82 -5
  100. package/dist/inspector/projection/{workspaceProjection.d.ts → draftProjection.d.ts} +6 -6
  101. package/dist/inspector/projection/{workspaceProjection.js → draftProjection.js} +4 -4
  102. package/dist/inspector/projection/renderedInstance.d.ts +2 -1
  103. package/dist/inspector/projection/renderedInstance.js +9 -5
  104. package/dist/inspector/projection/structuralProjection.d.ts +2 -1
  105. package/dist/inspector/projection/structuralProjection.js +19 -15
  106. package/dist/inspector/projection/textProjection.d.ts +2 -1
  107. package/dist/inspector/projection/textProjection.js +8 -4
  108. package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
  109. package/dist/inspector/prompt/clipboardHandoff.d.ts +10 -18
  110. package/dist/inspector/prompt/clipboardHandoff.js +92 -143
  111. package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
  112. package/dist/inspector/prompt/generatePrompt.js +17 -16
  113. package/dist/inspector/runtime/runtimeConfig.d.ts +9 -0
  114. package/dist/inspector/runtime/runtimeConfig.js +24 -0
  115. package/dist/inspector/settings/SettingsDialog.js +21 -8
  116. package/dist/inspector/shell/AgentStatusButton.d.ts +11 -0
  117. package/dist/inspector/shell/AgentStatusButton.js +36 -0
  118. package/dist/inspector/shell/AppShell.js +4 -2
  119. package/dist/inspector/shell/ChangesLog.js +46 -26
  120. package/dist/inspector/shell/CopyPromptButton.js +138 -89
  121. package/dist/inspector/shell/EmptyState.js +9 -8
  122. package/dist/inspector/shell/InspectorShell.js +13 -21
  123. package/dist/inspector/shell/PeekOriginalButton.js +24 -23
  124. package/dist/inspector/shell/originalPreview.js +5 -5
  125. package/dist/inspector/shell/shortcuts.d.ts +3 -0
  126. package/dist/inspector/shell/shortcuts.js +11 -0
  127. package/dist/inspector/sketch/SketchEditor.js +14 -14
  128. package/dist/inspector/sketch/SketchEntryButton.js +1 -1
  129. package/dist/inspector/sketch/SketchFrameOverlay.d.ts +3 -1
  130. package/dist/inspector/sketch/SketchFrameOverlay.js +11 -8
  131. package/dist/inspector/sketch/SketchLayersPanel.js +13 -5
  132. package/dist/inspector/sketch/SketchOverlay.js +7 -7
  133. package/dist/inspector/sketch/SketchWorkspace.js +18 -12
  134. package/dist/inspector/sketch/interaction.d.ts +1 -0
  135. package/dist/inspector/sketch/interaction.js +8 -4
  136. package/dist/inspector/sketch/model.d.ts +5 -0
  137. package/dist/inspector/sketch/model.js +6 -2
  138. package/dist/inspector/sketch/raster.d.ts +1 -2
  139. package/dist/inspector/sketch/raster.js +68 -4
  140. package/dist/inspector/styleEditors/BackgroundEditor.d.ts +4 -0
  141. package/dist/inspector/styleEditors/BackgroundEditor.js +195 -0
  142. package/dist/inspector/styleEditors/BorderEditor.js +49 -78
  143. package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -1
  144. package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +1 -2
  145. package/dist/inspector/styleEditors/BoxShadowEditor.js +132 -4
  146. package/dist/inspector/styleEditors/ColorPicker.d.ts +5 -1
  147. package/dist/inspector/styleEditors/ColorPicker.js +10 -4
  148. package/dist/inspector/styleEditors/GapField.js +3 -5
  149. package/dist/inspector/styleEditors/GridChildSection.d.ts +1 -1
  150. package/dist/inspector/styleEditors/GridChildSection.js +18 -9
  151. package/dist/inspector/styleEditors/GridPicker.d.ts +1 -1
  152. package/dist/inspector/styleEditors/GridPicker.js +8 -2
  153. package/dist/inspector/styleEditors/GridSection.js +1 -1
  154. package/dist/inspector/styleEditors/GridValueField.js +19 -14
  155. package/dist/inspector/styleEditors/ImageBackgroundEditor.d.ts +18 -0
  156. package/dist/inspector/styleEditors/ImageBackgroundEditor.js +118 -0
  157. package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +2 -2
  158. package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +3 -3
  159. package/dist/inspector/styleEditors/LayoutComboField.js +6 -4
  160. package/dist/inspector/styleEditors/LayoutDropdown.js +6 -3
  161. package/dist/inspector/styleEditors/LayoutSection.js +32 -11
  162. package/dist/inspector/styleEditors/SpacingBox.js +7 -5
  163. package/dist/inspector/styleEditors/Typography.js +11 -3
  164. package/dist/inspector/styleEditors/backgroundLayers.d.ts +24 -0
  165. package/dist/inspector/styleEditors/backgroundLayers.js +51 -0
  166. package/dist/inspector/styleEditors/gradientValue.d.ts +17 -0
  167. package/dist/inspector/styleEditors/gradientValue.js +114 -0
  168. package/dist/inspector/styleEditors/inlineAuthored.d.ts +10 -0
  169. package/dist/inspector/styleEditors/inlineAuthored.js +114 -0
  170. package/dist/inspector/styleEditors/layoutValue.d.ts +0 -8
  171. package/dist/inspector/styleEditors/layoutValue.js +0 -42
  172. package/dist/inspector/styleEditors/nudgeValue.d.ts +2 -2
  173. package/dist/inspector/styleEditors/nudgeValue.js +36 -8
  174. package/dist/inspector/tokens/TokenField.d.ts +7 -0
  175. package/dist/inspector/tokens/TokenField.js +29 -21
  176. package/dist/inspector/tokens/TokenLabel.js +5 -14
  177. package/dist/inspector/tokens/editActions.d.ts +1 -1
  178. package/dist/inspector/tokens/editActions.js +1 -1
  179. package/dist/inspector/ui/AtRuleContext.js +4 -6
  180. package/dist/inspector/ui/Button.d.ts +6 -2
  181. package/dist/inspector/ui/Button.js +4 -3
  182. package/dist/inspector/ui/ControlSurface.d.ts +2 -2
  183. package/dist/inspector/ui/ControlSurface.js +4 -3
  184. package/dist/inspector/ui/InlineStyleWarning.d.ts +11 -0
  185. package/dist/inspector/ui/InlineStyleWarning.js +13 -0
  186. package/dist/inspector/ui/InspectorPopover.d.ts +2 -1
  187. package/dist/inspector/ui/InspectorPopover.js +4 -5
  188. package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
  189. package/dist/inspector/ui/PopoverListbox.js +8 -7
  190. package/dist/inspector/ui/SegmentedControl.d.ts +2 -1
  191. package/dist/inspector/ui/SegmentedControl.js +2 -2
  192. package/dist/inspector/ui/Select.d.ts +6 -1
  193. package/dist/inspector/ui/Select.js +7 -11
  194. package/dist/inspector/ui/SideValuesField.js +1 -1
  195. package/dist/inspector/ui/Tooltip.d.ts +26 -0
  196. package/dist/inspector/ui/Tooltip.js +32 -0
  197. package/dist/inspector/ui/classNames.d.ts +2 -0
  198. package/dist/inspector/ui/classNames.js +4 -0
  199. package/dist/inspector/ui/customCursors.d.ts +23 -0
  200. package/dist/inspector/ui/customCursors.js +122 -0
  201. package/dist/inspector/ui/dragCursor.d.ts +0 -2
  202. package/dist/inspector/ui/dragCursor.js +2 -10
  203. package/dist/inspector/ui/portalContainer.d.ts +2 -0
  204. package/dist/inspector/ui/portalContainer.js +6 -0
  205. package/dist/inspector/ui/styles.js +29 -21
  206. package/dist/inspector/workspace/commands.d.ts +9 -0
  207. package/dist/inspector/workspace/commands.js +82 -0
  208. package/dist/inspector/workspace/controller.d.ts +4 -0
  209. package/dist/inspector/workspace/controller.js +66 -0
  210. package/dist/inspector/workspace/handoff.d.ts +42 -0
  211. package/dist/inspector/workspace/handoff.js +115 -0
  212. package/dist/inspector/workspace/timeline.d.ts +30 -0
  213. package/dist/inspector/workspace/timeline.js +108 -0
  214. package/dist/internal/agent-protocol.d.ts +19 -2
  215. package/dist/internal/agent-protocol.js +13 -0
  216. package/dist/nudge-ui.mjs +558 -311
  217. package/dist/project/artifacts.d.ts +13 -0
  218. package/dist/project/artifacts.js +253 -0
  219. package/dist/transport/artifacts.d.ts +8 -0
  220. package/dist/transport/artifacts.js +9 -0
  221. package/dist/transport/editor.js +3 -1
  222. package/dist/transport/routes.d.ts +2 -0
  223. package/dist/transport/routes.js +2 -0
  224. package/package.json +6 -2
  225. package/dist/inspector/changes/workspaceChanges.d.ts +0 -47
  226. package/dist/inspector/changes/workspaceChanges.js +0 -265
@@ -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,10 +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";
16
18
  import { startDragPointerLock } from "./dragPointerLock.js";
17
- import { createChangeHistoryGroup } from "../changes/workspaceChanges.js";
19
+ import { createChangeHistoryGroup } from "../changes/draftChanges.js";
18
20
  import { isMultiTarget } from "../selection/editTarget.js";
21
+ import { inlineBlockedBy } from "../styleEditors/inlineAuthored.js";
22
+ import { InlineStyleWarning } from "../ui/InlineStyleWarning.js";
19
23
  const NON_COLOR_FACTS = { hasEmbeddedAlpha: false, isExpression: false, opacityEditable: false };
20
24
  function colorFacts(value) {
21
25
  return selectTokens({
@@ -155,7 +159,8 @@ function NativeColorSwatch({ value, onChange, disabled, }) {
155
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) })] }));
156
160
  }
157
161
  export function TokenValueField(props) {
158
- 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;
159
164
  const inheritedAtRules = useFieldAtRules(property);
160
165
  const fieldAtRules = atRules ?? inheritedAtRules;
161
166
  const controlledToken = controlledTokenName ? entries.find((entry) => entry.name === controlledTokenName) : null;
@@ -243,6 +248,8 @@ export function TokenValueField(props) {
243
248
  handleTokenSelect(chosen);
244
249
  }
245
250
  function commitRawValue(value = rawValue) {
251
+ if (fieldDisabled)
252
+ return;
246
253
  if (mixed && value.trim().toLowerCase() === "mixed")
247
254
  return;
248
255
  const formatted = formatRawValue(value);
@@ -286,7 +293,7 @@ export function TokenValueField(props) {
286
293
  if (direction && !event.altKey && !event.ctrlKey && !event.metaKey) {
287
294
  const next = property === "opacity"
288
295
  ? nudgeOpacityValue(rawValue, direction, event.shiftKey)
289
- : nudgeCssValue(property, rawValue, direction, event.shiftKey);
296
+ : nudgeCssValue(nudgeProperty, rawValue, direction, event.shiftKey);
290
297
  if (next) {
291
298
  event.preventDefault();
292
299
  event.stopPropagation();
@@ -336,9 +343,9 @@ export function TokenValueField(props) {
336
343
  function handleDragNudgePointerDown(event) {
337
344
  if (event.button !== 0)
338
345
  return;
339
- if (disabled || !supportsDragNudge(property))
346
+ if (fieldDisabled || !supportsDragNudge(nudgeProperty))
340
347
  return;
341
- if (!canNudgeCssValueByDrag(property, rawValue))
348
+ if (!canNudgeCssValueByDrag(nudgeProperty, rawValue))
342
349
  return;
343
350
  stopDragNudge();
344
351
  const handle = event.currentTarget;
@@ -386,7 +393,7 @@ export function TokenValueField(props) {
386
393
  drag.shiftSnapPending = event.shiftKey;
387
394
  }
388
395
  drag.deltaX += movementX;
389
- const next = nudgeCssValueByDrag(property, drag.startValue, drag.deltaX, drag.shiftActive, drag.shiftActive && drag.shiftSnapPending);
396
+ const next = nudgeCssValueByDrag(nudgeProperty, drag.startValue, drag.deltaX, drag.shiftActive, drag.shiftActive && drag.shiftSnapPending);
390
397
  if (next === null || next === drag.lastValue)
391
398
  return;
392
399
  drag.lastValue = next;
@@ -409,15 +416,15 @@ export function TokenValueField(props) {
409
416
  function renderLeading() {
410
417
  if (!leading)
411
418
  return null;
412
- const canDrag = !disabled
413
- && supportsDragNudge(property)
414
- && canNudgeCssValueByDrag(property, rawValue);
419
+ const canDrag = !fieldDisabled
420
+ && supportsDragNudge(nudgeProperty)
421
+ && canNudgeCssValueByDrag(nudgeProperty, rawValue);
415
422
  if (!canDrag)
416
423
  return _jsx("span", { className: "token-field__leading", children: leading });
417
- return (_jsx("span", { className: "token-field__leading token-field__leading--nudge", "data-test": "nudge-handle", "data-dragging": isDraggingNudge ? "true" : undefined, title: `Drag to adjust ${label ?? property}`, onPointerDown: handleDragNudgePointerDown, onPointerMove: handleDragNudgePointerMove, onPointerUp: handleDragNudgePointerEnd, onPointerCancel: handleDragNudgePointerEnd, onBlur: stopDragNudge, children: leading }));
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 }));
418
425
  }
419
426
  function commitOpacityValue(value = opacityValue) {
420
- if (!showOpacity || !onCommitOpacity)
427
+ if (fieldDisabled || !showOpacity || !onCommitOpacity)
421
428
  return;
422
429
  const normalized = normalizeOpacityPercent(value);
423
430
  if (normalized === null) {
@@ -430,7 +437,7 @@ export function TokenValueField(props) {
430
437
  }
431
438
  setOpacityValue(normalized);
432
439
  }
433
- const opacityControl = showOpacity ? (_jsx("input", { className: "token-opacity-input", "data-test": "color-opacity-input", type: "text", inputMode: "decimal", value: opacityValue, disabled: disabled || !onCommitOpacity, "aria-label": `Opacity for ${property}`, onChange: (event) => setOpacityValue(event.target.value), onBlur: () => commitOpacityValue(), onKeyDown: (event) => {
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) => {
434
441
  const direction = arrowDirection(event.key);
435
442
  if (direction && !event.altKey && !event.ctrlKey && !event.metaKey) {
436
443
  const next = nudgeOpacityValue(opacityValue, direction, event.shiftKey);
@@ -453,17 +460,17 @@ export function TokenValueField(props) {
453
460
  }
454
461
  } })) : null;
455
462
  const colorPreview = activeToken ? resolvedValue || activeToken.value : resolvedValue || rawValue;
456
- const colorControlEl = isColor ? (_jsx(NativeColorSwatch, { value: colorPreview, disabled: disabled, onChange: (value) => commitRawValue(value) })) : null;
463
+ const colorControlEl = isColor ? (_jsx(NativeColorSwatch, { value: colorPreview, disabled: fieldDisabled, onChange: (value) => commitRawValue(value) })) : null;
457
464
  const rawSuggestionItems = availableSuggestions.map(rawSuggestion);
458
465
  if (activeToken) {
459
466
  const chipValue = chipVariant === "small" ? stripCssUnit(activeToken.value) : activeToken.name;
460
467
  const embedColorSwatch = isColor && chipVariant !== "small";
461
- return (_jsxs("span", { className: `token-field${isColor ? " token-field--color" : ""}${embedColorSwatch ? " token-field--color-chip" : ""}${className ? ` ${className}` : ""}`, "data-test": "token-field", "data-property": property, "aria-label": label, title: label, children: [renderLeading(), embedColorSwatch ? null : colorControlEl, _jsxs(TokenChip, { size: chipVariant, "data-group": groupByTokenName.get(activeToken.name) ?? tokenGroup(activeToken), children: [_jsx(PopoverListbox, { query: "", value: activeToken.name, open: isTokenPickerOpen, trigger: (_jsxs(TokenChip.Picker, { children: [embedColorSwatch ? colorControlEl : null, _jsx(TokenChip.Label, { title: activeToken.name, children: chipValue })] })), triggerClassName: "token-chip__trigger", triggerDataTest: "token-chip", triggerAriaLabel: `Change ${property} token`, searchable: true, searchPlaceholder: "Search tokens\u2026", searchAriaLabel: "Search tokens", items: [...rawSuggestionItems, ...relevantTokens.map((entry) => tokenSuggestion(entry, groupByTokenName))], onQueryChange: () => undefined, onOpenChange: setTokenPickerOpen, disabled: disabled, onSelect: (value) => {
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) => {
462
469
  handleSuggestionSelect(value);
463
- } }), _jsx(TokenChip.Action, { children: _jsx(IconButton, { variant: "quiet", size: "compact", style: { borderRadius: "var(--radius-4)" }, label: "Replace with raw value", "data-test": "delink-btn", disabled: disabled, onClick: handleDelink, children: _jsx(IconLinkOff, { size: chipVariant === "small" ? 12 : 14, stroke: 1.75, "aria-hidden": "true" }) }) })] }), opacityControl, _jsx(AtRuleIndicator, { atRules: fieldAtRules }), trailing ? _jsx("span", { className: "token-field__trailing", children: trailing }) : null] }));
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 })] }));
464
471
  }
465
472
  const showPopover = isFocused && (filteredTokens.length > 0 || availableSuggestions.length > 0);
466
- return (_jsxs("span", { className: `token-field token-field--raw${isColor ? " token-field--color" : ""}${className ? ` ${className}` : ""}`, "data-test": "token-field", "data-property": property, "aria-label": label, title: label, children: [renderLeading(), colorControlEl, _jsx(PopoverListbox, { query: rawValue, value: null, open: showPopover, placeholder: property, inputRef: inputRef, inputAppearance: "embedded", inputDataTest: inputDataTest, inputOnFocus: () => {
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: () => {
467
474
  setIsFocused(true);
468
475
  if (mixed && rawValue.trim().toLowerCase() === "mixed")
469
476
  setRawValue("");
@@ -473,9 +480,9 @@ export function TokenValueField(props) {
473
480
  ], onQueryChange: (value) => {
474
481
  isNavigatingSuggestions.current = false;
475
482
  setRawValue(value);
476
- }, onOpenChange: setIsFocused, disabled: disabled, onSelect: (value) => {
483
+ }, onOpenChange: setIsFocused, disabled: fieldDisabled, onSelect: (value) => {
477
484
  handleSuggestionSelect(value);
478
- } }), 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 })] }));
479
486
  }
480
487
  function arrowDirection(key) {
481
488
  if (key === "ArrowUp")
@@ -485,7 +492,7 @@ function arrowDirection(key) {
485
492
  return null;
486
493
  }
487
494
  export function TokenField(props) {
488
- 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;
489
496
  const selectedProperty = selection && selection.elements.length > 1
490
497
  ? selection.getProperty(property)
491
498
  : null;
@@ -495,6 +502,7 @@ export function TokenField(props) {
495
502
  ? selectedProperty.value.value
496
503
  : undefined;
497
504
  const effectiveMetadata = editTarget && isMultiTarget(editTarget) ? undefined : editMetadata;
505
+ const blockedBy = inlineBlockedBy(selection?.domElements ?? [el], property);
498
506
  const tokenBackedOpacityName = tokenRow?.tokenName
499
507
  && tokenRow.opacity
500
508
  && tokenRow.opacity.tokenName !== tokenRow.tokenName
@@ -544,7 +552,7 @@ export function TokenField(props) {
544
552
  ?? (selectedProperty?.token.kind === "mixed" ? ["Mixed tokens"] : undefined)
545
553
  ?? (expression
546
554
  ? tokenRow?.tokens?.filter((token) => token.name !== tokenRow.opacity?.tokenName).map((token) => token.name)
547
- : 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) => {
548
556
  if (formatRawValueProp)
549
557
  return formatRawValueProp(value);
550
558
  return completeCssValue(value.trim(), valuePolicyFor(property));
@@ -582,7 +590,7 @@ export function TokenField(props) {
582
590
  }, onUnlink: (value) => {
583
591
  setStyle(editTarget ?? el, property, value, effectiveMetadata);
584
592
  onAfterEdit?.();
585
- }, 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 }));
586
594
  }
587
595
  function tokenSuggestion(entry, groups) {
588
596
  return {
@@ -1,23 +1,14 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- function textContent(children) {
3
- if (children === null || children === undefined || typeof children === "boolean")
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: `token-label${className ? ` ${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
- return as === "code"
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
  }
@@ -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, clearWorkspace as resetPendingRules } from "../changes/changesLog.js";
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, clearWorkspace as resetPendingRules } from "../changes/changesLog.js";
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, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createContext, useContext, useMemo } from "react";
3
- import { Tooltip } from "@base-ui/react/tooltip";
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.Provider, { children: _jsxs(Tooltip.Root, { disableHoverablePopup: true, children: [_jsx(Tooltip.Trigger, { type: "button", delay: 0, className: `at-rule-indicator${className ? ` ${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 }) }), _jsx(Tooltip.Portal, { container: portalContainer(), children: _jsx(Tooltip.Positioner, { className: "at-rule-tooltip-positioner", side: "top", align: "end", sideOffset: 7, children: _jsx(Tooltip.Popup, { className: "at-rule-tooltip", "data-test": "at-rule-tooltip", children: _jsx("div", { className: "at-rule-tooltip__rules", children: atRules.map((atRule, index) => (_jsx("div", { className: `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}`))) }) }) }) })] }) }));
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, ReactElement } from "react";
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 function Button({ variant, size, className, ...props }: ButtonProps): ReactElement;
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
- export function Button({ variant = "secondary", size = "default", className, ...props }) {
3
- return (_jsx("button", { ...props, className: `button button--${variant} button--${size}${className ? ` ${className}` : ""}` }));
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, ReactElement, ReactNode } from "react";
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 function ControlSurface({ appearance, density, className, children, ...props }: ControlSurfaceProps): ReactElement;
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
- export function ControlSurface({ appearance = "default", density = "default", className, children, ...props }) {
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,11 @@
1
+ import type { ReactElement } from "react";
2
+ export interface InlineStyleWarningProps {
3
+ /** Inline declaration blocking the field; renders nothing when null. */
4
+ blockedBy: string | null;
5
+ dataTest?: string;
6
+ tooltipDataTest?: string;
7
+ className?: string;
8
+ symbolClassName?: string;
9
+ }
10
+ export declare function inlineStyleWarningContent(blockedBy: string | null): ReactElement | undefined;
11
+ export declare function InlineStyleWarning({ blockedBy, dataTest, tooltipDataTest, className, symbolClassName, }: InlineStyleWarningProps): ReactElement | null;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cx } from "./classNames.js";
3
+ import { Tooltip } from "./Tooltip.js";
4
+ export function inlineStyleWarningContent(blockedBy) {
5
+ if (blockedBy === null)
6
+ return undefined;
7
+ return (_jsx("div", { className: "at-rule-tooltip__rules", children: _jsxs("div", { className: "at-rule-tooltip__rule at-rule-tooltip__rule--active", children: ["Set inline (", _jsx("code", { children: blockedBy }), "). Previews can't beat inline styles \u2014 move it to a stylesheet to edit it here."] }) }));
8
+ }
9
+ export function InlineStyleWarning({ blockedBy, dataTest = "inline-style-warning", tooltipDataTest, className, symbolClassName, }) {
10
+ if (blockedBy === null)
11
+ return null;
12
+ return (_jsx(Tooltip, { content: inlineStyleWarningContent(blockedBy), delay: 0, positionerClassName: "at-rule-tooltip-positioner", popupClassName: "at-rule-tooltip", "data-test": tooltipDataTest, children: _jsx("button", { type: "button", className: cx("inline-style-warning", className), "data-test": dataTest, "aria-label": `Blocked by inline style: ${blockedBy}`, children: _jsx("span", { className: cx("inline-style-warning__symbol", symbolClassName), "aria-hidden": "true", children: "!" }) }) }));
13
+ }
@@ -7,6 +7,7 @@ export interface InspectorPopoverProps {
7
7
  side?: "top" | "bottom" | "left" | "right";
8
8
  align?: "start" | "center" | "end";
9
9
  sideOffset?: number;
10
+ triggerTooltip?: ReactNode;
10
11
  "data-test"?: string;
11
12
  }
12
13
  /**
@@ -14,4 +15,4 @@ export interface InspectorPopoverProps {
14
15
  * listbox popover, this leaves the popup content to the caller for compound
15
16
  * settings panels and field controls.
16
17
  */
17
- export declare function InspectorPopover({ triggerElement, children, open, onOpenChange, side, align, sideOffset, "data-test": dataTest, }: InspectorPopoverProps): ReactElement;
18
+ export declare function InspectorPopover({ triggerElement, children, open, onOpenChange, side, align, sideOffset, triggerTooltip, "data-test": dataTest, }: InspectorPopoverProps): ReactElement;
@@ -1,13 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Popover as BasePopover } from "@base-ui/react/popover";
3
+ import { Tooltip } from "./Tooltip.js";
4
+ import { portalContainer } from "./portalContainer.js";
3
5
  /**
4
6
  * Base UI popover anchored inside the inspector shadow root. Unlike the
5
7
  * listbox popover, this leaves the popup content to the caller for compound
6
8
  * settings panels and field controls.
7
9
  */
8
- export function InspectorPopover({ triggerElement, children, open, onOpenChange, side = "bottom", align = "center", sideOffset = 6, "data-test": dataTest, }) {
9
- const portalContainer = typeof document !== "undefined"
10
- ? document.getElementById("nudge-ui-root")?.shadowRoot ?? document.body
11
- : null;
12
- return (_jsxs(BasePopover.Root, { open: open, onOpenChange: onOpenChange, children: [_jsx(BasePopover.Trigger, { render: triggerElement, "data-test": dataTest }), _jsx(BasePopover.Portal, { container: portalContainer, children: _jsx(BasePopover.Positioner, { className: "inspector-popover__positioner", side: side, align: align, sideOffset: sideOffset, children: _jsx(BasePopover.Popup, { className: "inspector-popover__popup", "data-test": dataTest ? `${dataTest}-popover` : undefined, children: children }) }) })] }));
10
+ export function InspectorPopover({ triggerElement, children, open, onOpenChange, side = "bottom", align = "center", sideOffset = 6, triggerTooltip, "data-test": dataTest, }) {
11
+ return (_jsxs(BasePopover.Root, { open: open, onOpenChange: onOpenChange, children: [_jsx(Tooltip, { content: triggerTooltip, disabled: triggerTooltip === undefined, children: _jsx(BasePopover.Trigger, { render: triggerElement, "data-test": dataTest }) }), _jsx(BasePopover.Portal, { container: portalContainer(), children: _jsx(BasePopover.Positioner, { className: "inspector-popover__positioner", side: side, align: align, sideOffset: sideOffset, children: _jsx(BasePopover.Popup, { className: "inspector-popover__popup", "data-test": dataTest ? `${dataTest}-popover` : undefined, children: children }) }) })] }));
13
12
  }
@@ -17,6 +17,7 @@ export interface PopoverListboxProps {
17
17
  triggerClassName?: string;
18
18
  triggerDataTest?: string;
19
19
  triggerAriaLabel?: string;
20
+ triggerTooltip?: ReactNode;
20
21
  searchable?: boolean;
21
22
  searchPlaceholder?: string;
22
23
  searchAriaLabel?: string;
@@ -34,4 +35,4 @@ export interface PopoverListboxProps {
34
35
  onOpenChange: (open: boolean) => void;
35
36
  onSelect: (value: string) => void;
36
37
  }
37
- export declare function PopoverListbox({ value, query, items, open, trigger, triggerElement, triggerClassName, triggerDataTest, triggerAriaLabel, searchable, searchPlaceholder, searchAriaLabel, placeholder, inputRef, inputClassName, inputAppearance, inputDataTest, inputOnFocus, inputOnBlur, inputOnKeyDown, disabled, className, onQueryChange, onOpenChange, onSelect, }: PopoverListboxProps): ReactElement;
38
+ export declare function PopoverListbox({ value, query, items, open, trigger, triggerElement, triggerClassName, triggerDataTest, triggerAriaLabel, triggerTooltip, searchable, searchPlaceholder, searchAriaLabel, placeholder, inputRef, inputClassName, inputAppearance, inputDataTest, inputOnFocus, inputOnBlur, inputOnKeyDown, disabled, className, onQueryChange, onOpenChange, onSelect, }: PopoverListboxProps): ReactElement;
@@ -1,21 +1,22 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Combobox } from "@base-ui/react/combobox";
3
3
  import { Autocomplete } from "@base-ui/react/autocomplete";
4
- export function PopoverListbox({ value = null, query, items, open, trigger, triggerElement, triggerClassName, triggerDataTest, triggerAriaLabel, searchable = false, searchPlaceholder = "Search…", searchAriaLabel = "Search options", placeholder, inputRef, inputClassName, inputAppearance = "default", inputDataTest, inputOnFocus, inputOnBlur, inputOnKeyDown, disabled = false, className, onQueryChange, onOpenChange, onSelect, }) {
5
- const portalContainer = typeof document !== "undefined"
6
- ? document.getElementById("nudge-ui-root")?.shadowRoot ?? document.body
7
- : null;
4
+ import { cx } from "./classNames.js";
5
+ import { Tooltip } from "./Tooltip.js";
6
+ import { portalContainer } from "./portalContainer.js";
7
+ export function PopoverListbox({ value = null, query, items, open, trigger, triggerElement, triggerClassName, triggerDataTest, triggerAriaLabel, triggerTooltip, searchable = false, searchPlaceholder = "Search…", searchAriaLabel = "Search options", placeholder, inputRef, inputClassName, inputAppearance = "default", inputDataTest, inputOnFocus, inputOnBlur, inputOnKeyDown, disabled = false, className, onQueryChange, onOpenChange, onSelect, }) {
8
8
  const itemByValue = new Map(items.map((item) => [item.value, item]));
9
+ const resolvedTriggerTooltip = triggerTooltip ?? (triggerElement ? triggerAriaLabel : undefined);
9
10
  function renderComboboxItem(item) {
10
11
  return (_jsxs(Combobox.Item, { value: item.value, className: "popover-listbox__item", "data-test": item["data-test"], children: [item.leading ? _jsx("span", { className: "popover-listbox__leading", children: item.leading }) : null, _jsx("span", { className: "popover-listbox__label", children: item.label }), item.trailing ? _jsx("span", { className: "popover-listbox__trailing", children: item.trailing }) : null] }, item.value));
11
12
  }
12
- return (_jsx("div", { className: `popover-listbox${className ? ` ${className}` : ""}`, children: trigger || triggerElement ? (_jsxs(Combobox.Root, { value: value, inputValue: searchable ? undefined : query, open: open, items: items.map((item) => item.value), filteredItems: searchable ? undefined : items.map((item) => item.value), autoHighlight: true, itemToStringLabel: (item) => itemByValue.get(item)?.label ?? item, onInputValueChange: (next) => onQueryChange(next), onOpenChange: (next) => onOpenChange(next), onValueChange: (next) => {
13
+ return (_jsx("div", { className: cx("popover-listbox", className), children: trigger || triggerElement ? (_jsxs(Combobox.Root, { value: value, inputValue: searchable ? undefined : query, open: open, items: items.map((item) => item.value), filteredItems: searchable ? undefined : items.map((item) => item.value), autoHighlight: true, itemToStringLabel: (item) => itemByValue.get(item)?.label ?? item, onInputValueChange: (next) => onQueryChange(next), onOpenChange: (next) => onOpenChange(next), onValueChange: (next) => {
13
14
  if (typeof next === "string")
14
15
  onSelect(next);
15
- }, children: [triggerElement ? (_jsx(Combobox.Trigger, { render: triggerElement, className: `popover-listbox__trigger${triggerClassName ? ` ${triggerClassName}` : ""}`, "data-test": triggerDataTest, "aria-label": triggerAriaLabel, disabled: disabled })) : (_jsx(Combobox.Trigger, { className: `popover-listbox__trigger${triggerClassName ? ` ${triggerClassName}` : ""}`, "data-test": triggerDataTest, "aria-label": triggerAriaLabel, disabled: disabled, children: trigger })), _jsx(Combobox.Portal, { container: portalContainer, children: _jsx(Combobox.Positioner, { className: "popover-listbox__positioner", children: _jsxs(Combobox.Popup, { className: `popover-listbox__popup${searchable ? " popover-listbox__popup--searchable" : ""}`, children: [searchable ? (_jsxs(_Fragment, { children: [_jsx(Combobox.Input, { className: "popover-listbox__search-input", placeholder: searchPlaceholder, "aria-label": searchAriaLabel, "data-test": triggerDataTest ? `${triggerDataTest}-search` : "popover-listbox-search" }), _jsx(Combobox.Empty, { className: "popover-listbox__empty", children: "No matching options." })] })) : null, _jsx(Combobox.List, { className: `popover-listbox__list${searchable ? " popover-listbox__list--searchable" : ""}`, children: searchable
16
+ }, children: [_jsx(Tooltip, { content: resolvedTriggerTooltip, disabled: resolvedTriggerTooltip === undefined, stableTrigger: true, children: _jsx(Combobox.Trigger, { render: triggerElement, className: cx("popover-listbox__trigger", triggerClassName), "data-test": triggerDataTest, "aria-label": triggerAriaLabel, disabled: disabled, children: triggerElement ? undefined : trigger }) }), _jsx(Combobox.Portal, { container: portalContainer(), children: _jsx(Combobox.Positioner, { className: "popover-listbox__positioner", children: _jsxs(Combobox.Popup, { className: cx("popover-listbox__popup", searchable && "popover-listbox__popup--searchable"), children: [searchable ? (_jsxs(_Fragment, { children: [_jsx(Combobox.Input, { className: "popover-listbox__search-input", placeholder: searchPlaceholder, "aria-label": searchAriaLabel, "data-test": triggerDataTest ? `${triggerDataTest}-search` : "popover-listbox-search" }), _jsx(Combobox.Empty, { className: "popover-listbox__empty", children: "No matching options." })] })) : null, _jsx(Combobox.List, { className: cx("popover-listbox__list", searchable && "popover-listbox__list--searchable"), children: searchable
16
17
  ? ((itemValue) => {
17
18
  const item = itemByValue.get(itemValue);
18
19
  return item ? renderComboboxItem(item) : null;
19
20
  })
20
- : items.map((item) => renderComboboxItem(item)) })] }) }) })] })) : (_jsxs(Autocomplete.Root, { value: query, open: open, items: items.map((item) => item.value), filteredItems: items.map((item) => item.value), autoHighlight: true, mode: "none", openOnInputClick: true, onValueChange: onQueryChange, onOpenChange: (next) => onOpenChange(next), children: [_jsx(Autocomplete.Input, { ref: inputRef, className: `text-input${inputAppearance === "embedded" ? " text-input--embedded" : ""}${inputClassName ? ` ${inputClassName}` : ""}`, placeholder: placeholder, "data-test": inputDataTest, onFocus: inputOnFocus, onBlur: inputOnBlur, onKeyDownCapture: inputOnKeyDown, disabled: disabled }), _jsx(Autocomplete.Portal, { container: portalContainer, children: _jsx(Autocomplete.Positioner, { className: "popover-listbox__positioner", children: _jsx(Autocomplete.Popup, { className: "popover-listbox__popup", children: _jsx(Autocomplete.List, { className: "popover-listbox__list", children: items.map((item) => (_jsxs(Autocomplete.Item, { value: item.value, className: "popover-listbox__item", "data-test": item["data-test"], onClick: () => onSelect(item.value), children: [item.leading ? _jsx("span", { className: "popover-listbox__leading", children: item.leading }) : null, _jsx("span", { className: "popover-listbox__label", children: item.label }), item.trailing ? _jsx("span", { className: "popover-listbox__trailing", children: item.trailing }) : null] }, item.value))) }) }) }) })] })) }));
21
+ : items.map((item) => renderComboboxItem(item)) })] }) }) })] })) : (_jsxs(Autocomplete.Root, { value: query, open: open, items: items.map((item) => item.value), filteredItems: items.map((item) => item.value), autoHighlight: true, mode: "none", openOnInputClick: true, onValueChange: onQueryChange, onOpenChange: (next) => onOpenChange(next), children: [_jsx(Autocomplete.Input, { ref: inputRef, className: cx("text-input", inputAppearance === "embedded" && "text-input--embedded", inputClassName), placeholder: placeholder, "data-test": inputDataTest, onFocus: inputOnFocus, onBlur: inputOnBlur, onKeyDownCapture: inputOnKeyDown, disabled: disabled }), _jsx(Autocomplete.Portal, { container: portalContainer(), children: _jsx(Autocomplete.Positioner, { className: "popover-listbox__positioner", children: _jsx(Autocomplete.Popup, { className: "popover-listbox__popup", children: _jsx(Autocomplete.List, { className: "popover-listbox__list", children: items.map((item) => (_jsxs(Autocomplete.Item, { value: item.value, className: "popover-listbox__item", "data-test": item["data-test"], onClick: () => onSelect(item.value), children: [item.leading ? _jsx("span", { className: "popover-listbox__leading", children: item.leading }) : null, _jsx("span", { className: "popover-listbox__label", children: item.label }), item.trailing ? _jsx("span", { className: "popover-listbox__trailing", children: item.trailing }) : null] }, item.value))) }) }) }) })] })) }));
21
22
  }
@@ -14,11 +14,12 @@ interface SegmentedControlProps<T extends string> {
14
14
  "data-test"?: string;
15
15
  "data-property"?: string;
16
16
  className?: string;
17
+ disabled?: boolean;
17
18
  /** Allows the active option to be cleared by clicking it again. */
18
19
  allowDeselect?: boolean;
19
20
  /** Restores the value represented by an unselected control. */
20
21
  onDeselect?: () => void;
21
22
  }
22
23
  /** A compact single-choice control for adjacent, peer actions. */
23
- export declare function SegmentedControl<T extends string>({ value, options, onChange, "aria-label": ariaLabel, "data-test": dataTest, "data-property": dataProperty, className, allowDeselect, onDeselect, }: SegmentedControlProps<T>): ReactElement;
24
+ export declare function SegmentedControl<T extends string>({ value, options, onChange, "aria-label": ariaLabel, "data-test": dataTest, "data-property": dataProperty, className, disabled, allowDeselect, onDeselect, }: SegmentedControlProps<T>): ReactElement;
24
25
  export {};
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Toggle } from "@base-ui/react/toggle";
3
3
  /** A compact single-choice control for adjacent, peer actions. */
4
- export function SegmentedControl({ value, options, onChange, "aria-label": ariaLabel, "data-test": dataTest, "data-property": dataProperty, className, allowDeselect = false, onDeselect, }) {
4
+ export function SegmentedControl({ value, options, onChange, "aria-label": ariaLabel, "data-test": dataTest, "data-property": dataProperty, className, disabled = false, allowDeselect = false, onDeselect, }) {
5
5
  return (_jsx("div", { className: `segmented-control${className ? ` ${className}` : ""}`, role: "group", "aria-label": ariaLabel, "data-test": dataTest, "data-property": dataProperty, children: options.map((option) => {
6
6
  const selected = option.value === value;
7
- return (_jsx(Toggle, { type: "button", className: `button segmented-control__button${selected ? " segmented-control__button--selected" : ""}`, pressed: selected, "aria-label": option.label, title: option.label, "data-test": option.testId, "data-active": selected ? "true" : "false", onPressedChange: (pressed) => {
7
+ return (_jsx(Toggle, { type: "button", className: `button segmented-control__button${selected ? " segmented-control__button--selected" : ""}`, pressed: selected, disabled: disabled, "aria-label": option.label, "data-test": option.testId, "data-active": selected ? "true" : "false", onPressedChange: (pressed) => {
8
8
  if (pressed) {
9
9
  onChange(option.value);
10
10
  }
@@ -1,4 +1,5 @@
1
- import type { ButtonHTMLAttributes, ReactElement } from "react";
1
+ import { Select as BaseSelect } from "@base-ui/react/select";
2
+ import type { ButtonHTMLAttributes, ComponentProps, ReactElement } from "react";
2
3
  import type { ControlAppearance } from "./ControlSurface.js";
3
4
  export interface SelectOption {
4
5
  value: string;
@@ -15,7 +16,11 @@ export type SelectProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "onChang
15
16
  groups?: SelectGroup[];
16
17
  placeholder?: string;
17
18
  compact?: boolean;
19
+ /** Uses the shared icon button as the trigger; requires an accessible label. */
20
+ iconOnly?: boolean;
18
21
  appearance?: ControlAppearance;
22
+ /** Overrides popup placement, including text alignment for icon-only triggers. */
23
+ popupPosition?: Pick<ComponentProps<typeof BaseSelect.Positioner>, "side" | "align" | "alignItemWithTrigger">;
19
24
  searchable?: boolean;
20
25
  searchPlaceholder?: string;
21
26
  searchAriaLabel?: string;
@@ -2,25 +2,24 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Select as BaseSelect } from "@base-ui/react/select";
3
3
  import { Combobox as BaseCombobox } from "@base-ui/react/combobox";
4
4
  import { IconCheck, IconChevronDown } from "@tabler/icons-react";
5
+ import { portalContainer } from "./portalContainer.js";
6
+ import { IconButton } from "./IconButton.js";
5
7
  export function Select(props) {
6
8
  if (props.searchable)
7
9
  return _jsx(SearchableSelect, { ...props });
8
10
  return _jsx(NativeSelect, { ...props });
9
11
  }
10
- function NativeSelect({ value, options = [], groups = [], placeholder, compact, appearance = "default", searchable: _searchable, searchPlaceholder: _searchPlaceholder, searchAriaLabel: _searchAriaLabel, className, disabled, children, ...props }) {
12
+ function NativeSelect({ value, options = [], groups = [], placeholder, compact, iconOnly, appearance = "default", popupPosition, searchable: _searchable, searchPlaceholder: _searchPlaceholder, searchAriaLabel: _searchAriaLabel, className, disabled, children, ...props }) {
11
13
  const allOptions = [...options, ...groups.flatMap((group) => group.options)];
12
14
  const selectedOption = allOptions.find((option) => option.value === value);
13
- const portalContainer = typeof document !== "undefined"
14
- ? document.getElementById("nudge-ui-root")?.shadowRoot ?? document.body
15
- : null;
16
15
  function handleValueChange(next) {
17
16
  if (typeof next === "string")
18
17
  props.onValueChange?.(next);
19
18
  }
20
19
  const { onValueChange: _onValueChange, ...triggerProps } = props;
21
- return (_jsxs(BaseSelect.Root, { value: value || null, disabled: disabled, items: allOptions.map((option) => ({ value: option.value, label: option.label })), onValueChange: handleValueChange, children: [_jsxs(BaseSelect.Trigger, { ...triggerProps, disabled: disabled, className: `select${compact ? " select--compact" : ""}${appearance === "embedded" ? " select--embedded" : ""}${className ? ` ${className}` : ""}`, children: [_jsx(BaseSelect.Value, { className: "select__value", placeholder: placeholder, children: selectedOption?.label ?? (value || undefined) }), _jsx(BaseSelect.Icon, { className: "select__icon", children: _jsx(IconChevronDown, { size: 15, stroke: 1.8, "aria-hidden": "true" }) }), children] }), _jsx(BaseSelect.Portal, { container: portalContainer, children: _jsx(BaseSelect.Positioner, { className: "select__positioner", sideOffset: 4, children: _jsx(BaseSelect.Popup, { className: "select__popup", children: _jsxs(BaseSelect.List, { className: "select__list", children: [options.map((option) => _jsx(SelectItem, { option: option }, option.value)), groups.map((group) => (_jsxs(BaseSelect.Group, { className: "select__group", children: [_jsx(BaseSelect.GroupLabel, { className: "select__group-label", children: group.label }), group.options.map((option) => _jsx(SelectItem, { option: option }, `${group.label}-${option.value}`))] }, group.label)))] }) }) }) })] }));
20
+ return (_jsxs(BaseSelect.Root, { value: value || null, disabled: disabled, items: allOptions.map((option) => ({ value: option.value, label: option.label })), onValueChange: handleValueChange, children: [_jsxs(BaseSelect.Trigger, { ...triggerProps, render: iconOnly ? _jsx(IconButton, { label: props["aria-label"] ?? "Select option" }) : undefined, disabled: disabled, className: `select${iconOnly ? " select--icon-only" : ""}${compact ? " select--compact" : ""}${appearance === "embedded" ? " select--embedded" : ""}${className ? ` ${className}` : ""}`, children: [_jsx(BaseSelect.Value, { className: "select__value", placeholder: placeholder, children: selectedOption?.label ?? (value || undefined) }), _jsx(BaseSelect.Icon, { className: "select__icon", children: _jsx(IconChevronDown, { size: 15, stroke: 1.8, "aria-hidden": "true" }) }), children] }), _jsx(BaseSelect.Portal, { container: portalContainer(), children: _jsx(BaseSelect.Positioner, { className: "select__positioner", sideOffset: 4, ...popupPosition, alignItemWithTrigger: iconOnly ? false : popupPosition?.alignItemWithTrigger, children: _jsx(BaseSelect.Popup, { className: "select__popup", children: _jsxs(BaseSelect.List, { className: "select__list", children: [options.map((option) => _jsx(SelectItem, { option: option }, option.value)), groups.map((group) => (_jsxs(BaseSelect.Group, { className: "select__group", children: [_jsx(BaseSelect.GroupLabel, { className: "select__group-label", children: group.label }), group.options.map((option) => _jsx(SelectItem, { option: option }, `${group.label}-${option.value}`))] }, group.label)))] }) }) }) })] }));
22
21
  }
23
- function SearchableSelect({ value, options = [], groups = [], placeholder, compact, appearance = "default", searchable: _searchable, searchPlaceholder = "Search…", searchAriaLabel = "Search options", className, disabled, children, "data-test": dataTest, ...props }) {
22
+ function SearchableSelect({ value, options = [], groups = [], placeholder, compact, iconOnly, appearance = "default", popupPosition, searchable: _searchable, searchPlaceholder = "Search…", searchAriaLabel = "Search options", className, disabled, children, "data-test": dataTest, ...props }) {
24
23
  const allOptions = [...options, ...groups.flatMap((group) => group.options)];
25
24
  const selectedOption = allOptions.find((option) => option.value === value);
26
25
  const optionByValue = new Map(allOptions.map((option) => [option.value, option]));
@@ -34,16 +33,13 @@ function SearchableSelect({ value, options = [], groups = [], placeholder, compa
34
33
  items: group.options.map((option) => option.value),
35
34
  })),
36
35
  ];
37
- const portalContainer = typeof document !== "undefined"
38
- ? document.getElementById("nudge-ui-root")?.shadowRoot ?? document.body
39
- : null;
40
36
  function handleValueChange(next) {
41
37
  if (typeof next === "string")
42
38
  props.onValueChange?.(next);
43
39
  }
44
40
  const { onValueChange: _onValueChange, ...triggerProps } = props;
45
- const triggerClassName = `select${compact ? " select--compact" : ""}${appearance === "embedded" ? " select--embedded" : ""}${className ? ` ${className}` : ""}`;
46
- return (_jsxs(BaseCombobox.Root, { value: value || null, disabled: disabled, items: searchableGroups, itemToStringLabel: (item) => optionByValue.get(item)?.label ?? item, autoHighlight: true, onValueChange: handleValueChange, children: [_jsxs(BaseCombobox.Trigger, { ...triggerProps, "data-test": dataTest, disabled: disabled, className: triggerClassName, children: [_jsx("span", { className: "select__value", children: _jsx(BaseCombobox.Value, { placeholder: placeholder, children: selectedOption?.label ?? (value || undefined) }) }), _jsx(BaseCombobox.Icon, { className: "select__icon", children: _jsx(IconChevronDown, { size: 15, stroke: 1.8, "aria-hidden": "true" }) }), children] }), _jsx(BaseCombobox.Portal, { container: portalContainer, children: _jsx(BaseCombobox.Positioner, { className: "select__positioner", sideOffset: 4, children: _jsxs(BaseCombobox.Popup, { className: "select__popup select__popup--searchable", children: [_jsx(BaseCombobox.Input, { className: "select__search-input", placeholder: searchPlaceholder, "aria-label": searchAriaLabel, "data-test": dataTest ? `${dataTest}-search` : "select-search" }), _jsx(BaseCombobox.Empty, { className: "select__empty", children: "No matching options." }), _jsx(BaseCombobox.List, { className: "select__list select__list--searchable", children: (group) => (_jsxs(BaseCombobox.Group, { className: "select__group", items: group.items, children: [group.label ? (_jsx(BaseCombobox.GroupLabel, { className: "select__group-label", children: group.label })) : null, _jsx(BaseCombobox.Collection, { children: (item) => {
41
+ const triggerClassName = `select${iconOnly ? " select--icon-only" : ""}${compact ? " select--compact" : ""}${appearance === "embedded" ? " select--embedded" : ""}${className ? ` ${className}` : ""}`;
42
+ return (_jsxs(BaseCombobox.Root, { value: value || null, disabled: disabled, items: searchableGroups, itemToStringLabel: (item) => optionByValue.get(item)?.label ?? item, autoHighlight: true, onValueChange: handleValueChange, children: [_jsxs(BaseCombobox.Trigger, { ...triggerProps, render: iconOnly ? _jsx(IconButton, { label: props["aria-label"] ?? "Select option" }) : undefined, "data-test": dataTest, disabled: disabled, className: triggerClassName, children: [_jsx("span", { className: "select__value", children: _jsx(BaseCombobox.Value, { placeholder: placeholder, children: selectedOption?.label ?? (value || undefined) }) }), _jsx(BaseCombobox.Icon, { className: "select__icon", children: _jsx(IconChevronDown, { size: 15, stroke: 1.8, "aria-hidden": "true" }) }), children] }), _jsx(BaseCombobox.Portal, { container: portalContainer(), children: _jsx(BaseCombobox.Positioner, { className: "select__positioner", sideOffset: 4, side: popupPosition?.side, align: popupPosition?.align, children: _jsxs(BaseCombobox.Popup, { className: "select__popup select__popup--searchable", children: [_jsx(BaseCombobox.Input, { className: "select__search-input", placeholder: searchPlaceholder, "aria-label": searchAriaLabel, "data-test": dataTest ? `${dataTest}-search` : "select-search" }), _jsx(BaseCombobox.Empty, { className: "select__empty", children: "No matching options." }), _jsx(BaseCombobox.List, { className: "select__list select__list--searchable", children: (group) => (_jsxs(BaseCombobox.Group, { className: "select__group", items: group.items, children: [group.label ? (_jsx(BaseCombobox.GroupLabel, { className: "select__group-label", children: group.label })) : null, _jsx(BaseCombobox.Collection, { children: (item) => {
47
43
  const option = optionByValue.get(item);
48
44
  return option ? _jsx(SearchableSelectItem, { option: option }, item) : null;
49
45
  } })] }, group.value)) })] }) }) })] }));