nudge-ui 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/README.md +164 -46
  2. package/dist/client.mjs +252 -54
  3. package/dist/css/value-semantics/colorSemantics.d.ts +4 -0
  4. package/dist/css/value-semantics/colorSemantics.js +17 -0
  5. package/dist/hosts/astro/astroRuntimeConfig.js +1 -0
  6. package/dist/hosts/astro/clientTransport.js +41 -32
  7. package/dist/hosts/astro/integration.d.ts +2 -2
  8. package/dist/hosts/astro/integration.js +9 -4
  9. package/dist/hosts/astro/markdownIdentity.d.ts +28 -0
  10. package/dist/hosts/astro/markdownIdentity.js +81 -0
  11. package/dist/hosts/environment.d.ts +15 -0
  12. package/dist/hosts/environment.js +16 -0
  13. package/dist/hosts/next/manifest.js +1 -1
  14. package/dist/hosts/next/sidecar.js +12 -2
  15. package/dist/hosts/next/wrapper.d.ts +2 -0
  16. package/dist/hosts/next/wrapper.js +2 -1
  17. package/dist/hosts/projectBridge.d.ts +1 -0
  18. package/dist/hosts/projectBridge.js +1 -0
  19. package/dist/hosts/static/manifest.js +3 -1
  20. package/dist/hosts/static/server.js +4 -0
  21. package/dist/hosts/vite/vite.d.ts +4 -0
  22. package/dist/hosts/vite/vite.js +28 -5
  23. package/dist/inspector/agent/McpConnectionDialog.d.ts +3 -2
  24. package/dist/inspector/agent/McpConnectionDialog.js +23 -22
  25. package/dist/inspector/agent/activity.d.ts +18 -0
  26. package/dist/inspector/agent/activity.js +70 -0
  27. package/dist/inspector/agent/client.d.ts +8 -0
  28. package/dist/inspector/agent/client.js +65 -5
  29. package/dist/inspector/agent/connectionStatus.d.ts +3 -3
  30. package/dist/inspector/agent/connectionStatus.js +9 -2
  31. package/dist/inspector/agent/httpTransport.d.ts +6 -0
  32. package/dist/inspector/agent/httpTransport.js +50 -3
  33. package/dist/inspector/agent/protocol.d.ts +9 -3
  34. package/dist/inspector/agent/protocol.js +1 -1
  35. package/dist/inspector/agent/verification.d.ts +11 -1
  36. package/dist/inspector/agent/verification.js +53 -25
  37. package/dist/inspector/canvas/AgentActivityOverlay.d.ts +13 -0
  38. package/dist/inspector/canvas/AgentActivityOverlay.js +111 -0
  39. package/dist/inspector/canvas/CanvasCard.d.ts +9 -2
  40. package/dist/inspector/canvas/CanvasCard.js +133 -38
  41. package/dist/inspector/canvas/CanvasElementOverlay.js +200 -22
  42. package/dist/inspector/canvas/CanvasToolIcons.d.ts +10 -0
  43. package/dist/inspector/canvas/CanvasToolIcons.js +20 -0
  44. package/dist/inspector/canvas/CanvasToolbar.js +8 -4
  45. package/dist/inspector/canvas/CanvasWorkspace.js +243 -56
  46. package/dist/inspector/canvas/StaleChangeIndicator.js +3 -13
  47. package/dist/inspector/canvas/agentPresentation.d.ts +8 -8
  48. package/dist/inspector/canvas/agentPresentation.js +64 -52
  49. package/dist/inspector/canvas/canvasGestures.d.ts +1 -1
  50. package/dist/inspector/canvas/canvasGestures.js +1 -1
  51. package/dist/inspector/canvas/canvasStore.d.ts +46 -82
  52. package/dist/inspector/canvas/canvasStore.js +251 -284
  53. package/dist/inspector/canvas/frameContent.d.ts +21 -0
  54. package/dist/inspector/canvas/frameContent.js +44 -0
  55. package/dist/inspector/canvas/frameProtocol.d.ts +34 -4
  56. package/dist/inspector/canvas/frameProtocol.js +9 -2
  57. package/dist/inspector/canvas/keyboardShortcuts.d.ts +4 -1
  58. package/dist/inspector/canvas/keyboardShortcuts.js +5 -3
  59. package/dist/inspector/canvas/layout.d.ts +52 -0
  60. package/dist/inspector/canvas/layout.js +106 -0
  61. package/dist/inspector/canvas/linkEligibility.d.ts +0 -5
  62. package/dist/inspector/canvas/linkEligibility.js +0 -29
  63. package/dist/inspector/canvas/projection.d.ts +15 -5
  64. package/dist/inspector/canvas/projection.js +69 -13
  65. package/dist/inspector/canvas/rendererBootstrap.js +45 -4
  66. package/dist/inspector/canvas/rendererElementSelector.d.ts +1 -1
  67. package/dist/inspector/canvas/rendererElementSelector.js +102 -45
  68. package/dist/inspector/canvas/rendererStylesheet.js +2 -2
  69. package/dist/inspector/canvas/resizeHandleScale.js +1 -1
  70. package/dist/inspector/canvas/sessionStore.d.ts +11 -26
  71. package/dist/inspector/canvas/sessionStore.js +43 -183
  72. package/dist/inspector/canvas/staleChangeDetector.js +9 -3
  73. package/dist/inspector/canvas/useCanvasLayoutAnimation.d.ts +5 -0
  74. package/dist/inspector/canvas/useCanvasLayoutAnimation.js +107 -0
  75. package/dist/inspector/canvas/viewStore.d.ts +38 -0
  76. package/dist/inspector/canvas/viewStore.js +104 -0
  77. package/dist/inspector/canvas/wheelPan.d.ts +8 -0
  78. package/dist/inspector/canvas/wheelPan.js +8 -0
  79. package/dist/inspector/changes/changesLog.d.ts +6 -5
  80. package/dist/inspector/changes/changesLog.js +40 -32
  81. package/dist/inspector/changes/draftChanges.d.ts +56 -0
  82. package/dist/inspector/changes/draftChanges.js +300 -0
  83. package/dist/inspector/changes/previewDiagnostics.d.ts +4 -2
  84. package/dist/inspector/changes/previewDiagnostics.js +11 -25
  85. package/dist/inspector/clientManifest.d.ts +3 -1
  86. package/dist/inspector/clientManifest.js +1 -0
  87. package/dist/inspector/comments/CommentsOverlay.d.ts +2 -0
  88. package/dist/inspector/comments/CommentsOverlay.js +250 -0
  89. package/dist/inspector/comments/element.d.ts +6 -0
  90. package/dist/inspector/comments/element.js +47 -0
  91. package/dist/inspector/comments/store.d.ts +29 -0
  92. package/dist/inspector/comments/store.js +121 -0
  93. package/dist/inspector/comments/verification.d.ts +5 -0
  94. package/dist/inspector/comments/verification.js +52 -0
  95. package/dist/inspector/drafts/model.d.ts +35 -0
  96. package/dist/inspector/drafts/model.js +45 -0
  97. package/dist/inspector/drafts/store.d.ts +28 -0
  98. package/dist/inspector/drafts/store.js +231 -0
  99. package/dist/inspector/index.js +26 -35
  100. package/dist/inspector/inline-text/inlineTextEditor.js +7 -0
  101. package/dist/inspector/inspection/useBrowserCssInspection.js +15 -1
  102. package/dist/inspector/iterations/capture.d.ts +2 -0
  103. package/dist/inspector/iterations/capture.js +173 -0
  104. package/dist/inspector/iterations/client.d.ts +7 -0
  105. package/dist/inspector/iterations/client.js +52 -0
  106. package/dist/inspector/iterations/coordinator.d.ts +15 -0
  107. package/dist/inspector/iterations/coordinator.js +130 -0
  108. package/dist/inspector/iterations/prompt.d.ts +3 -0
  109. package/dist/inspector/iterations/prompt.js +26 -0
  110. package/dist/inspector/overlay/DomNavigator.d.ts +10 -0
  111. package/dist/inspector/overlay/DomNavigator.js +46 -0
  112. package/dist/inspector/overlay/InspectorOverlay.js +6 -2
  113. package/dist/inspector/overlay/clickPolicy.d.ts +18 -2
  114. package/dist/inspector/overlay/clickPolicy.js +34 -3
  115. package/dist/inspector/overlay/elementSelector.d.ts +1 -1
  116. package/dist/inspector/overlay/elementSelector.js +18 -7
  117. package/dist/inspector/overlay/interactionStyles.js +3 -1
  118. package/dist/inspector/overlay/spacingGestures.d.ts +15 -3
  119. package/dist/inspector/overlay/spacingGestures.js +88 -13
  120. package/dist/inspector/projection/{workspaceProjection.d.ts → draftProjection.d.ts} +6 -6
  121. package/dist/inspector/projection/{workspaceProjection.js → draftProjection.js} +4 -4
  122. package/dist/inspector/projection/renderedInstance.d.ts +2 -1
  123. package/dist/inspector/projection/renderedInstance.js +9 -5
  124. package/dist/inspector/projection/structuralProjection.d.ts +2 -1
  125. package/dist/inspector/projection/structuralProjection.js +19 -15
  126. package/dist/inspector/projection/textProjection.d.ts +2 -1
  127. package/dist/inspector/projection/textProjection.js +8 -4
  128. package/dist/inspector/prompt/PromptSettingsDialog.js +1 -5
  129. package/dist/inspector/prompt/clipboardHandoff.d.ts +10 -18
  130. package/dist/inspector/prompt/clipboardHandoff.js +92 -143
  131. package/dist/inspector/prompt/generatePrompt.d.ts +4 -1
  132. package/dist/inspector/prompt/generatePrompt.js +17 -16
  133. package/dist/inspector/runtime/runtimeConfig.d.ts +10 -1
  134. package/dist/inspector/runtime/runtimeConfig.js +24 -0
  135. package/dist/inspector/selection/hierarchy.d.ts +6 -0
  136. package/dist/inspector/selection/hierarchy.js +8 -0
  137. package/dist/inspector/settings/SettingsDialog.d.ts +1 -1
  138. package/dist/inspector/settings/SettingsDialog.js +22 -9
  139. package/dist/inspector/shell/AgentStatusButton.d.ts +11 -0
  140. package/dist/inspector/shell/AgentStatusButton.js +36 -0
  141. package/dist/inspector/shell/AppShell.js +4 -2
  142. package/dist/inspector/shell/ChangesLog.js +47 -27
  143. package/dist/inspector/shell/CopyPromptButton.js +146 -90
  144. package/dist/inspector/shell/EmptyState.js +9 -8
  145. package/dist/inspector/shell/InspectorShell.js +14 -25
  146. package/dist/inspector/shell/PeekOriginalButton.js +24 -23
  147. package/dist/inspector/shell/originalPreview.js +5 -5
  148. package/dist/inspector/shell/shortcuts.d.ts +3 -0
  149. package/dist/inspector/shell/shortcuts.js +11 -0
  150. package/dist/inspector/sketch/SketchEditor.js +14 -14
  151. package/dist/inspector/sketch/SketchEntryButton.js +1 -1
  152. package/dist/inspector/sketch/SketchFrameOverlay.d.ts +3 -1
  153. package/dist/inspector/sketch/SketchFrameOverlay.js +11 -8
  154. package/dist/inspector/sketch/SketchLayersPanel.js +13 -5
  155. package/dist/inspector/sketch/SketchOverlay.js +7 -7
  156. package/dist/inspector/sketch/SketchWorkspace.js +18 -12
  157. package/dist/inspector/sketch/interaction.d.ts +1 -0
  158. package/dist/inspector/sketch/interaction.js +8 -4
  159. package/dist/inspector/sketch/model.d.ts +5 -0
  160. package/dist/inspector/sketch/model.js +6 -2
  161. package/dist/inspector/sketch/raster.d.ts +1 -2
  162. package/dist/inspector/sketch/raster.js +68 -4
  163. package/dist/inspector/sketch/store.js +48 -23
  164. package/dist/inspector/styleEditors/BackgroundEditor.d.ts +4 -0
  165. package/dist/inspector/styleEditors/BackgroundEditor.js +195 -0
  166. package/dist/inspector/styleEditors/BorderEditor.js +49 -78
  167. package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -1
  168. package/dist/inspector/styleEditors/BoxShadowEditor.d.ts +1 -2
  169. package/dist/inspector/styleEditors/BoxShadowEditor.js +132 -4
  170. package/dist/inspector/styleEditors/ColorPicker.d.ts +5 -1
  171. package/dist/inspector/styleEditors/ColorPicker.js +10 -4
  172. package/dist/inspector/styleEditors/GapField.js +3 -5
  173. package/dist/inspector/styleEditors/GridChildSection.d.ts +1 -1
  174. package/dist/inspector/styleEditors/GridChildSection.js +18 -9
  175. package/dist/inspector/styleEditors/GridPicker.d.ts +1 -1
  176. package/dist/inspector/styleEditors/GridPicker.js +8 -2
  177. package/dist/inspector/styleEditors/GridSection.js +1 -1
  178. package/dist/inspector/styleEditors/GridValueField.js +19 -14
  179. package/dist/inspector/styleEditors/ImageBackgroundEditor.d.ts +18 -0
  180. package/dist/inspector/styleEditors/ImageBackgroundEditor.js +118 -0
  181. package/dist/inspector/styleEditors/LayoutBlockedIndicator.d.ts +2 -2
  182. package/dist/inspector/styleEditors/LayoutBlockedIndicator.js +3 -3
  183. package/dist/inspector/styleEditors/LayoutComboField.js +6 -4
  184. package/dist/inspector/styleEditors/LayoutDropdown.js +6 -3
  185. package/dist/inspector/styleEditors/LayoutSection.js +32 -11
  186. package/dist/inspector/styleEditors/SpacingBox.js +16 -9
  187. package/dist/inspector/styleEditors/Typography.js +11 -3
  188. package/dist/inspector/styleEditors/backgroundLayers.d.ts +24 -0
  189. package/dist/inspector/styleEditors/backgroundLayers.js +51 -0
  190. package/dist/inspector/styleEditors/gradientValue.d.ts +17 -0
  191. package/dist/inspector/styleEditors/gradientValue.js +114 -0
  192. package/dist/inspector/styleEditors/inlineAuthored.d.ts +10 -0
  193. package/dist/inspector/styleEditors/inlineAuthored.js +114 -0
  194. package/dist/inspector/styleEditors/layoutValue.d.ts +0 -8
  195. package/dist/inspector/styleEditors/layoutValue.js +0 -42
  196. package/dist/inspector/styleEditors/nudgeValue.d.ts +4 -4
  197. package/dist/inspector/styleEditors/nudgeValue.js +41 -11
  198. package/dist/inspector/tokens/TokenField.d.ts +7 -0
  199. package/dist/inspector/tokens/TokenField.js +49 -22
  200. package/dist/inspector/tokens/TokenLabel.js +5 -14
  201. package/dist/inspector/tokens/TokensPanel.js +2 -1
  202. package/dist/inspector/tokens/dragPointerLock.d.ts +8 -0
  203. package/dist/inspector/tokens/dragPointerLock.js +70 -0
  204. package/dist/inspector/tokens/editActions.d.ts +1 -1
  205. package/dist/inspector/tokens/editActions.js +1 -1
  206. package/dist/inspector/ui/AtRuleContext.js +4 -6
  207. package/dist/inspector/ui/Button.d.ts +6 -2
  208. package/dist/inspector/ui/Button.js +4 -3
  209. package/dist/inspector/ui/ControlSurface.d.ts +2 -2
  210. package/dist/inspector/ui/ControlSurface.js +4 -3
  211. package/dist/inspector/ui/Disclosure.d.ts +22 -0
  212. package/dist/inspector/ui/Disclosure.js +13 -0
  213. package/dist/inspector/ui/InlineStyleWarning.d.ts +11 -0
  214. package/dist/inspector/ui/InlineStyleWarning.js +13 -0
  215. package/dist/inspector/ui/InspectorPopover.d.ts +2 -1
  216. package/dist/inspector/ui/InspectorPopover.js +4 -5
  217. package/dist/inspector/ui/PopoverListbox.d.ts +2 -1
  218. package/dist/inspector/ui/PopoverListbox.js +8 -7
  219. package/dist/inspector/ui/SegmentedControl.d.ts +2 -1
  220. package/dist/inspector/ui/SegmentedControl.js +2 -2
  221. package/dist/inspector/ui/Select.d.ts +6 -1
  222. package/dist/inspector/ui/Select.js +7 -11
  223. package/dist/inspector/ui/SideValuesField.js +1 -1
  224. package/dist/inspector/ui/Tooltip.d.ts +26 -0
  225. package/dist/inspector/ui/Tooltip.js +32 -0
  226. package/dist/inspector/ui/classNames.d.ts +2 -0
  227. package/dist/inspector/ui/classNames.js +4 -0
  228. package/dist/inspector/ui/customCursors.d.ts +23 -0
  229. package/dist/inspector/ui/customCursors.js +122 -0
  230. package/dist/inspector/ui/dragCursor.d.ts +6 -0
  231. package/dist/inspector/ui/dragCursor.js +13 -0
  232. package/dist/inspector/ui/portalContainer.d.ts +2 -0
  233. package/dist/inspector/ui/portalContainer.js +6 -0
  234. package/dist/inspector/ui/styles.js +34 -24
  235. package/dist/inspector/workspace/commands.d.ts +9 -0
  236. package/dist/inspector/workspace/commands.js +82 -0
  237. package/dist/inspector/workspace/controller.d.ts +4 -0
  238. package/dist/inspector/workspace/controller.js +66 -0
  239. package/dist/inspector/workspace/handoff.d.ts +42 -0
  240. package/dist/inspector/workspace/handoff.js +115 -0
  241. package/dist/inspector/workspace/timeline.d.ts +30 -0
  242. package/dist/inspector/workspace/timeline.js +108 -0
  243. package/dist/internal/agent-protocol.d.ts +19 -2
  244. package/dist/internal/agent-protocol.js +13 -0
  245. package/dist/nudge-ui.mjs +560 -299
  246. package/dist/project/artifacts.d.ts +13 -0
  247. package/dist/project/artifacts.js +253 -0
  248. package/dist/transport/artifacts.d.ts +8 -0
  249. package/dist/transport/artifacts.js +9 -0
  250. package/dist/transport/editor.d.ts +20 -1
  251. package/dist/transport/editor.js +44 -11
  252. package/dist/transport/routes.d.ts +6 -1
  253. package/dist/transport/routes.js +6 -1
  254. package/package.json +6 -2
  255. package/dist/inspector/changes/workspaceChanges.d.ts +0 -43
  256. package/dist/inspector/changes/workspaceChanges.js +0 -239
  257. package/dist/inspector/shell/DomNavigation.d.ts +0 -8
  258. package/dist/inspector/shell/DomNavigation.js +0 -30
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Collapsible } from "@base-ui/react/collapsible";
3
+ import { IconChevronDown } from "@tabler/icons-react";
4
+ /**
5
+ * A single collapsible disclosure built on Base UI Collapsible.
6
+ * Replaces native details/summary for consistent 12px label styling and chevron.
7
+ */
8
+ export function Disclosure({ title, badge, children, className, triggerClassName, panelClassName, defaultOpen, open, onOpenChange, keepMounted = true, "data-test": dataTest, triggerDataTest, }) {
9
+ function handleOpenChange(next) {
10
+ onOpenChange?.(next);
11
+ }
12
+ return (_jsxs(Collapsible.Root, { className: `disclosure${className ? ` ${className}` : ""}`, "data-test": dataTest, defaultOpen: defaultOpen, open: open, onOpenChange: handleOpenChange, children: [_jsxs(Collapsible.Trigger, { className: `disclosure__trigger${triggerClassName ? ` ${triggerClassName}` : ""}`, "data-test": triggerDataTest, children: [_jsx("span", { className: "disclosure__label", children: title }), badge, _jsx(IconChevronDown, { className: "disclosure__chevron", size: 15, stroke: 2, "aria-hidden": "true" })] }), _jsx(Collapsible.Panel, { keepMounted: keepMounted, className: `disclosure__panel${panelClassName ? ` ${panelClassName}` : ""}`, children: children })] }));
13
+ }
@@ -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)) })] }) }) })] }));
@@ -36,7 +36,7 @@ export function SideValuesField({ label, sides, pairedControls, defaultExpanded
36
36
  }
37
37
  return (_jsx("div", { className: "side-values", "data-test": dataTest, "data-property": dataProperty, "data-empty": empty ? "true" : undefined, ...(hasPairedControls
38
38
  ? { "data-expanded": isExpanded ? "true" : "false" }
39
- : {}), children: empty ? (_jsxs("div", { className: "side-values__header", children: [_jsx("span", { className: "side-values__label", children: displayLabel }), emptyAction ?? (_jsx(IconButton, { variant: "quiet", size: "default", "data-test": "add-value", label: `Add ${labelText}`, title: `Add ${labelText}`, onClick: onAdd, children: _jsx(IconPlus, { size: 16, "aria-hidden": "true" }) }))] })) : hasPairedControls ? (_jsxs(_Fragment, { children: [showLabel ? (_jsx("div", { className: "side-values__header", children: _jsx("span", { className: "side-values__label", children: displayLabel }) })) : null, _jsxs("div", { className: "side-values__value-row", children: [isExpanded ? (_jsx(SideControls, { label: label, sides: sides })) : (_jsx("div", { className: "side-values__pairs", role: "group", "aria-label": `${labelText} Grouped Sides`, children: orderedPairedControls.map(({ axis, control, icon }) => (_jsxs(ControlSurface, { className: "side-values__side", "data-test": `pair-value-${axis}`, "data-axis": axis, "aria-label": `${labelText} ${axis === "horizontal" ? "Left And Right" : "Top And Bottom"}`, title: `${labelText} ${axis === "horizontal" ? "Left And Right" : "Top And Bottom"}`, children: [icon !== undefined ? icon : _jsx(AxisIndicator, { axis: axis }), _jsx("div", { className: "side-values__control", children: control })] }, axis))) })), _jsx(ToggleButton, { variant: "quiet", size: "default", "data-test": "individual-sides", label: isExpanded ? `Collapse ${labelText} Sides` : `Expand ${labelText} Sides`, title: isExpanded ? "Collapse To Grouped Sides" : "Expand To Individual Sides", pressed: isExpanded, onPressedChange: toggleExpanded, children: _jsx(IconBorderSides, { size: 16, "aria-hidden": "true" }) })] })] })) : (_jsxs(_Fragment, { children: [showLabel ? (_jsx("div", { className: "side-values__header", children: _jsx("span", { className: "side-values__label", children: displayLabel }) })) : null, _jsx(SideControls, { label: label, sides: sides })] })) }));
39
+ : {}), children: empty ? (_jsxs("div", { className: "side-values__header", children: [_jsx("span", { className: "side-values__label", children: displayLabel }), emptyAction ?? (_jsx(IconButton, { variant: "quiet", size: "default", "data-test": "add-value", label: `Add ${labelText}`, onClick: onAdd, children: _jsx(IconPlus, { size: 16, "aria-hidden": "true" }) }))] })) : hasPairedControls ? (_jsxs(_Fragment, { children: [showLabel ? (_jsx("div", { className: "side-values__header", children: _jsx("span", { className: "side-values__label", children: displayLabel }) })) : null, _jsxs("div", { className: "side-values__value-row", children: [isExpanded ? (_jsx(SideControls, { label: label, sides: sides })) : (_jsx("div", { className: "side-values__pairs", role: "group", "aria-label": `${labelText} Grouped Sides`, children: orderedPairedControls.map(({ axis, control, icon }) => (_jsxs(ControlSurface, { className: "side-values__side", "data-test": `pair-value-${axis}`, "data-axis": axis, "aria-label": `${labelText} ${axis === "horizontal" ? "Left And Right" : "Top And Bottom"}`, children: [icon !== undefined ? icon : _jsx(AxisIndicator, { axis: axis }), _jsx("div", { className: "side-values__control", children: control })] }, axis))) })), _jsx(ToggleButton, { variant: "quiet", size: "default", "data-test": "individual-sides", label: isExpanded ? `Collapse ${labelText} Sides` : `Expand ${labelText} Sides`, pressed: isExpanded, onPressedChange: toggleExpanded, children: _jsx(IconBorderSides, { size: 16, "aria-hidden": "true" }) })] })] })) : (_jsxs(_Fragment, { children: [showLabel ? (_jsx("div", { className: "side-values__header", children: _jsx("span", { className: "side-values__label", children: displayLabel }) })) : null, _jsx(SideControls, { label: label, sides: sides })] })) }));
40
40
  }
