nudge-ui 0.2.0 → 0.2.2

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 (231) hide show
  1. package/bin/nudge-ui.mjs +3 -1
  2. package/dist/cli/agentCommand.d.ts +8 -0
  3. package/dist/cli/agentCommand.js +59 -0
  4. package/dist/client.mjs +878 -11
  5. package/dist/hosts/astro/astroRuntimeConfig.js +1 -1
  6. package/dist/hosts/astro/clientTransport.js +63 -11
  7. package/dist/hosts/astro/integration.d.ts +2 -2
  8. package/dist/hosts/astro/integration.js +4 -3
  9. package/dist/hosts/environment.d.ts +15 -0
  10. package/dist/hosts/environment.js +16 -0
  11. package/dist/hosts/next/sidecar.d.ts +4 -0
  12. package/dist/hosts/next/sidecar.js +56 -7
  13. package/dist/hosts/next/wrapper.d.ts +2 -0
  14. package/dist/hosts/next/wrapper.js +32 -3
  15. package/dist/hosts/projectBridge.d.ts +21 -0
  16. package/dist/hosts/projectBridge.js +98 -0
  17. package/dist/hosts/static/cli.d.ts +1 -1
  18. package/dist/hosts/static/cli.js +6 -1
  19. package/dist/hosts/static/manifest.d.ts +1 -1
  20. package/dist/hosts/static/manifest.js +3 -1
  21. package/dist/hosts/static/server.js +45 -3
  22. package/dist/hosts/vite/vite.d.ts +6 -1
  23. package/dist/hosts/vite/vite.js +82 -15
  24. package/dist/inspector/agent/McpConnectionDialog.d.ts +5 -4
  25. package/dist/inspector/agent/McpConnectionDialog.js +20 -37
  26. package/dist/inspector/agent/client.d.ts +16 -3
  27. package/dist/inspector/agent/client.js +114 -11
  28. package/dist/inspector/agent/connectionStatus.d.ts +3 -3
  29. package/dist/inspector/agent/connectionStatus.js +11 -4
  30. package/dist/inspector/agent/httpTransport.d.ts +8 -0
  31. package/dist/inspector/agent/httpTransport.js +78 -18
  32. package/dist/inspector/agent/protocol.d.ts +11 -3
  33. package/dist/inspector/agent/protocol.js +1 -1
  34. package/dist/inspector/agent/verification.d.ts +1 -1
  35. package/dist/inspector/agent/verification.js +69 -12
  36. package/dist/inspector/canvas/CanvasCard.d.ts +5 -3
  37. package/dist/inspector/canvas/CanvasCard.js +181 -91
  38. package/dist/inspector/canvas/CanvasElementOverlay.js +288 -52
  39. package/dist/inspector/canvas/CanvasToolbar.d.ts +12 -0
  40. package/dist/inspector/canvas/CanvasToolbar.js +24 -0
  41. package/dist/inspector/canvas/CanvasWorkspace.d.ts +4 -1
  42. package/dist/inspector/canvas/CanvasWorkspace.js +410 -72
  43. package/dist/inspector/canvas/activeCanvasDocument.d.ts +5 -0
  44. package/dist/inspector/canvas/activeCanvasDocument.js +23 -0
  45. package/dist/inspector/canvas/canvasResize.d.ts +30 -0
  46. package/dist/inspector/canvas/canvasResize.js +52 -0
  47. package/dist/inspector/canvas/canvasStore.d.ts +30 -6
  48. package/dist/inspector/canvas/canvasStore.js +128 -61
  49. package/dist/inspector/canvas/frameProtocol.d.ts +82 -5
  50. package/dist/inspector/canvas/frameProtocol.js +63 -2
  51. package/dist/inspector/canvas/keyboardShortcuts.d.ts +4 -0
  52. package/dist/inspector/canvas/keyboardShortcuts.js +16 -0
  53. package/dist/inspector/canvas/linkEligibility.d.ts +0 -5
  54. package/dist/inspector/canvas/linkEligibility.js +0 -29
  55. package/dist/inspector/canvas/projection.d.ts +7 -0
  56. package/dist/inspector/canvas/projection.js +118 -25
  57. package/dist/inspector/canvas/rendererBootstrap.js +42 -29
  58. package/dist/inspector/canvas/rendererElementSelector.d.ts +1 -1
  59. package/dist/inspector/canvas/rendererElementSelector.js +385 -58
  60. package/dist/inspector/canvas/rendererMessageRouter.d.ts +11 -0
  61. package/dist/inspector/canvas/rendererMessageRouter.js +43 -0
  62. package/dist/inspector/canvas/rendererSelectionProxy.js +6 -2
  63. package/dist/inspector/canvas/sessionStore.d.ts +1 -0
  64. package/dist/inspector/canvas/sessionStore.js +12 -4
  65. package/dist/inspector/canvas/staleChangeDetector.js +16 -14
  66. package/dist/inspector/changes/changesLog.js +31 -1
  67. package/dist/inspector/changes/managedStyleProjection.d.ts +1 -1
  68. package/dist/inspector/changes/managedStyleProjection.js +3 -3
  69. package/dist/inspector/changes/structuralTypes.d.ts +4 -0
  70. package/dist/inspector/changes/workspaceChanges.d.ts +4 -0
  71. package/dist/inspector/changes/workspaceChanges.js +29 -3
  72. package/dist/inspector/clientManifest.d.ts +7 -0
  73. package/dist/inspector/clientManifest.js +12 -0
  74. package/dist/inspector/componentSemantics/adapterRegistry.js +4 -3
  75. package/dist/inspector/componentSemantics/runtimeBridge.d.ts +2 -2
  76. package/dist/inspector/componentSemantics/runtimeBridge.js +16 -3
  77. package/dist/inspector/index.d.ts +2 -0
  78. package/dist/inspector/index.js +80 -32
  79. package/dist/inspector/inline-text/inlineTextDiagnostics.d.ts +10 -0
  80. package/dist/inspector/inline-text/inlineTextDiagnostics.js +65 -0
  81. package/dist/inspector/inline-text/inlineTextEditor.d.ts +3 -5
  82. package/dist/inspector/inline-text/inlineTextEditor.js +74 -206
  83. package/dist/inspector/inline-text/inlineTextFeedback.d.ts +5 -0
  84. package/dist/inspector/inline-text/inlineTextFeedback.js +27 -0
  85. package/dist/inspector/inline-text/inlineTextLifecycle.js +2 -0
  86. package/dist/inspector/inline-text/textEditChange.d.ts +14 -0
  87. package/dist/inspector/inline-text/textEditChange.js +165 -0
  88. package/dist/inspector/inspection/selectionProperty.d.ts +1 -0
  89. package/dist/inspector/inspection/selectionProperty.js +1 -0
  90. package/dist/inspector/overlay/DomNavigator.d.ts +10 -0
  91. package/dist/inspector/overlay/DomNavigator.js +40 -0
  92. package/dist/inspector/overlay/InspectorOverlay.js +6 -2
  93. package/dist/inspector/overlay/clickPolicy.d.ts +18 -2
  94. package/dist/inspector/overlay/clickPolicy.js +34 -3
  95. package/dist/inspector/overlay/elementSelector.d.ts +1 -1
  96. package/dist/inspector/overlay/elementSelector.js +18 -7
  97. package/dist/inspector/overlay/selectedGeometry.js +21 -2
  98. package/dist/inspector/overlay/spacingGestures.d.ts +45 -0
  99. package/dist/inspector/overlay/spacingGestures.js +351 -0
  100. package/dist/inspector/overlay/structuralGestures.d.ts +2 -2
  101. package/dist/inspector/overlay/structuralGestures.js +12 -10
  102. package/dist/inspector/projection/managedStylesheet.js +4 -1
  103. package/dist/inspector/projection/renderedInstance.d.ts +2 -0
  104. package/dist/inspector/projection/renderedInstance.js +5 -1
  105. package/dist/inspector/projection/structuralProjection.d.ts +2 -0
  106. package/dist/inspector/projection/structuralProjection.js +85 -1
  107. package/dist/inspector/projection/structuralProjectionBoundary.js +17 -1
  108. package/dist/inspector/projection/textProjection.d.ts +2 -0
  109. package/dist/inspector/projection/textProjection.js +10 -4
  110. package/dist/inspector/prompt/clipboardHandoff.d.ts +1 -1
  111. package/dist/inspector/prompt/clipboardHandoff.js +3 -3
  112. package/dist/inspector/prompt/generatePrompt.d.ts +2 -1
  113. package/dist/inspector/prompt/generatePrompt.js +19 -2
  114. package/dist/inspector/runtime/editorShell.d.ts +2 -0
  115. package/dist/inspector/runtime/editorShell.js +4 -0
  116. package/dist/inspector/runtime/runtimeConfig.d.ts +5 -1
  117. package/dist/inspector/runtime/runtimeConfig.js +4 -0
  118. package/dist/inspector/selection/hierarchy.d.ts +6 -0
  119. package/dist/inspector/selection/hierarchy.js +8 -0
  120. package/dist/inspector/selection/selectionStore.js +2 -0
  121. package/dist/inspector/settings/SettingsDialog.d.ts +1 -1
  122. package/dist/inspector/settings/SettingsDialog.js +12 -2
  123. package/dist/inspector/shell/AppShell.js +5 -1
  124. package/dist/inspector/shell/ChangesLog.js +26 -22
  125. package/dist/inspector/shell/CopyPromptButton.js +102 -19
  126. package/dist/inspector/shell/EmptyState.js +1 -1
  127. package/dist/inspector/shell/InspectorShell.d.ts +0 -1
  128. package/dist/inspector/shell/InspectorShell.js +38 -42
  129. package/dist/inspector/shell/PeekOriginalButton.d.ts +7 -0
  130. package/dist/inspector/shell/PeekOriginalButton.js +57 -0
  131. package/dist/inspector/shell/PeekOriginalIcon.d.ts +7 -0
  132. package/dist/inspector/shell/PeekOriginalIcon.js +9 -0
  133. package/dist/inspector/shell/originalPreview.d.ts +9 -0
  134. package/dist/inspector/shell/originalPreview.js +61 -0
  135. package/dist/inspector/shell/shortcuts.d.ts +3 -0
  136. package/dist/inspector/shell/shortcuts.js +15 -0
  137. package/dist/inspector/sketch/SketchChanges.d.ts +2 -0
  138. package/dist/inspector/sketch/SketchChanges.js +72 -0
  139. package/dist/inspector/sketch/SketchEditor.d.ts +21 -0
  140. package/dist/inspector/sketch/SketchEditor.js +402 -0
  141. package/dist/inspector/sketch/SketchEntryButton.d.ts +4 -0
  142. package/dist/inspector/sketch/SketchEntryButton.js +11 -0
  143. package/dist/inspector/sketch/SketchFrameOverlay.d.ts +11 -0
  144. package/dist/inspector/sketch/SketchFrameOverlay.js +119 -0
  145. package/dist/inspector/sketch/SketchLayersPanel.d.ts +2 -0
  146. package/dist/inspector/sketch/SketchLayersPanel.js +63 -0
  147. package/dist/inspector/sketch/SketchOverlay.d.ts +19 -0
  148. package/dist/inspector/sketch/SketchOverlay.js +420 -0
  149. package/dist/inspector/sketch/SketchPromptPanel.d.ts +15 -0
  150. package/dist/inspector/sketch/SketchPromptPanel.js +18 -0
  151. package/dist/inspector/sketch/SketchWorkspace.d.ts +13 -0
  152. package/dist/inspector/sketch/SketchWorkspace.js +152 -0
  153. package/dist/inspector/sketch/capture.d.ts +55 -0
  154. package/dist/inspector/sketch/capture.js +350 -0
  155. package/dist/inspector/sketch/freehand.d.ts +13 -0
  156. package/dist/inspector/sketch/freehand.js +64 -0
  157. package/dist/inspector/sketch/geometry.d.ts +17 -0
  158. package/dist/inspector/sketch/geometry.js +98 -0
  159. package/dist/inspector/sketch/handoff.d.ts +21 -0
  160. package/dist/inspector/sketch/handoff.js +72 -0
  161. package/dist/inspector/sketch/interaction.d.ts +21 -0
  162. package/dist/inspector/sketch/interaction.js +98 -0
  163. package/dist/inspector/sketch/model.d.ts +104 -0
  164. package/dist/inspector/sketch/model.js +282 -0
  165. package/dist/inspector/sketch/persistence.d.ts +21 -0
  166. package/dist/inspector/sketch/persistence.js +205 -0
  167. package/dist/inspector/sketch/raster.d.ts +22 -0
  168. package/dist/inspector/sketch/raster.js +203 -0
  169. package/dist/inspector/sketch/sketchNote.d.ts +10 -0
  170. package/dist/inspector/sketch/sketchNote.js +30 -0
  171. package/dist/inspector/sketch/store.d.ts +47 -0
  172. package/dist/inspector/sketch/store.js +434 -0
  173. package/dist/inspector/styleEditors/BorderEditor.js +15 -19
  174. package/dist/inspector/styleEditors/BorderRadiusEditor.js +6 -6
  175. package/dist/inspector/styleEditors/BoxShadowEditor.js +12 -1
  176. package/dist/inspector/styleEditors/ColorPicker.js +11 -36
  177. package/dist/inspector/styleEditors/GapField.d.ts +3 -2
  178. package/dist/inspector/styleEditors/GapField.js +2 -2
  179. package/dist/inspector/styleEditors/GridSection.js +1 -1
  180. package/dist/inspector/styleEditors/LayoutSection.js +11 -8
  181. package/dist/inspector/styleEditors/SpacingBox.js +31 -33
  182. package/dist/inspector/styleEditors/layoutPreviewState.d.ts +5 -0
  183. package/dist/inspector/styleEditors/layoutPreviewState.js +19 -0
  184. package/dist/inspector/styleEditors/layoutValue.js +3 -0
  185. package/dist/inspector/styleEditors/nudgeValue.d.ts +11 -0
  186. package/dist/inspector/styleEditors/nudgeValue.js +93 -5
  187. package/dist/inspector/styleEditors/stylePresence.d.ts +7 -0
  188. package/dist/inspector/styleEditors/stylePresence.js +22 -0
  189. package/dist/inspector/styleEditors/textRelevance.d.ts +3 -0
  190. package/dist/inspector/styleEditors/textRelevance.js +35 -0
  191. package/dist/inspector/styleEditors/useFieldVisibility.d.ts +6 -0
  192. package/dist/inspector/styleEditors/useFieldVisibility.js +26 -0
  193. package/dist/inspector/tokens/TokenField.js +130 -7
  194. package/dist/inspector/tokens/TokensPanel.js +2 -1
  195. package/dist/inspector/tokens/dragPointerLock.d.ts +8 -0
  196. package/dist/inspector/tokens/dragPointerLock.js +70 -0
  197. package/dist/inspector/tokens/editActions.d.ts +2 -0
  198. package/dist/inspector/tokens/editActions.js +2 -2
  199. package/dist/inspector/tokens/resolution/cssomCollector.d.ts +1 -1
  200. package/dist/inspector/tokens/resolution/cssomCollector.js +9 -5
  201. package/dist/inspector/tokens/resolution/ruleMatching.d.ts +40 -0
  202. package/dist/inspector/tokens/resolution/ruleMatching.js +423 -0
  203. package/dist/inspector/tokens/resolution/selectorSemantics.d.ts +19 -3
  204. package/dist/inspector/tokens/resolution/selectorSemantics.js +378 -4
  205. package/dist/inspector/tokens/resolution.d.ts +3 -26
  206. package/dist/inspector/tokens/resolution.js +44 -735
  207. package/dist/inspector/tokens/tokenAvailability.d.ts +18 -0
  208. package/dist/inspector/tokens/tokenAvailability.js +204 -0
  209. package/dist/inspector/ui/Button.d.ts +1 -1
  210. package/dist/inspector/ui/Disclosure.d.ts +22 -0
  211. package/dist/inspector/ui/Disclosure.js +13 -0
  212. package/dist/inspector/ui/SideValuesField.js +2 -2
  213. package/dist/inspector/ui/StatusCallout.d.ts +4 -1
  214. package/dist/inspector/ui/StatusCallout.js +2 -2
  215. package/dist/inspector/ui/dragCursor.d.ts +8 -0
  216. package/dist/inspector/ui/dragCursor.js +21 -0
  217. package/dist/inspector/ui/styles.js +21 -17
  218. package/dist/internal/agent-protocol.d.ts +65 -1
  219. package/dist/internal/agent-protocol.js +183 -3
  220. package/dist/nudge-ui.mjs +276 -58
  221. package/dist/transport/editor.d.ts +47 -0
  222. package/dist/transport/editor.js +163 -0
  223. package/dist/transport/index.d.ts +1 -0
  224. package/dist/transport/index.js +1 -0
  225. package/dist/transport/routes.d.ts +10 -0
  226. package/dist/transport/routes.js +10 -0
  227. package/package.json +3 -1
  228. package/dist/inspector/shell/DomNavigation.d.ts +0 -8
  229. package/dist/inspector/shell/DomNavigation.js +0 -30
  230. package/dist/inspector/shell/panelLayout.d.ts +0 -2
  231. package/dist/inspector/shell/panelLayout.js +0 -29