41
41
  export function SideControls({ label, sides, layout = "sides", }) {
42
42
  const displayOrder = layout === "corners" ? SIDE_NAMES : SIDE_DISPLAY_ORDER;
@@ -0,0 +1,26 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ export interface TooltipGroupProps {
3
+ children?: ReactNode;
4
+ delay?: number;
5
+ closeDelay?: number;
6
+ timeout?: number;
7
+ }
8
+ export declare function TooltipGroup({ children, delay, closeDelay, timeout, }: TooltipGroupProps): ReactElement;
9
+ export interface TooltipProps {
10
+ children: ReactElement;
11
+ content?: ReactNode;
12
+ shortcut?: ReactNode;
13
+ side?: "top" | "bottom" | "left" | "right";
14
+ align?: "start" | "center" | "end";
15
+ sideOffset?: number;
16
+ delay?: number;
17
+ closeDelay?: number;
18
+ disableFocus?: boolean;
19
+ disabled?: boolean;
20
+ stableTrigger?: boolean;
21
+ triggerClassName?: string;
22
+ positionerClassName?: string;
23
+ popupClassName?: string;
24
+ "data-test"?: string;
25
+ }
26
+ export declare function Tooltip({ children, content, shortcut, side, align, sideOffset, delay, closeDelay, disableFocus, disabled, stableTrigger, triggerClassName, positionerClassName, popupClassName, "data-test": dataTest, }: TooltipProps): ReactElement;
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
3
+ import { cx } from "./classNames.js";
4
+ import { portalContainer } from "./portalContainer.js";
5
+ export function TooltipGroup({ children, delay = 500, closeDelay = 0, timeout = 400, }) {
6
+ return (_jsx(BaseTooltip.Provider, { delay: delay, closeDelay: closeDelay, timeout: timeout, children: children }));
7
+ }
8
+ function isDisabledTrigger(element) {
9
+ // SAFETY: Inspector triggers are host elements with optional disabled props.
10
+ return Boolean(element.props.disabled);
11
+ }
12
+ function defaultTooltipContent(element) {
13
+ // SAFETY: Inspector triggers carry label or aria-label for tooltip text.
14
+ const props = element.props;
15
+ return props.label ?? props["aria-label"] ?? null;
16
+ }
17
+ function preventFocusOpening(event) {
18
+ if (!("preventBaseUIHandler" in event))
19
+ return;
20
+ // SAFETY: The `in` guard proves preventBaseUIHandler exists on this Base UI focus event.
21
+ const preventBaseUIHandler = event.preventBaseUIHandler;
22
+ if (typeof preventBaseUIHandler === "function")
23
+ preventBaseUIHandler();
24
+ }
25
+ export function Tooltip({ children, content, shortcut, side = "top", align = "center", sideOffset = 8, delay, closeDelay, disableFocus = false, disabled = false, stableTrigger = false, triggerClassName, positionerClassName, popupClassName, "data-test": dataTest, }) {
26
+ if (disabled)
27
+ return children;
28
+ const childDisabled = isDisabledTrigger(children);
29
+ const trigger = stableTrigger || childDisabled ? (_jsx("span", { className: cx("tooltip__trigger", triggerClassName), "data-tooltip-trigger-disabled": childDisabled ? "" : undefined, children: children })) : children;
30
+ const tooltipContent = content ?? defaultTooltipContent(children);
31
+ return (_jsxs(BaseTooltip.Root, { disableHoverablePopup: true, children: [_jsx(BaseTooltip.Trigger, { render: trigger, delay: delay, closeDelay: closeDelay, onFocus: disableFocus ? preventFocusOpening : undefined }), _jsx(BaseTooltip.Portal, { container: portalContainer(), children: _jsx(BaseTooltip.Positioner, { className: cx("tooltip__positioner", positionerClassName), side: side, align: align, sideOffset: sideOffset, children: _jsxs(BaseTooltip.Popup, { className: cx("tooltip__popup", popupClassName), "data-test": dataTest, children: [_jsx("div", { className: "tooltip__content", children: tooltipContent }), shortcut !== undefined ? _jsx("span", { className: "tooltip__shortcut", children: shortcut }) : null] }) }) })] }));
32
+ }
@@ -0,0 +1,2 @@
1
+ /** Joins truthy class names with spaces. */
2
+ export declare function cx(...classNames: ReadonlyArray<string | false | null | undefined>): string;
@@ -0,0 +1,4 @@
1
+ /** Joins truthy class names with spaces. */
2
+ export function cx(...classNames) {
3
+ return classNames.filter(Boolean).join(" ");
4
+ }
@@ -0,0 +1,23 @@
1
+ export type RendererCursor = "design" | "drag" | "comment";
2
+ /** Custom property the renderer sets on its root to drive the interaction cursor. */
3
+ export declare const INTERACTION_CURSOR_PROPERTY = "--nudge-ui-interaction-cursor";
4
+ /** Rendered size and hotspot of the drag cursor, shared with the pointer-lock stand-in. */
5
+ export declare const DRAG_CURSOR_SIZE: {
6
+ readonly width: 28.8;
7
+ readonly height: 24;
8
+ };
9
+ export declare const DRAG_CURSOR_HOTSPOT: {
10
+ readonly x: 14.4;
11
+ readonly y: 12;
12
+ };
13
+ export declare const DESIGN_SELECT_CURSOR_URL: string;
14
+ export declare const DRAG_CURSOR_URL: string;
15
+ export declare const SKETCH_CURSOR_URL: string;
16
+ export declare const DESIGN_SELECT_CURSOR: string;
17
+ /** Cursor SVGs are separate images, so resolve CSS tokens before encoding them. */
18
+ export declare function createCommentCursor(tokenSource?: Element | null): string;
19
+ export declare const COMMENT_CURSOR: string;
20
+ export declare const PAN_CURSOR = "grab";
21
+ export declare const DRAG_CURSOR: string;
22
+ export declare const SKETCH_CURSOR: string;
23
+ export declare function rendererCursorValue(cursor: RendererCursor, commentCursor?: string): string;
@@ -0,0 +1,122 @@
1
+ const foundationStyles = ":host {\n all: initial;\n --surface-panel: #F5F5F4;\n --surface-control: var(--surface-well);\n --surface-control-hover: var(--surface-well-2x);\n --surface-raised: #FAFAFA;\n --surface-raised-2x: #fff ;\n --surface-raised-hover: #F5F5F4;\n --surface-well: hsla(0, 0%, 0%, 0.05);\n --surface-well-2x: hsla(0, 0%, 0%, 0.10);\n\n --border-subtle: hsla(0, 0%, 0%, 0.1);\n --border-medium: hsla(0, 0%, 0%, 0.2);\n --border-strong: #d8d8d8;\n\n --text-primary: #242424;\n --text-secondary: #6f6f6f;\n --text-muted: #777777;\n --text-muted-subtle: #a1a1a1;\n\n --accent: #0096ff;\n --accent-surface: rgba(0, 176, 255, 0.15);\n --warning: #d97706;\n --warning-text: #9a5b00;\n --warning-surface: #fff6e5;\n --danger: #df4b4b;\n --danger-text: #bd3636;\n --danger-surface: rgba(223, 75, 75, 0.2);\n --success: #2e7d52;\n\n --space-0: 0;\n --space-4: 4px;\n --space-8: 8px;\n --space-12: 12px;\n --space-16: 16px;\n --space-20: 20px;\n --space-24: 24px;\n --space-32: 32px;\n --space-40: 40px;\n --space-48: 48px;\n\n /* Radius */\n --radius-0: 0;\n --radius-4: 4px;\n --radius-8: 8px;\n --radius-12: 12px;\n --radius-16: 16px;\n --radius-20: 20px;\n --radius-24: 24px;\n --radius-pill: 999px;\n\n --radius-control: var(--radius-8);\n --shadow-outline: 0 0 0 1px rgba(0, 0, 0, 0.05);\n --shadow-popup: 0 0 0 1px rgba(0, 0, 0, 0.05), 0 4px 16px rgba(0, 0, 0, 0.10);\n --shadow-control: inset 0 -2px 0 rgba(0, 0, 0, 0.03), 0 0 0 0.5px rgba(0, 0, 0, 0.25);\n --z-index: 2147483647;\n\n --font-family: \"Inter Variable\", Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n --font-size-base: 12px;\n --font-size-small: 10px;\n --font-weight-base: 400;\n --font-weight-label: 600;\n\n /* Control semantic sizes */\n --control-height-small: 24px;\n --control-height-large: 32px;\n --control-height-xlarge: 40px;\n --label-column: 104px;\n\n --icon-size-small: 16px;\n --icon-size-large: 20px;\n --icon-stroke-width: 1.5px;\n\n position: fixed;\n inset: 0;\n z-index: var(--z-index);\n pointer-events: none;\n font-family: var(--font-family);\n background: transparent;\n box-sizing: border-box;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\nbutton,\ninput,\nselect {\n font-family: inherit;\n}\n";
2
+ /** Custom property the renderer sets on its root to drive the interaction cursor. */
3
+ export const INTERACTION_CURSOR_PROPERTY = "--nudge-ui-interaction-cursor";
4
+ const DESIGN_SELECT_CURSOR_SVG = `<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
5
+ <g clip-path="url(#clip0_1681_15)">
6
+ <g filter="url(#filter0_d_1681_15)">
7
+ <path d="M17.3586 9.11501L12.9167 10.8333L12.6544 10.95C12.457 11.0271 12.2776 11.1443 12.1278 11.2942C11.9779 11.444 11.8607 11.6234 11.7836 11.8208L9.94861 16.5242C9.42111 17.8783 7.47944 17.8058 7.05444 16.4158L3.40277 4.48418C3.04277 3.30918 4.14277 2.21001 5.31777 2.56918L17.2503 6.22085C18.6403 6.64668 18.7128 8.58668 17.3586 9.11501Z" fill="black"/>
8
+ <path d="M17.3586 9.11501L12.9167 10.8333L12.6544 10.95C12.457 11.0271 12.2776 11.1443 12.1278 11.2942C11.9779 11.444 11.8607 11.6234 11.7836 11.8208L9.94861 16.5242C9.42111 17.8783 7.47944 17.8058 7.05444 16.4158L3.40277 4.48418C3.04277 3.30918 4.14277 2.21001 5.31777 2.56918L17.2503 6.22085C18.6403 6.64668 18.7128 8.58668 17.3586 9.11501Z" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
9
+ </g>
10
+ </g>
11
+ <defs>
12
+ <filter id="filter0_d_1681_15" x="0.332611" y="0.332662" width="21.002" height="21.0009" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
13
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
14
+ <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
15
+ <feOffset dy="0.833333"/>
16
+ <feGaussianBlur stdDeviation="1.25"/>
17
+ <feComposite in2="hardAlpha" operator="out"/>
18
+ <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
19
+ <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1681_15"/>
20
+ <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1681_15" result="shape"/>
21
+ </filter>
22
+ <clipPath id="clip0_1681_15">
23
+ <rect width="20" height="20" fill="white"/>
24
+ </clipPath>
25
+ </defs>
26
+ </svg>`;
27
+ /** Rendered size and hotspot of the drag cursor, shared with the pointer-lock stand-in. */
28
+ export const DRAG_CURSOR_SIZE = { width: 28.8, height: 24 };
29
+ export const DRAG_CURSOR_HOTSPOT = { x: 14.4, y: 12 };
30
+ const DRAG_CURSOR_SVG = `<svg width="${DRAG_CURSOR_SIZE.width}" height="${DRAG_CURSOR_SIZE.height}" viewBox="0 0 24 20" fill="none" xmlns="http://www.w3.org/2000/svg">
31
+ <g filter="url(#filter0_d_1681_26)">
32
+ <path d="M13.2767 13.6586V7.616C13.2767 7.17654 13.736 6.88812 14.1318 7.07897L20.3982 10.1003C20.8478 10.3171 20.8478 10.9575 20.3982 11.1743L14.1318 14.1956C13.736 14.3864 13.2767 14.098 13.2767 13.6586Z" fill="black"/>
33
+ <path d="M13.2767 13.6586V7.616C13.2767 7.17654 13.736 6.88812 14.1318 7.07897L20.3982 10.1003C20.8478 10.3171 20.8478 10.9575 20.3982 11.1743L14.1318 14.1956C13.736 14.3864 13.2767 14.098 13.2767 13.6586Z" stroke="white"/>
34
+ </g>
35
+ <g filter="url(#filter1_d_1681_26)">
36
+ <path d="M9.74729 13.6586V7.616C9.74729 7.17654 9.28803 6.88812 8.89218 7.07897L2.62582 10.1003C2.17614 10.3171 2.17614 10.9575 2.62582 11.1743L8.89218 14.1956C9.28803 14.3864 9.74729 14.098 9.74729 13.6586Z" fill="black"/>
37
+ <path d="M9.74729 13.6586V7.616C9.74729 7.17654 9.28803 6.88812 8.89218 7.07897L2.62582 10.1003C2.17614 10.3171 2.17614 10.9575 2.62582 11.1743L8.89218 14.1956C9.28803 14.3864 9.74729 14.098 9.74729 13.6586Z" stroke="white"/>
38
+ </g>
39
+ <defs>
40
+ <filter id="filter0_d_1681_26" x="10.9881" y="5.32606" width="12.0358" height="11.8148" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
41
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
42
+ <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
43
+ <feOffset dy="0.596185"/>
44
+ <feGaussianBlur stdDeviation="0.894277"/>
45
+ <feComposite in2="hardAlpha" operator="out"/>
46
+ <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
47
+ <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1681_26"/>
48
+ <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1681_26" result="shape"/>
49
+ </filter>
50
+ <filter id="filter1_d_1681_26" x="4.76837e-06" y="5.32606" width="12.0358" height="11.8148" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
51
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
52
+ <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
53
+ <feOffset dy="0.596185"/>
54
+ <feGaussianBlur stdDeviation="0.894277"/>
55
+ <feComposite in2="hardAlpha" operator="out"/>
56
+ <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
57
+ <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1681_26"/>
58
+ <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1681_26" result="shape"/>
59
+ </filter>
60
+ </defs>
61
+ </svg>`;
62
+ const SKETCH_CURSOR_SVG = `<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
63
+ <g clip-path="url(#clip0_1681_8)">
64
+ <g filter="url(#filter0_d_1681_8)">
65
+ <path d="M11.6667 5L17.5 10.8333L14.1667 14.1667" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
66
+ <path d="M5.62132 15.6544C5.33535 15.5359 5.07552 15.3622 4.85667 15.1433C4.63776 14.9245 4.46411 14.6647 4.34563 14.3787C4.22715 14.0927 4.16617 13.7862 4.16617 13.4767C4.16617 13.1671 4.22715 12.8606 4.34563 12.5746C4.46411 12.2887 4.63776 12.0288 4.85667 11.81L13.6783 2.98833C13.8331 2.8335 14.0169 2.71067 14.2191 2.62687C14.4214 2.54307 14.6382 2.49994 14.8571 2.49994C15.076 2.49994 15.2928 2.54307 15.495 2.62687C15.6973 2.71067 15.8811 2.8335 16.0358 2.98833L17.0117 3.96417C17.1665 4.11894 17.2893 4.3027 17.3731 4.50495C17.4569 4.70721 17.5001 4.92399 17.5001 5.14292C17.5001 5.36184 17.4569 5.57862 17.3731 5.78088C17.2893 5.98313 17.1665 6.16689 17.0117 6.32167L8.19 15.1433C7.97116 15.3622 7.71133 15.5359 7.42536 15.6544C7.13939 15.7729 6.83288 15.8338 6.52334 15.8338C6.2138 15.8338 5.90729 15.7729 5.62132 15.6544Z" fill="white" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
67
+ <path d="M3.33334 16.6667L4.80668 15.1934" stroke="black" stroke-linecap="round" stroke-linejoin="round"/>
68
+ </g>
69
+ </g>
70
+ <defs>
71
+ <filter id="filter0_d_1681_8" x="0.333344" y="0.333272" width="20.1667" height="20.1667" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
72
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
73
+ <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
74
+ <feOffset dy="0.833333"/>
75
+ <feGaussianBlur stdDeviation="1.25"/>
76
+ <feComposite in2="hardAlpha" operator="out"/>
77
+ <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
78
+ <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1681_8"/>
79
+ <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1681_8" result="shape"/>
80
+ </filter>
81
+ <clipPath id="clip0_1681_8">
82
+ <rect width="20" height="20" fill="white"/>
83
+ </clipPath>
84
+ </defs>
85
+ </svg>`;
86
+ function cursorDataUrl(svg) {
87
+ return `data:image/svg+xml,${encodeURIComponent(svg)}`;
88
+ }
89
+ export const DESIGN_SELECT_CURSOR_URL = cursorDataUrl(DESIGN_SELECT_CURSOR_SVG);
90
+ export const DRAG_CURSOR_URL = cursorDataUrl(DRAG_CURSOR_SVG);
91
+ export const SKETCH_CURSOR_URL = cursorDataUrl(SKETCH_CURSOR_SVG);
92
+ export const DESIGN_SELECT_CURSOR = `url("${DESIGN_SELECT_CURSOR_URL}") 3 4, default`;
93
+ /** Cursor SVGs are separate images, so resolve CSS tokens before encoding them. */
94
+ export function createCommentCursor(tokenSource) {
95
+ const styles = tokenSource?.ownerDocument.defaultView?.getComputedStyle(tokenSource);
96
+ const token = (name) => styles?.getPropertyValue(name).trim()
97
+ || foundationStyles.match(new RegExp(`${name}:\\s*([^;]+);`))[1].trim();
98
+ const svg = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
99
+ <g clip-path="url(#comment-clip)"><g filter="url(#comment-shadow)">
100
+ <path d="M4.3 16.1L3 20L7.7 19C11.659 20.922 16.608 19.942 19.274 16.707C21.94 13.472 21.5 8.983 18.245 6.206C14.99 3.43 9.926 3.225 6.4 5.726C2.874 8.228 1.976 12.663 4.3 16.1Z" fill="${token("--text-primary")}" stroke="${token("--surface-raised-2x")}" stroke-width="${token("--icon-stroke-width")}" stroke-linecap="round" stroke-linejoin="round"/>
101
+ </g></g>
102
+ <defs>
103
+ <filter id="comment-shadow" x="-0.0000152588" y="1.81214" width="24.0141" height="22.0212" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
104
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
105
+ <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
106
+ <feOffset dy="0.833333"/><feGaussianBlur stdDeviation="1.25"/>
107
+ <feComposite in2="hardAlpha" operator="out"/>
108
+ <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
109
+ <feBlend mode="normal" in2="BackgroundImageFix" result="dropShadow"/>
110
+ <feBlend mode="normal" in="SourceGraphic" in2="dropShadow" result="shape"/>
111
+ </filter>
112
+ <clipPath id="comment-clip"><rect width="24" height="24" fill="white"/></clipPath>
113
+ </defs></svg>`;
114
+ return `url("${cursorDataUrl(svg)}") 3 20, crosshair`;
115
+ }
116
+ export const COMMENT_CURSOR = createCommentCursor();
117
+ export const PAN_CURSOR = "grab";
118
+ export const DRAG_CURSOR = `url("${DRAG_CURSOR_URL}") ${DRAG_CURSOR_HOTSPOT.x} ${DRAG_CURSOR_HOTSPOT.y}, grab`;
119
+ export const SKETCH_CURSOR = `url("${SKETCH_CURSOR_URL}") 3 17, crosshair`;
120
+ export function rendererCursorValue(cursor, commentCursor = COMMENT_CURSOR) {
121
+ return cursor === "comment" ? commentCursor : cursor === "drag" ? PAN_CURSOR : DESIGN_SELECT_CURSOR;
122
+ }
@@ -0,0 +1,6 @@
1
+ export declare const DRAG_CURSOR_STYLES: string;
2
+ /** Shows the same cursor at a fixed viewport point while the native cursor is locked. */
3
+ export declare function showLockedDragCursor(doc: Document, point: {
4
+ x: number;
5
+ y: number;
6
+ }): () => void;
@@ -0,0 +1,13 @@
1
+ import { DRAG_CURSOR, DRAG_CURSOR_HOTSPOT, DRAG_CURSOR_SIZE, DRAG_CURSOR_URL } from "./customCursors.js";
2
+ export const DRAG_CURSOR_STYLES = `:host { --nudge-drag-cursor: ${DRAG_CURSOR}; }`;
3
+ /** Shows the same cursor at a fixed viewport point while the native cursor is locked. */
4
+ export function showLockedDragCursor(doc, point) {
5
+ const cursor = doc.createElement("img");
6
+ cursor.src = DRAG_CURSOR_URL;
7
+ cursor.alt = "";
8
+ cursor.setAttribute("aria-hidden", "true");
9
+ cursor.dataset.test = "locked-drag-cursor";
10
+ cursor.style.cssText = `all: initial; position: fixed; left: ${point.x - DRAG_CURSOR_HOTSPOT.x}px; top: ${point.y - DRAG_CURSOR_HOTSPOT.y}px; width: ${DRAG_CURSOR_SIZE.width}px; height: ${DRAG_CURSOR_SIZE.height}px; pointer-events: none; z-index: 2147483647; user-select: none;`;
11
+ doc.documentElement.append(cursor);
12
+ return () => cursor.remove();
13
+ }
@@ -0,0 +1,2 @@
1
+ /** Portal target inside the inspector's shadow root, so popups inherit its styles. */
2
+ export declare function portalContainer(): HTMLElement | ShadowRoot | null;
@@ -0,0 +1,6 @@
1
+ /** Portal target inside the inspector's shadow root, so popups inherit its styles. */
2
+ export function portalContainer() {
3
+ if (typeof document === "undefined")
4
+ return null;
5
+ return document.getElementById("nudge-ui-root")?.shadowRoot ?? document.body;
6
+ }