@@ -0,0 +1,47 @@
1
+ /** Returns the editor URL for one same-origin application location. */
2
+ export declare function createNudgeUiEditorUrl(applicationHref: string): string;
3
+ /** Resolves the application URL carried by an editor URL. */
4
+ export declare function readNudgeUiEditorTarget(editorHref: string): string | null;
5
+ type RequestHeaderValue = string | readonly string[] | undefined;
6
+ /** Returns whether a host request should receive the pure editor document. */
7
+ export declare function isNudgeUiEditorDocumentRequest(requestHref: string, method: string | undefined, headers: Record<string, RequestHeaderValue> | undefined): boolean;
8
+ /** Adds the persistent marker that bypasses editor entry for a plain app view. */
9
+ export declare function createNudgeUiDirectUrl(applicationHref: string): string;
10
+ /** Reads the public `nudge-ui=off` / `nudge-ui=on` switch from an application URL. */
11
+ export declare function readNudgeUiQuerySwitch(href: string): "off" | "on" | null;
12
+ /** Returns whether this application location explicitly bypasses editor entry. */
13
+ export declare function isNudgeUiDirectUrl(href: string): boolean;
14
+ /** Remembers that this browser tab was explicitly opened outside the editor. */
15
+ export declare function rememberNudgeUiDirectTabIntent(): void;
16
+ /** Remembers an explicit URL switch so later navigations in this tab keep it. */
17
+ export declare function rememberNudgeUiTabSwitch(value: "off" | "on"): void;
18
+ /** Returns whether this browser tab should remain outside the editor. */
19
+ export declare function hasNudgeUiDirectTabIntent(): boolean;
20
+ /** Returns whether this browser tab explicitly asked for the editor with `nudge-ui=on`. */
21
+ export declare function hasNudgeUiForcedTabIntent(): boolean;
22
+ export type NudgeUiClientEntry = {
23
+ readonly kind: "bootstrap";
24
+ } | {
25
+ readonly kind: "direct";
26
+ } | {
27
+ readonly kind: "redirect";
28
+ readonly href: string;
29
+ }
30
+ /** An automated browser that enters the editor only when the host opts in. */
31
+ | {
32
+ readonly kind: "automated";
33
+ readonly href: string;
34
+ };
35
+ export interface NudgeUiClientEntryContext {
36
+ readonly editorDocument: boolean;
37
+ readonly canvasRenderer: boolean;
38
+ readonly directTab?: boolean;
39
+ readonly forcedTab?: boolean;
40
+ /** `navigator.webdriver`: Playwright, Puppeteer, Selenium, and headless Chrome. */
41
+ readonly automated?: boolean;
42
+ }
43
+ /** Chooses the browser-client role before any runtime manifest is fetched. */
44
+ export declare function resolveNudgeUiClientEntry(href: string, context: NudgeUiClientEntryContext): NudgeUiClientEntry;
45
+ /** Renders the host-neutral editor document served by every development Adapter. */
46
+ export declare function createNudgeUiEditorDocument(): string;
47
+ export {};
@@ -0,0 +1,163 @@
1
+ import { NUDGE_UI_CLIENT_PATH, NUDGE_UI_DIRECT_QUERY_PARAM, NUDGE_UI_EDITOR_QUERY_PARAM, NUDGE_UI_EDITOR_QUERY_VALUE, NUDGE_UI_EDITOR_PATH, NUDGE_UI_MANIFEST_PATH, NUDGE_UI_MOUNT_ID, NUDGE_UI_OFF_QUERY_VALUE, NUDGE_UI_ON_QUERY_VALUE, isReservedNudgeUiRoute, } from "./routes.js";
2
+ const TARGET_QUERY_PARAM = "url";
3
+ const DIRECT_TAB_SESSION_KEY = "nudge-ui:direct-tab";
4
+ const FORCED_TAB_SESSION_KEY = "nudge-ui:forced-tab";
5
+ /** Returns the editor URL for one same-origin application location. */
6
+ export function createNudgeUiEditorUrl(applicationHref) {
7
+ const applicationUrl = new URL(applicationHref);
8
+ assertApplicationUrl(applicationUrl);
9
+ const retainedSegments = applicationUrl.search.slice(1).split("&").filter((segment) => {
10
+ const entry = new URLSearchParams(segment);
11
+ const value = entry.get(NUDGE_UI_EDITOR_QUERY_PARAM);
12
+ return entry.get(NUDGE_UI_DIRECT_QUERY_PARAM) !== "1"
13
+ && value !== NUDGE_UI_OFF_QUERY_VALUE
14
+ && value !== NUDGE_UI_ON_QUERY_VALUE;
15
+ });
16
+ applicationUrl.search = retainedSegments.join("&");
17
+ if (applicationUrl.searchParams.getAll(NUDGE_UI_EDITOR_QUERY_PARAM).includes(NUDGE_UI_EDITOR_QUERY_VALUE)) {
18
+ return applicationUrl.href;
19
+ }
20
+ const hash = applicationUrl.hash;
21
+ applicationUrl.hash = "";
22
+ applicationUrl.search = `${applicationUrl.search}${applicationUrl.search ? "&" : "?"}${NUDGE_UI_EDITOR_QUERY_PARAM}=${NUDGE_UI_EDITOR_QUERY_VALUE}`;
23
+ applicationUrl.hash = hash;
24
+ return applicationUrl.href;
25
+ }
26
+ /** Resolves the application URL carried by an editor URL. */
27
+ export function readNudgeUiEditorTarget(editorHref) {
28
+ const editorUrl = new URL(editorHref);
29
+ if (editorUrl.pathname !== NUDGE_UI_EDITOR_PATH) {
30
+ if (!editorUrl.searchParams.getAll(NUDGE_UI_EDITOR_QUERY_PARAM).includes(NUDGE_UI_EDITOR_QUERY_VALUE)) {
31
+ return null;
32
+ }
33
+ const retainedSegments = editorUrl.search.slice(1).split("&").filter((segment) => {
34
+ const entry = new URLSearchParams(segment);
35
+ return entry.get(NUDGE_UI_EDITOR_QUERY_PARAM) !== NUDGE_UI_EDITOR_QUERY_VALUE;
36
+ });
37
+ editorUrl.search = retainedSegments.join("&");
38
+ return isApplicationUrl(editorUrl) ? editorUrl.href : null;
39
+ }
40
+ const target = editorUrl.searchParams.get(TARGET_QUERY_PARAM);
41
+ if (!target)
42
+ return null;
43
+ try {
44
+ const targetUrl = new URL(target, editorUrl.origin);
45
+ return targetUrl.origin === editorUrl.origin && isApplicationUrl(targetUrl)
46
+ ? targetUrl.href
47
+ : null;
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ /** Returns whether a host request should receive the pure editor document. */
54
+ export function isNudgeUiEditorDocumentRequest(requestHref, method, headers) {
55
+ const normalizedMethod = (method ?? "GET").toUpperCase();
56
+ if (normalizedMethod !== "GET" && normalizedMethod !== "HEAD")
57
+ return false;
58
+ const url = new URL(requestHref, "http://nudge-ui.local");
59
+ if (url.pathname === NUDGE_UI_EDITOR_PATH)
60
+ return true;
61
+ if (!isApplicationUrl(url))
62
+ return false;
63
+ if (!url.searchParams.getAll(NUDGE_UI_EDITOR_QUERY_PARAM).includes(NUDGE_UI_EDITOR_QUERY_VALUE))
64
+ return false;
65
+ const header = (name) => {
66
+ const value = headers?.[name] ?? headers?.[name.toLowerCase()];
67
+ return typeof value === "string" ? value : value?.join(",") ?? "";
68
+ };
69
+ return header("sec-fetch-dest").toLowerCase() === "document"
70
+ || header("accept").toLowerCase().includes("text/html");
71
+ }
72
+ /** Adds the persistent marker that bypasses editor entry for a plain app view. */
73
+ export function createNudgeUiDirectUrl(applicationHref) {
74
+ const url = new URL(applicationHref);
75
+ assertApplicationUrl(url);
76
+ url.searchParams.set(NUDGE_UI_DIRECT_QUERY_PARAM, "1");
77
+ return url.href;
78
+ }
79
+ /** Reads the public `nudge-ui=off` / `nudge-ui=on` switch from an application URL. */
80
+ export function readNudgeUiQuerySwitch(href) {
81
+ const url = new URL(href);
82
+ const values = url.searchParams.getAll(NUDGE_UI_EDITOR_QUERY_PARAM);
83
+ if (values.includes(NUDGE_UI_OFF_QUERY_VALUE) || url.searchParams.get(NUDGE_UI_DIRECT_QUERY_PARAM) === "1") {
84
+ return "off";
85
+ }
86
+ return values.includes(NUDGE_UI_ON_QUERY_VALUE) ? "on" : null;
87
+ }
88
+ /** Returns whether this application location explicitly bypasses editor entry. */
89
+ export function isNudgeUiDirectUrl(href) {
90
+ return readNudgeUiQuerySwitch(href) === "off";
91
+ }
92
+ /** Remembers that this browser tab was explicitly opened outside the editor. */
93
+ export function rememberNudgeUiDirectTabIntent() {
94
+ rememberNudgeUiTabSwitch("off");
95
+ }
96
+ /** Remembers an explicit URL switch so later navigations in this tab keep it. */
97
+ export function rememberNudgeUiTabSwitch(value) {
98
+ try {
99
+ sessionStorage.setItem(value === "off" ? DIRECT_TAB_SESSION_KEY : FORCED_TAB_SESSION_KEY, "1");
100
+ sessionStorage.removeItem(value === "off" ? FORCED_TAB_SESSION_KEY : DIRECT_TAB_SESSION_KEY);
101
+ }
102
+ catch {
103
+ // Storage denial must not prevent the current page from honoring the switch.
104
+ }
105
+ }
106
+ /** Returns whether this browser tab should remain outside the editor. */
107
+ export function hasNudgeUiDirectTabIntent() {
108
+ return readTabFlag(DIRECT_TAB_SESSION_KEY);
109
+ }
110
+ /** Returns whether this browser tab explicitly asked for the editor with `nudge-ui=on`. */
111
+ export function hasNudgeUiForcedTabIntent() {
112
+ return readTabFlag(FORCED_TAB_SESSION_KEY);
113
+ }
114
+ function readTabFlag(key) {
115
+ try {
116
+ return sessionStorage.getItem(key) === "1";
117
+ }
118
+ catch {
119
+ return false;
120
+ }
121
+ }
122
+ /** Chooses the browser-client role before any runtime manifest is fetched. */
123
+ export function resolveNudgeUiClientEntry(href, context) {
124
+ if (context.editorDocument || context.canvasRenderer)
125
+ return { kind: "bootstrap" };
126
+ const urlSwitch = readNudgeUiQuerySwitch(href);
127
+ if (urlSwitch === "off")
128
+ return { kind: "direct" };
129
+ const forced = urlSwitch === "on" || context.forcedTab === true;
130
+ if (!forced && context.directTab === true)
131
+ return { kind: "direct" };
132
+ const editorHref = createNudgeUiEditorUrl(href);
133
+ if (context.automated === true && !forced)
134
+ return { kind: "automated", href: editorHref };
135
+ return { kind: "redirect", href: editorHref };
136
+ }
137
+ function isApplicationUrl(url) {
138
+ return (url.protocol === "http:" || url.protocol === "https:")
139
+ && url.username === ""
140
+ && url.password === ""
141
+ && !isReservedNudgeUiRoute(url.pathname);
142
+ }
143
+ function assertApplicationUrl(url) {
144
+ if (!isApplicationUrl(url)) {
145
+ throw new TypeError("Nudge UI application URLs must be HTTP(S) URLs outside its reserved route namespace.");
146
+ }
147
+ }
148
+ /** Renders the host-neutral editor document served by every development Adapter. */
149
+ export function createNudgeUiEditorDocument() {
150
+ return `<!doctype html>
151
+ <html lang="en" data-nudge-ui-editor>
152
+ <head>
153
+ <meta charset="utf-8">
154
+ <meta name="viewport" content="width=device-width, initial-scale=1">
155
+ <title>Nudge UI</title>
156
+ <style>html,body,#${NUDGE_UI_MOUNT_ID}{width:100%;height:100%;margin:0}body{overflow:hidden}</style>
157
+ </head>
158
+ <body>
159
+ <div id="${NUDGE_UI_MOUNT_ID}"></div>
160
+ <script type="module" src="${NUDGE_UI_CLIENT_PATH}" data-nudge-ui-client data-nudge-ui-manifest="${NUDGE_UI_MANIFEST_PATH}"></script>
161
+ </body>
162
+ </html>`;
163
+ }
@@ -4,5 +4,6 @@
4
4
  * Anything needing Node belongs in `project/`.
5
5
  */
6
6
  export * from "./routes.js";
7
+ export * from "./editor.js";
7
8
  /** Envelope version understood by the browser client. */
8
9
  export declare const NUDGE_UI_MANIFEST_VERSION = 1;
@@ -4,5 +4,6 @@
4
4
  * Anything needing Node belongs in `project/`.
5
5
  */
6
6
  export * from "./routes.js";
7
+ export * from "./editor.js";
7
8
  /** Envelope version understood by the browser client. */
8
9
  export const NUDGE_UI_MANIFEST_VERSION = 1;
@@ -7,7 +7,17 @@
7
7
  export declare const NUDGE_UI_ROUTE_PREFIX = "/__nudge_ui__/";
8
8
  export declare const NUDGE_UI_MANIFEST_PATH = "/__nudge_ui__/manifest";
9
9
  export declare const NUDGE_UI_CLIENT_PATH = "/__nudge_ui__/client.mjs";
10
+ /** Pure controller document that hosts the editor chrome. */
11
+ export declare const NUDGE_UI_EDITOR_PATH = "/__nudge_ui__/editor";
10
12
  /** Server-sent events announcing settled project changes. */
11
13
  export declare const NUDGE_UI_RELOAD_PATH = "/__nudge_ui__/reload";
12
14
  export declare const NUDGE_UI_MOUNT_ID = "nudge-ui-root";
15
+ /** Query marker that presents an application route through the editor shell. */
16
+ export declare const NUDGE_UI_EDITOR_QUERY_PARAM = "nudge-ui";
17
+ export declare const NUDGE_UI_EDITOR_QUERY_VALUE = "editor";
18
+ /** Public `nudge-ui` values that turn the inspector off or on for one browser tab. */
19
+ export declare const NUDGE_UI_OFF_QUERY_VALUE = "off";
20
+ export declare const NUDGE_UI_ON_QUERY_VALUE = "on";
21
+ /** Internal alias of `nudge-ui=off` kept for existing direct-view links. */
22
+ export declare const NUDGE_UI_DIRECT_QUERY_PARAM = "__nudge_ui_direct";
13
23
  export declare function isReservedNudgeUiRoute(pathname: string): boolean;
@@ -7,9 +7,19 @@
7
7
  export const NUDGE_UI_ROUTE_PREFIX = "/__nudge_ui__/";
8
8
  export const NUDGE_UI_MANIFEST_PATH = `${NUDGE_UI_ROUTE_PREFIX}manifest`;
9
9
  export const NUDGE_UI_CLIENT_PATH = `${NUDGE_UI_ROUTE_PREFIX}client.mjs`;
10
+ /** Pure controller document that hosts the editor chrome. */
11
+ export const NUDGE_UI_EDITOR_PATH = `${NUDGE_UI_ROUTE_PREFIX}editor`;
10
12
  /** Server-sent events announcing settled project changes. */
11
13
  export const NUDGE_UI_RELOAD_PATH = `${NUDGE_UI_ROUTE_PREFIX}reload`;
12
14
  export const NUDGE_UI_MOUNT_ID = "nudge-ui-root";
15
+ /** Query marker that presents an application route through the editor shell. */
16
+ export const NUDGE_UI_EDITOR_QUERY_PARAM = "nudge-ui";
17
+ export const NUDGE_UI_EDITOR_QUERY_VALUE = "editor";
18
+ /** Public `nudge-ui` values that turn the inspector off or on for one browser tab. */
19
+ export const NUDGE_UI_OFF_QUERY_VALUE = "off";
20
+ export const NUDGE_UI_ON_QUERY_VALUE = "on";
21
+ /** Internal alias of `nudge-ui=off` kept for existing direct-view links. */
22
+ export const NUDGE_UI_DIRECT_QUERY_PARAM = "__nudge_ui_direct";
13
23
  export function isReservedNudgeUiRoute(pathname) {
14
24
  return pathname === NUDGE_UI_ROUTE_PREFIX.slice(0, -1)
15
25
  || pathname.startsWith(NUDGE_UI_ROUTE_PREFIX);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nudge-ui",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Development-only visual UI inspector. One package, one subpath per host.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -79,7 +79,9 @@
79
79
  "@base-ui/react": "^1.7.0",
80
80
  "@tabler/icons-react": "^3.46.0",
81
81
  "magic-string": "^0.30.21",
82
+ "modern-screenshot": "^4.7.0",
82
83
  "parse5": "^7.3.0",
84
+ "perfect-freehand": "^1.2.3",
83
85
  "postcss": "^8.5.26",
84
86
  "typescript": "^5.9.3"
85
87
  },
@@ -1,8 +0,0 @@
1
- import type { ReactElement } from "react";
2
- import type { SelectedElement } from "../selection/selectionStore.js";
3
- interface DomNavigationProps {
4
- selected: SelectedElement;
5
- hierarchy: HTMLElement[];
6
- }
7
- export declare function DomNavigation({ selected, hierarchy }: DomNavigationProps): ReactElement | null;
8
- export {};
@@ -1,30 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { resolveSelectionFromElement } from "../selection/resolveSelection.js";
3
- import { setSelectedElement } from "../selection/selectionStore.js";
4
- import { computeDescendants } from "../selection/hierarchy.js";
5
- import { Button } from "../ui/Button.js";
6
- const MAX_PARENT_LEVELS = 2;
7
- const MAX_CHILD_NODES = 2;
8
- function nodeLabel(node) {
9
- return node.getAttribute("data-cid") ?? node.localName;
10
- }
11
- function nodeDescription(node) {
12
- const id = node.id ? `#${node.id}` : "";
13
- const className = typeof node.className === "string"
14
- ? node.className.trim().split(/\s+/).filter(Boolean).slice(0, 2).map((name) => `.${name}`).join("")
15
- : "";
16
- const source = node.getAttribute("data-src");
17
- return `${node.localName}${id}${className}${source ? ` — ${source}` : ""}`;
18
- }
19
- function selectNode(node) {
20
- const resolved = resolveSelectionFromElement(node);
21
- if (resolved)
22
- setSelectedElement(resolved);
23
- }
24
- export function DomNavigation({ selected, hierarchy }) {
25
- const parents = hierarchy.slice(1, MAX_PARENT_LEVELS + 1);
26
- const children = computeDescendants(selected.domElement, 2, MAX_CHILD_NODES);
27
- if (parents.length === 0 && children.length === 0)
28
- return null;
29
- return (_jsxs("section", { className: "dom-navigation", "data-test": "dom-navigation", "aria-label": "DOM navigation", children: [_jsx("div", { className: "dom-navigation__header", children: _jsx("span", { className: "dom-navigation__title", children: "DOM" }) }), parents.length > 0 ? (_jsxs("div", { className: "dom-navigation__group", "data-test": "dom-parents", children: [_jsx("span", { className: "dom-navigation__label", children: "Parents" }), _jsx("div", { className: "dom-navigation__items", children: parents.map((node, index) => (_jsxs(Button, { size: "compact", variant: "quiet", className: "dom-navigation__item", "data-test": "dom-parent-step", "data-depth": index + 1, "data-cid": node.getAttribute("data-cid") ?? undefined, title: nodeDescription(node), onClick: () => selectNode(node), children: [_jsx("span", { "aria-hidden": "true", children: "\u2191" }), index === 0 ? "Parent" : "Grandparent", _jsx("span", { className: "dom-navigation__value", children: nodeLabel(node) })] }, `${index}-${nodeLabel(node)}`))) })] })) : null, children.length > 0 ? (_jsxs("div", { className: "dom-navigation__group", "data-test": "dom-children", children: [_jsx("span", { className: "dom-navigation__label", children: "Children" }), _jsx("div", { className: "dom-navigation__items", children: children.map(({ element, depth }, index) => (_jsxs(Button, { size: "compact", variant: "quiet", className: "dom-navigation__item", "data-test": "dom-child-step", "data-depth": depth, "data-cid": element.getAttribute("data-cid") ?? undefined, title: nodeDescription(element), onClick: () => selectNode(element), children: [_jsx("span", { "aria-hidden": "true", children: "\u2193" }), depth === 1 ? "Child" : "Descendant", _jsx("span", { className: "dom-navigation__value", children: nodeLabel(element) })] }, `${depth}-${index}-${nodeLabel(element)}`))) })] })) : null] }));
30
- }
@@ -1,2 +0,0 @@
1
- export declare function setInspectorLayoutOpen(open: boolean): void;
2
- export declare function clearInspectorLayout(): void;
@@ -1,29 +0,0 @@
1
- const LAYOUT_STYLE_ID = "nudge-ui-panel-layout";
2
- const PANEL_LAYOUT_ATTRIBUTE = "data-nudge-ui-panel";
3
- const LAYOUT_STYLES = `
4
- html[${PANEL_LAYOUT_ATTRIBUTE}="open"] body {
5
- margin-right: min(320px, 100vw);
6
- transition: margin-right 180ms ease;
7
- }
8
- `;
9
- function ensureLayoutStyles() {
10
- if (document.getElementById(LAYOUT_STYLE_ID))
11
- return;
12
- const style = document.createElement("style");
13
- style.id = LAYOUT_STYLE_ID;
14
- style.textContent = LAYOUT_STYLES;
15
- document.head.appendChild(style);
16
- }
17
- export function setInspectorLayoutOpen(open) {
18
- const root = document.documentElement;
19
- if (open) {
20
- ensureLayoutStyles();
21
- root.setAttribute(PANEL_LAYOUT_ATTRIBUTE, "open");
22
- return;
23
- }
24
- root.removeAttribute(PANEL_LAYOUT_ATTRIBUTE);
25
- }
26
- export function clearInspectorLayout() {
27
- document.documentElement.removeAttribute(PANEL_LAYOUT_ATTRIBUTE);
28
- document.getElementById(LAYOUT_STYLE_ID)?.remove();
29
- }