From cbdbc4043a79ce37f73a0a58e3acea44447f82b1 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 09:47:39 -0800 Subject: [PATCH 01/13] sync(isolated): update isolated renderer from desktop Syncs isolated renderer components from desktop app, including: - Search functionality in isolated frames (search, searchNavigate) - Updated frame bridge communication - Enhanced comm bridge manager for custom messages - Test updates for new IsolatedFrameHandle interface --- registry/outputs/isolated/IsolationTest.tsx | 2 - .../__tests__/comm-bridge-manager.test.ts | 2 + .../outputs/isolated/comm-bridge-manager.ts | 18 +-- registry/outputs/isolated/frame-bridge.ts | 62 ++++++++--- registry/outputs/isolated/frame-html.ts | 103 +++++++++++++++--- registry/outputs/isolated/index.ts | 3 - registry/outputs/isolated/isolated-frame.tsx | 31 +++++- .../isolated/isolated-renderer-context.tsx | 2 - 8 files changed, 167 insertions(+), 56 deletions(-) diff --git a/registry/outputs/isolated/IsolationTest.tsx b/registry/outputs/isolated/IsolationTest.tsx index a70fce3..5f411a9 100644 --- a/registry/outputs/isolated/IsolationTest.tsx +++ b/registry/outputs/isolated/IsolationTest.tsx @@ -1,5 +1,3 @@ -"use client"; - import { useEffect, useRef, useState } from "react"; import { IsolatedFrame, type IsolatedFrameHandle } from "./isolated-frame"; diff --git a/registry/outputs/isolated/__tests__/comm-bridge-manager.test.ts b/registry/outputs/isolated/__tests__/comm-bridge-manager.test.ts index 992e092..1e645bb 100644 --- a/registry/outputs/isolated/__tests__/comm-bridge-manager.test.ts +++ b/registry/outputs/isolated/__tests__/comm-bridge-manager.test.ts @@ -90,6 +90,8 @@ function createMockFrame(): { eval: vi.fn(), setTheme: vi.fn(), clear: vi.fn(), + search: vi.fn(), + searchNavigate: vi.fn(), isReady: true, isIframeReady: true, }; diff --git a/registry/outputs/isolated/comm-bridge-manager.ts b/registry/outputs/isolated/comm-bridge-manager.ts index efb5332..73d7234 100644 --- a/registry/outputs/isolated/comm-bridge-manager.ts +++ b/registry/outputs/isolated/comm-bridge-manager.ts @@ -1,17 +1,3 @@ -/** - * Comm Bridge Manager - Parent Side - * - * This module manages the communication bridge between the parent window's - * widget system and an isolated iframe. It: - * - Buffers comm messages until iframe sends `widget_ready` - * - Syncs all existing widget models to iframe on ready - * - Forwards comm messages from kernel to iframe - * - Handles widget messages from iframe and updates parent store + kernel - * - * Security: The iframe cannot access Tauri APIs directly. All widget - * communication must go through this controlled postMessage bridge. - */ - import type { WidgetStore } from "@/registry/widgets/widget-store"; import type { CommCloseMessage, @@ -370,9 +356,9 @@ export class CommBridgeManager { const unsubscribe = this.store.subscribeToCustomMessage( commId, - (content, buffers) => { + (content: Record, buffers?: DataView[]) => { // Convert DataView[] to ArrayBuffer[] for postMessage - const arrayBuffers = buffers?.map((dv) => dv.buffer as ArrayBuffer); + const arrayBuffers = buffers?.map((dv: DataView) => dv.buffer as ArrayBuffer); // Forward custom message to iframe this.sendCommMsg(commId, "custom", content, arrayBuffers); }, diff --git a/registry/outputs/isolated/frame-bridge.ts b/registry/outputs/isolated/frame-bridge.ts index 5952489..6344a63 100644 --- a/registry/outputs/isolated/frame-bridge.ts +++ b/registry/outputs/isolated/frame-bridge.ts @@ -1,16 +1,3 @@ -/** - * Message protocol types for parent ↔ iframe communication. - * - * This module defines the contract between the parent window and isolated output frames. - * All communication happens via postMessage with structured message types. - */ - -// --- Message Types: Parent → Iframe --- - -/** - * Bootstrap the iframe with JavaScript code. - * Used to inject the ESM renderer bundle into the iframe. - */ export interface EvalMessage { type: "eval"; payload: { @@ -168,6 +155,33 @@ export interface BridgeReadyMessage { type: "bridge_ready"; } +// --- Global Find: Parent → Iframe --- + +/** + * Search for text within the iframe's rendered content. + * The iframe should highlight all matches and report the count. + */ +export interface SearchMessage { + type: "search"; + payload: { + /** The search query string (empty string clears search) */ + query: string; + /** Whether the search should be case-sensitive */ + caseSensitive?: boolean; + }; +} + +/** + * Navigate to a specific match in the iframe's search results. + */ +export interface SearchNavigateMessage { + type: "search_navigate"; + payload: { + /** The index of the match to navigate to (0-based) */ + matchIndex: number; + }; +} + /** * All message types that can be sent from parent to iframe. */ @@ -182,7 +196,9 @@ export type ParentToIframeMessage = | CommMsgMessage | CommCloseMessage | CommSyncMessage - | BridgeReadyMessage; + | BridgeReadyMessage + | SearchMessage + | SearchNavigateMessage; // --- Message Types: Iframe → Parent --- @@ -337,6 +353,20 @@ export interface WidgetCommCloseMessage { }; } +// --- Global Find: Iframe → Parent --- + +/** + * Report search results from the iframe. + * Sent after processing a search message. + */ +export interface SearchResultsMessage { + type: "search_results"; + payload: { + /** Number of matches found */ + count: number; + }; +} + /** * All message types that can be sent from iframe to parent. */ @@ -353,7 +383,8 @@ export type IframeToParentMessage = | RendererReadyMessage | WidgetReadyMessage | WidgetCommMsgMessage - | WidgetCommCloseMessage; + | WidgetCommCloseMessage + | SearchResultsMessage; // --- Utility Types --- @@ -389,6 +420,7 @@ export function isIframeMessage(data: unknown): data is IframeToParentMessage { "widget_ready", "widget_comm_msg", "widget_comm_close", + "search_results", ].includes(msg.type) ); } diff --git a/registry/outputs/isolated/frame-html.ts b/registry/outputs/isolated/frame-html.ts index 50cb1a6..b9a77ba 100644 --- a/registry/outputs/isolated/frame-html.ts +++ b/registry/outputs/isolated/frame-html.ts @@ -1,14 +1,3 @@ -/** - * HTML template generator for isolated output frames. - * - * Creates the minimal HTML document that runs inside the blob URL iframe. - * This document handles the message protocol and provides a render target - * for output content. - * - * Security: This code runs in an isolated origin (blob:) with sandbox - * restrictions, so it cannot access Tauri APIs or the parent DOM. - */ - export interface FrameHtmlOptions { /** * Whether to include dark mode styles by default. @@ -69,16 +58,11 @@ export function generateFrameHtml(options: FrameHtmlOptions = {}): string { margin: 0; padding: 0; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - font-size: 14px; line-height: 1.5; background: transparent; color: var(--text-primary); } - body { - padding: 8px; - } - /* Output container */ #root { min-height: 1px; @@ -200,6 +184,14 @@ export function generateFrameHtml(options: FrameHtmlOptions = {}): string { handleWidgetState(payload); break; + case 'search': + handleSearch(payload); + break; + + case 'search_navigate': + handleSearchNavigate(payload); + break; + // Comm bridge messages - handled by React widget system, ignore here case 'bridge_ready': case 'comm_open': @@ -393,6 +385,85 @@ export function generateFrameHtml(options: FrameHtmlOptions = {}): string { window.dispatchEvent(new CustomEvent('widget_state', { detail: payload })); } + // --- Search --- + var searchMarks = []; + var currentSearchIndex = -1; + + function handleSearch(payload) { + var query = (payload && payload.query) || ''; + var caseSensitive = payload && payload.caseSensitive; + clearSearchMarks(); + if (!query) { + send('search_results', { count: 0 }); + return; + } + var marks = []; + var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null); + var node; + var compareQuery = caseSensitive ? query : query.toLowerCase(); + // Collect all text nodes and their match positions + var matches = []; + while ((node = walker.nextNode())) { + var text = node.nodeValue || ''; + var compareText = caseSensitive ? text : text.toLowerCase(); + var pos = 0; + while ((pos = compareText.indexOf(compareQuery, pos)) !== -1) { + matches.push({ node: node, offset: pos, length: query.length }); + pos += query.length; + } + } + // Highlight matches in reverse order to preserve offsets + for (var i = matches.length - 1; i >= 0; i--) { + var m = matches[i]; + try { + var range = document.createRange(); + range.setStart(m.node, m.offset); + range.setEnd(m.node, m.offset + m.length); + var mark = document.createElement('mark'); + mark.className = 'global-find-match'; + mark.style.cssText = 'background: #fbbf24; color: #000; border-radius: 2px; padding: 0;'; + range.surroundContents(mark); + marks.unshift(mark); + } catch (e) { + // surroundContents can fail if range crosses element boundaries + } + } + searchMarks = marks; + currentSearchIndex = -1; + send('search_results', { count: marks.length }); + } + + function handleSearchNavigate(payload) { + var matchIndex = (payload && payload.matchIndex) || 0; + if (searchMarks.length === 0) return; + // Clear previous active highlight + if (currentSearchIndex >= 0 && currentSearchIndex < searchMarks.length) { + searchMarks[currentSearchIndex].style.cssText = 'background: #fbbf24; color: #000; border-radius: 2px; padding: 0;'; + } + currentSearchIndex = matchIndex; + if (currentSearchIndex >= 0 && currentSearchIndex < searchMarks.length) { + var active = searchMarks[currentSearchIndex]; + active.style.cssText = 'background: #f97316; color: #000; border-radius: 2px; padding: 0;'; + active.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); + } + } + + function clearSearchMarks() { + for (var i = 0; i < searchMarks.length; i++) { + var mark = searchMarks[i]; + var parent = mark.parentNode; + if (parent) { + while (mark.firstChild) { + parent.insertBefore(mark.firstChild, mark); + } + parent.removeChild(mark); + parent.normalize(); + } + } + searchMarks = []; + currentSearchIndex = -1; + } + // --- Utilities --- function send(type, payload) { diff --git a/registry/outputs/isolated/index.ts b/registry/outputs/isolated/index.ts index 495db33..8f3e9b8 100644 --- a/registry/outputs/isolated/index.ts +++ b/registry/outputs/isolated/index.ts @@ -1,6 +1,3 @@ -// Production components - -// Widget comm bridge for isolated frames export { CommBridgeManager, createCommBridgeManager, diff --git a/registry/outputs/isolated/isolated-frame.tsx b/registry/outputs/isolated/isolated-frame.tsx index 2caf17b..e9fddfa 100644 --- a/registry/outputs/isolated/isolated-frame.tsx +++ b/registry/outputs/isolated/isolated-frame.tsx @@ -1,5 +1,3 @@ -"use client"; - import { forwardRef, useCallback, @@ -112,6 +110,17 @@ export interface IsolatedFrameHandle { */ clear: () => void; + /** + * Search for text within the iframe's rendered content. + * Pass empty string to clear search highlights. + */ + search: (query: string, caseSensitive?: boolean) => void; + + /** + * Navigate to a specific search match by index. + */ + searchNavigate: (matchIndex: number) => void; + /** * Whether the iframe is ready to receive messages. * True after the React renderer bundle is initialized. @@ -431,6 +440,24 @@ export const IsolatedFrame = forwardRef< setTheme: (isDark: boolean) => send({ type: "theme", payload: { isDark } }), clear: () => send({ type: "clear" }), + search: (query: string, caseSensitive?: boolean) => { + // Search handler is in bootstrap HTML, so send directly when iframe is loaded + // (bypasses the isReady queue which waits for the React renderer) + if (iframeRef.current?.contentWindow) { + iframeRef.current.contentWindow.postMessage( + { type: "search", payload: { query, caseSensitive } }, + "*", + ); + } + }, + searchNavigate: (matchIndex: number) => { + if (iframeRef.current?.contentWindow) { + iframeRef.current.contentWindow.postMessage( + { type: "search_navigate", payload: { matchIndex } }, + "*", + ); + } + }, isReady, isIframeReady, }), diff --git a/registry/outputs/isolated/isolated-renderer-context.tsx b/registry/outputs/isolated/isolated-renderer-context.tsx index 1a3c5fc..89871c0 100644 --- a/registry/outputs/isolated/isolated-renderer-context.tsx +++ b/registry/outputs/isolated/isolated-renderer-context.tsx @@ -1,5 +1,3 @@ -"use client"; - import { createContext, type ReactNode, From 6c763a6df3737dbcf419911bfb6a43054ba6b82c Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 09:48:11 -0800 Subject: [PATCH 02/13] sync(outputs): update output components from desktop Syncs output components from desktop app including media router, provider, and all output renderers (ansi, html, image, json, markdown, svg). --- registry/outputs/html-output.tsx | 2 -- registry/outputs/json-output.tsx | 2 -- registry/outputs/markdown-output.tsx | 2 -- registry/outputs/media-provider.tsx | 2 -- registry/outputs/media-router.tsx | 15 +++++++++++++-- registry/outputs/svg-output.tsx | 2 -- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/registry/outputs/html-output.tsx b/registry/outputs/html-output.tsx index 59de859..32d8c97 100644 --- a/registry/outputs/html-output.tsx +++ b/registry/outputs/html-output.tsx @@ -1,5 +1,3 @@ -"use client"; - import { useEffect, useRef } from "react"; import { cn } from "@/lib/utils"; diff --git a/registry/outputs/json-output.tsx b/registry/outputs/json-output.tsx index db28afa..bfa7f6e 100644 --- a/registry/outputs/json-output.tsx +++ b/registry/outputs/json-output.tsx @@ -1,5 +1,3 @@ -"use client"; - import { ChevronRightIcon } from "lucide-react"; import { createContext, diff --git a/registry/outputs/markdown-output.tsx b/registry/outputs/markdown-output.tsx index 1398d78..2e40f3a 100644 --- a/registry/outputs/markdown-output.tsx +++ b/registry/outputs/markdown-output.tsx @@ -1,5 +1,3 @@ -"use client"; - import { Check, Copy } from "lucide-react"; import { useState } from "react"; import ReactMarkdown from "react-markdown"; diff --git a/registry/outputs/media-provider.tsx b/registry/outputs/media-provider.tsx index 39c1af9..d4e8bdb 100644 --- a/registry/outputs/media-provider.tsx +++ b/registry/outputs/media-provider.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * React context provider for shared media rendering configuration. * diff --git a/registry/outputs/media-router.tsx b/registry/outputs/media-router.tsx index 6d309a6..c9da0a6 100644 --- a/registry/outputs/media-router.tsx +++ b/registry/outputs/media-router.tsx @@ -1,5 +1,3 @@ -"use client"; - import { lazy, type ReactNode, Suspense } from "react"; import { useMediaContext } from "./media-provider"; @@ -346,6 +344,19 @@ export function MediaRouter({ return {String(content)}; } + // Widget view JSON - when rendered in-DOM without a widget renderer, + // show a helpful message instead of raw JSON. This typically happens + // when a widget is displayed inside an Output widget. + if (mimeType === "application/vnd.jupyter.widget-view+json") { + return ( +
+ Nested widget + · + Widgets inside Output widgets are not yet supported +
+ ); + } + // Unknown +json types without custom renderer - show as JSON if (mimeType.includes("+json")) { return ( diff --git a/registry/outputs/svg-output.tsx b/registry/outputs/svg-output.tsx index b110cd6..b98b425 100644 --- a/registry/outputs/svg-output.tsx +++ b/registry/outputs/svg-output.tsx @@ -1,5 +1,3 @@ -"use client"; - import { useEffect, useRef } from "react"; import { cn } from "@/lib/utils"; From 0b15be9648b80dbd84748aad54c797ca0a3b3a72 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 09:48:39 -0800 Subject: [PATCH 03/13] sync(editor): update editor components from desktop Syncs editor components (CodeMirror integration) from desktop app. Note: search-highlight.ts is desktop-specific and not synced. --- registry/editor/codemirror-editor.tsx | 2 -- registry/editor/extensions.ts | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/registry/editor/codemirror-editor.tsx b/registry/editor/codemirror-editor.tsx index 92c85d8..c76b3b7 100644 --- a/registry/editor/codemirror-editor.tsx +++ b/registry/editor/codemirror-editor.tsx @@ -1,5 +1,3 @@ -"use client"; - import { EditorView, type KeyBinding, diff --git a/registry/editor/extensions.ts b/registry/editor/extensions.ts index 86b8059..2f251cf 100644 --- a/registry/editor/extensions.ts +++ b/registry/editor/extensions.ts @@ -34,6 +34,11 @@ export const notebookEditorTheme = EditorView.theme({ "&.cm-focused": { outline: "none", }, + // Reset line padding so code aligns with output areas + // (CodeMirror's base theme adds "padding: 0 2px 0 6px" to .cm-line) + ".cm-line": { + paddingLeft: "0", + }, // Mobile-friendly padding "@media (max-width: 640px)": { ".cm-content": { From 09c87c8652340f4fd122f94b06ef66bbadc26679 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 09:50:11 -0800 Subject: [PATCH 04/13] sync(cell): update cell components from desktop Syncs cell components from desktop app including: - CellContainer, CellTypeSelector, CollaboratorAvatars - CompactExecutionButton, OutputArea, PresenceBookmarks - Added highlight-text.ts utility for search highlighting Import paths adjusted for elements registry structure. --- registry/cell/CellContainer.tsx | 6 +- registry/cell/CellTypeSelector.tsx | 7 +- registry/cell/CollaboratorAvatars.tsx | 2 - registry/cell/CompactExecutionButton.tsx | 2 +- registry/cell/OutputArea.tsx | 134 ++++++++++++++++------- registry/cell/PresenceBookmarks.tsx | 2 - registry/lib/highlight-text.ts | 66 +++++++++++ 7 files changed, 167 insertions(+), 52 deletions(-) create mode 100644 registry/lib/highlight-text.ts diff --git a/registry/cell/CellContainer.tsx b/registry/cell/CellContainer.tsx index d55e144..d453bc8 100644 --- a/registry/cell/CellContainer.tsx +++ b/registry/cell/CellContainer.tsx @@ -94,7 +94,7 @@ export const CellContainer = forwardRef( ribbonColor, )} /> -
{codeContent}
+
{codeContent}
{/* Output row - ribbon + content together */} {hasOutput && ( @@ -107,7 +107,7 @@ export const CellContainer = forwardRef( />
@@ -125,7 +125,7 @@ export const CellContainer = forwardRef( ribbonColor, )} /> -
{children}
+
{children}
)} {/* Right margin - pt-3 aligns with left gutter, appears on hover/focus */} diff --git a/registry/cell/CellTypeSelector.tsx b/registry/cell/CellTypeSelector.tsx index 6301305..a3a7d86 100644 --- a/registry/cell/CellTypeSelector.tsx +++ b/registry/cell/CellTypeSelector.tsx @@ -1,6 +1,8 @@ -"use client"; - import { Bot, ChevronDown, Code, Database, FileText } from "lucide-react"; +import { + type CellType, + cellTypeStyles, +} from "@/registry/cell/CellTypeButton"; import { Button } from "@/components/ui/button"; import { DropdownMenu, @@ -9,7 +11,6 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { cn } from "@/lib/utils"; -import { type CellType, cellTypeStyles } from "@/registry/cell/CellTypeButton"; const allCellTypes: CellType[] = ["code", "markdown", "sql", "ai"]; diff --git a/registry/cell/CollaboratorAvatars.tsx b/registry/cell/CollaboratorAvatars.tsx index 54de622..6914c0a 100644 --- a/registry/cell/CollaboratorAvatars.tsx +++ b/registry/cell/CollaboratorAvatars.tsx @@ -1,5 +1,3 @@ -"use client"; - import * as React from "react"; import { Avatar, diff --git a/registry/cell/CompactExecutionButton.tsx b/registry/cell/CompactExecutionButton.tsx index 3d5071f..0339c89 100644 --- a/registry/cell/CompactExecutionButton.tsx +++ b/registry/cell/CompactExecutionButton.tsx @@ -38,7 +38,6 @@ export function CompactExecutionButton({ return ( @@ -480,34 +529,37 @@ export function OutputArea({ )} {/* In-DOM outputs (when not using isolation) */} - {!shouldIsolate && - outputs.map((output, index) => ( -
- ( - - )} - onError={(error, errorInfo) => { - console.error( - `[OutputArea] Error rendering output ${index}:`, - error, - errorInfo.componentStack, - ); - }} + {!shouldIsolate && ( +
+ {outputs.map((output, index) => ( +
- {renderOutput(output, index, renderers, priority)} - -
- ))} + ( + + )} + onError={(error, errorInfo) => { + console.error( + `[OutputArea] Error rendering output ${index}:`, + error, + errorInfo.componentStack, + ); + }} + > + {renderOutput(output, index, renderers, priority)} + +
+ ))} +
+ )} )} diff --git a/registry/cell/PresenceBookmarks.tsx b/registry/cell/PresenceBookmarks.tsx index 7c6a907..1aa0366 100644 --- a/registry/cell/PresenceBookmarks.tsx +++ b/registry/cell/PresenceBookmarks.tsx @@ -1,5 +1,3 @@ -"use client"; - import type * as React from "react"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { diff --git a/registry/lib/highlight-text.ts b/registry/lib/highlight-text.ts new file mode 100644 index 0000000..870747c --- /dev/null +++ b/registry/lib/highlight-text.ts @@ -0,0 +1,66 @@ +/** + * Highlight all occurrences of a search query within a DOM container. + * + * Walks text nodes using TreeWalker, wraps matches in elements. + * Returns a cleanup function that removes all marks and restores text nodes. + */ +export function highlightTextInDom( + container: HTMLElement, + query: string, +): () => void { + if (!query) return () => {}; + + const marks: HTMLElement[] = []; + const walker = document.createTreeWalker( + container, + NodeFilter.SHOW_TEXT, + null, + ); + const lowerQuery = query.toLowerCase(); + + // Collect matches first (to avoid mutating DOM while walking) + const matches: { node: Text; offset: number; length: number }[] = []; + let node = walker.nextNode(); + while (node) { + const text = node.nodeValue || ""; + const lowerText = text.toLowerCase(); + let pos = lowerText.indexOf(lowerQuery, 0); + while (pos !== -1) { + matches.push({ node: node as Text, offset: pos, length: query.length }); + pos = lowerText.indexOf(lowerQuery, pos + query.length); + } + node = walker.nextNode(); + } + + // Apply highlights in reverse order to preserve offsets + for (let i = matches.length - 1; i >= 0; i--) { + const m = matches[i]; + try { + const range = document.createRange(); + range.setStart(m.node, m.offset); + range.setEnd(m.node, m.offset + m.length); + const mark = document.createElement("mark"); + mark.className = "global-find-match"; + mark.style.cssText = + "background: #fbbf24; color: #000; border-radius: 2px; padding: 0;"; + range.surroundContents(mark); + marks.unshift(mark); + } catch { + // surroundContents can fail if range crosses element boundaries + } + } + + // Return cleanup function + return () => { + for (const mark of marks) { + const parent = mark.parentNode; + if (parent) { + while (mark.firstChild) { + parent.insertBefore(mark.firstChild, mark); + } + parent.removeChild(mark); + parent.normalize(); + } + } + }; +} From 93bb44b8c9cbac8044958f2c8014f450b0d4be2b Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 09:51:15 -0800 Subject: [PATCH 05/13] sync(widgets): update widget root components from desktop Syncs widget root components from desktop app including: - widget-store.ts, widget-view.tsx, anywidget-view.tsx - use-comm-router.ts, use-layout-styles.ts, link-subscriptions.ts - widget-registry.ts, widget-store-context.tsx - canvas-manager-subscriptions.ts, buffer-utils.ts - widget-error-fallback.tsx utility Import paths adjusted for elements registry structure. --- registry/lib/widget-error-fallback.tsx | 2 -- registry/widgets/anywidget-view.tsx | 2 -- registry/widgets/buffer-utils.ts | 26 ------------------- .../widgets/canvas-manager-subscriptions.ts | 19 -------------- registry/widgets/link-subscriptions.ts | 17 ------------ registry/widgets/use-comm-router.ts | 2 -- registry/widgets/use-layout-styles.ts | 2 -- registry/widgets/widget-registry.ts | 6 ----- registry/widgets/widget-store-context.tsx | 2 -- registry/widgets/widget-store.ts | 9 ------- registry/widgets/widget-view.tsx | 4 +-- 11 files changed, 1 insertion(+), 90 deletions(-) diff --git a/registry/lib/widget-error-fallback.tsx b/registry/lib/widget-error-fallback.tsx index 7c4464c..ee7efe6 100644 --- a/registry/lib/widget-error-fallback.tsx +++ b/registry/lib/widget-error-fallback.tsx @@ -1,5 +1,3 @@ -"use client"; - import { cn } from "@/lib/utils"; export interface WidgetErrorFallbackProps { diff --git a/registry/widgets/anywidget-view.tsx b/registry/widgets/anywidget-view.tsx index ef04bb7..25b7af2 100644 --- a/registry/widgets/anywidget-view.tsx +++ b/registry/widgets/anywidget-view.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * anywidget ESM loader and AFM (AnyWidget Frontend Module) interface. * diff --git a/registry/widgets/buffer-utils.ts b/registry/widgets/buffer-utils.ts index 71aa786..4b06ae0 100644 --- a/registry/widgets/buffer-utils.ts +++ b/registry/widgets/buffer-utils.ts @@ -1,29 +1,3 @@ -/** - * Buffer path utilities for Jupyter widget protocol. - * - * Handles the buffer_paths field in comm messages which specifies - * where binary buffers should be inserted into the JSON message data. - * - * @see https://jupyter-widgets.readthedocs.io/en/latest/examples/Widget%20Low%20Level.html - */ - -/** - * Apply buffers to message data at specified paths. - * - * The Jupyter widget protocol sends binary data separately from JSON. - * The buffer_paths field specifies where each buffer should be inserted. - * - * @example - * // buffer_paths: [["state", "data"], ["content", "blob"]] - * // buffers: [ArrayBuffer1, ArrayBuffer2] - * // data: { state: {}, content: {} } - * // Result: { state: { data: ArrayBuffer1 }, content: { blob: ArrayBuffer2 } } - * - * @param data - The message data object to modify (mutated in place) - * @param bufferPaths - Array of paths, each path is an array of keys - * @param buffers - Array of buffers to insert at the corresponding paths - * @returns The modified data object (same reference as input) - */ export function applyBufferPaths( data: Record, bufferPaths: string[][] | undefined, diff --git a/registry/widgets/canvas-manager-subscriptions.ts b/registry/widgets/canvas-manager-subscriptions.ts index 55b93e4..fc895e4 100644 --- a/registry/widgets/canvas-manager-subscriptions.ts +++ b/registry/widgets/canvas-manager-subscriptions.ts @@ -1,22 +1,3 @@ -/** - * Store-level routing for ipycanvas CanvasManagerModel. - * - * CanvasManagerModel is a headless widget (_view_name: null) that receives - * ALL drawing commands from Python. This module subscribes to each manager's - * custom messages, parses switchCanvas targets, and re-emits to each target - * canvas's comm_id — isolating canvases from each other. - * - * Same pattern as link-subscriptions.ts for LinkModel/DirectionalLinkModel. - * - * Usage: - * const cleanup = createCanvasManagerRouter(store); - * // ... later, to tear down all routing: - * cleanup(); - * - * WidgetStoreProvider calls this automatically. For non-React integrations - * (e.g. iframe isolation), call createCanvasManagerRouter directly. - */ - import type { WidgetStore } from "./widget-store"; // ipycanvas drawing command names indexed by protocol number. diff --git a/registry/widgets/link-subscriptions.ts b/registry/widgets/link-subscriptions.ts index 0942498..3f90918 100644 --- a/registry/widgets/link-subscriptions.ts +++ b/registry/widgets/link-subscriptions.ts @@ -1,20 +1,3 @@ -/** - * Store-level link subscriptions for frontend-only property synchronization. - * - * Manages LinkModel (jslink) and DirectionalLinkModel (jsdlink) at the - * store level so links work without React component mounting. This is - * critical because link widgets are headless (_view_name: null) and won't - * appear in any container widget's children. - * - * Usage: - * const cleanup = createLinkManager(store); - * // ... later, to tear down all links: - * cleanup(); - * - * WidgetStoreProvider calls this automatically. For non-React integrations - * (e.g. iframe isolation), call createLinkManager directly. - */ - import { parseModelRef, type WidgetStore } from "./widget-store"; /** diff --git a/registry/widgets/use-comm-router.ts b/registry/widgets/use-comm-router.ts index 2f87c17..21ee3ca 100644 --- a/registry/widgets/use-comm-router.ts +++ b/registry/widgets/use-comm-router.ts @@ -1,5 +1,3 @@ -"use client"; - /** * Comm Protocol Router Hook * diff --git a/registry/widgets/use-layout-styles.ts b/registry/widgets/use-layout-styles.ts index f7656e9..5de2a84 100644 --- a/registry/widgets/use-layout-styles.ts +++ b/registry/widgets/use-layout-styles.ts @@ -1,5 +1,3 @@ -"use client"; - import type { CSSProperties } from "react"; import { useMemo } from "react"; import { diff --git a/registry/widgets/widget-registry.ts b/registry/widgets/widget-registry.ts index 06690ce..e9110fd 100644 --- a/registry/widgets/widget-registry.ts +++ b/registry/widgets/widget-registry.ts @@ -1,9 +1,3 @@ -/** - * Registry mapping widget model names to React components. - * - * This maps _model_name from ipywidgets to our shadcn-backed implementations. - */ - import type { ComponentType } from "react"; export interface WidgetComponentProps { diff --git a/registry/widgets/widget-store-context.tsx b/registry/widgets/widget-store-context.tsx index 69d8434..4b6f5c7 100644 --- a/registry/widgets/widget-store-context.tsx +++ b/registry/widgets/widget-store-context.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * React context and hooks for the widget model store. * diff --git a/registry/widgets/widget-store.ts b/registry/widgets/widget-store.ts index f7f0a67..de1d97e 100644 --- a/registry/widgets/widget-store.ts +++ b/registry/widgets/widget-store.ts @@ -1,12 +1,3 @@ -/** - * Pure React widget model store for Jupyter widgets. - * - * This replaces the Backbone.js-based model system from @jupyter-widgets/html-manager - * with a pure JavaScript store that integrates with React via useSyncExternalStore. - */ - -// === Types === - export interface WidgetModel { /** comm_id from the Jupyter protocol */ id: string; diff --git a/registry/widgets/widget-view.tsx b/registry/widgets/widget-view.tsx index 9092401..f3d7f3e 100644 --- a/registry/widgets/widget-view.tsx +++ b/registry/widgets/widget-view.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Universal widget view component. * @@ -9,8 +7,8 @@ * - Unknown widgets → UnsupportedWidget fallback */ -import { cn } from "@/lib/utils"; import { ErrorBoundary } from "@/registry/lib/error-boundary"; +import { cn } from "@/lib/utils"; import { WidgetErrorFallback } from "@/registry/lib/widget-error-fallback"; import { AnyWidgetView, isAnyWidget } from "./anywidget-view"; import { useLayoutStyles } from "./use-layout-styles"; From 14a8a89582964d2ad6086fcb4da1934a22ebe45e Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 09:52:02 -0800 Subject: [PATCH 06/13] sync(widgets/controls): update widget controls from desktop Syncs all 56 widget control components from desktop app including: - Form widgets (input, textarea, combobox, etc.) - Selection widgets (dropdown, radio, checkbox, toggle, etc.) - Layout widgets (box, hbox, vbox, stack, gridbox, etc.) - Display widgets (label, button, link, etc.) - Complex widgets (accordion, tabs, date-picker, time-picker, etc.) Import paths adjusted for elements registry structure. --- registry/widgets/controls/accordion-widget.tsx | 2 -- registry/widgets/controls/audio-widget.tsx | 2 -- .../widgets/controls/bounded-float-text-widget.tsx | 2 -- registry/widgets/controls/bounded-int-text-widget.tsx | 2 -- registry/widgets/controls/box-widget.tsx | 2 -- registry/widgets/controls/button-style-utils.ts | 10 ---------- registry/widgets/controls/button-widget.tsx | 2 -- registry/widgets/controls/checkbox-widget.tsx | 2 -- registry/widgets/controls/color-picker.tsx | 2 -- registry/widgets/controls/colors-input-widget.tsx | 2 -- registry/widgets/controls/combobox-widget.tsx | 2 -- registry/widgets/controls/controller-axis-widget.tsx | 2 -- registry/widgets/controls/controller-button-widget.tsx | 2 -- registry/widgets/controls/controller-widget.tsx | 2 -- registry/widgets/controls/date-picker-widget.tsx | 2 -- registry/widgets/controls/datetime-widget.tsx | 2 -- registry/widgets/controls/dropdown-widget.tsx | 2 -- registry/widgets/controls/file-upload-widget.tsx | 2 -- registry/widgets/controls/float-log-slider.tsx | 2 -- registry/widgets/controls/float-progress.tsx | 2 -- registry/widgets/controls/float-range-slider.tsx | 2 -- registry/widgets/controls/float-slider.tsx | 2 -- registry/widgets/controls/float-text-widget.tsx | 2 -- registry/widgets/controls/floats-input-widget.tsx | 2 -- registry/widgets/controls/gridbox-widget.tsx | 2 -- registry/widgets/controls/hbox-widget.tsx | 2 -- registry/widgets/controls/html-math-widget.tsx | 2 -- registry/widgets/controls/html-widget.tsx | 2 -- registry/widgets/controls/image-widget.tsx | 2 -- registry/widgets/controls/index.ts | 7 ------- registry/widgets/controls/int-progress.tsx | 2 -- registry/widgets/controls/int-range-slider.tsx | 2 -- registry/widgets/controls/int-slider.tsx | 2 -- registry/widgets/controls/int-text-widget.tsx | 2 -- registry/widgets/controls/ints-input-widget.tsx | 2 -- registry/widgets/controls/label-widget.tsx | 2 -- registry/widgets/controls/link-widget.tsx | 2 -- registry/widgets/controls/output-widget.tsx | 4 +--- registry/widgets/controls/password-widget.tsx | 2 -- registry/widgets/controls/play-widget.tsx | 2 -- registry/widgets/controls/radio-buttons-widget.tsx | 2 -- registry/widgets/controls/select-multiple-widget.tsx | 2 -- registry/widgets/controls/select-widget.tsx | 2 -- .../widgets/controls/selection-range-slider-widget.tsx | 2 -- registry/widgets/controls/selection-slider-widget.tsx | 2 -- registry/widgets/controls/stack-widget.tsx | 2 -- registry/widgets/controls/tab-widget.tsx | 2 -- registry/widgets/controls/tags-input-widget.tsx | 2 -- registry/widgets/controls/text-widget.tsx | 2 -- registry/widgets/controls/textarea-widget.tsx | 2 -- registry/widgets/controls/time-picker-widget.tsx | 2 -- registry/widgets/controls/toggle-button-widget.tsx | 2 -- registry/widgets/controls/toggle-buttons-widget.tsx | 2 -- registry/widgets/controls/valid-widget.tsx | 2 -- registry/widgets/controls/vbox-widget.tsx | 2 -- registry/widgets/controls/video-widget.tsx | 2 -- 56 files changed, 1 insertion(+), 126 deletions(-) diff --git a/registry/widgets/controls/accordion-widget.tsx b/registry/widgets/controls/accordion-widget.tsx index 6f71125..ea5dd9e 100644 --- a/registry/widgets/controls/accordion-widget.tsx +++ b/registry/widgets/controls/accordion-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Accordion widget - collapsible panel container. * diff --git a/registry/widgets/controls/audio-widget.tsx b/registry/widgets/controls/audio-widget.tsx index e5a8ad4..6bf2265 100644 --- a/registry/widgets/controls/audio-widget.tsx +++ b/registry/widgets/controls/audio-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Audio widget - plays audio from the kernel. * diff --git a/registry/widgets/controls/bounded-float-text-widget.tsx b/registry/widgets/controls/bounded-float-text-widget.tsx index 2196499..23c4178 100644 --- a/registry/widgets/controls/bounded-float-text-widget.tsx +++ b/registry/widgets/controls/bounded-float-text-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * BoundedFloatText widget - renders a bounded numeric text input for floats. * diff --git a/registry/widgets/controls/bounded-int-text-widget.tsx b/registry/widgets/controls/bounded-int-text-widget.tsx index 9d56b3b..72dbe50 100644 --- a/registry/widgets/controls/bounded-int-text-widget.tsx +++ b/registry/widgets/controls/bounded-int-text-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * BoundedIntText widget - renders a bounded numeric text input for integers. * diff --git a/registry/widgets/controls/box-widget.tsx b/registry/widgets/controls/box-widget.tsx index 7de0aab..42ac3dd 100644 --- a/registry/widgets/controls/box-widget.tsx +++ b/registry/widgets/controls/box-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Box widget - generic flex container. * diff --git a/registry/widgets/controls/button-style-utils.ts b/registry/widgets/controls/button-style-utils.ts index b2bf71c..6f77386 100644 --- a/registry/widgets/controls/button-style-utils.ts +++ b/registry/widgets/controls/button-style-utils.ts @@ -1,13 +1,3 @@ -/** - * Shared utility for mapping ipywidgets button_style to shadcn Button - * variant + Tailwind className overrides. - * - * The shadcn Button only has default, destructive, outline, secondary, ghost, - * link variants — no info/success/warning. We use the "default" variant as a - * base and apply Tailwind color classes via className. tailwind-merge resolves - * the conflict in favor of our overrides. - */ - type ButtonStyleVariant = "default" | "destructive" | "outline"; interface ButtonStyleResult { diff --git a/registry/widgets/controls/button-widget.tsx b/registry/widgets/controls/button-widget.tsx index 1f9832e..fadf225 100644 --- a/registry/widgets/controls/button-widget.tsx +++ b/registry/widgets/controls/button-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Button widget - renders a clickable button. * diff --git a/registry/widgets/controls/checkbox-widget.tsx b/registry/widgets/controls/checkbox-widget.tsx index 61dcdd3..9beadf6 100644 --- a/registry/widgets/controls/checkbox-widget.tsx +++ b/registry/widgets/controls/checkbox-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Checkbox widget - renders a checkbox input. * diff --git a/registry/widgets/controls/color-picker.tsx b/registry/widgets/controls/color-picker.tsx index 4f00606..b543c03 100644 --- a/registry/widgets/controls/color-picker.tsx +++ b/registry/widgets/controls/color-picker.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * ColorPicker widget - renders a color selection input. * diff --git a/registry/widgets/controls/colors-input-widget.tsx b/registry/widgets/controls/colors-input-widget.tsx index ef0a372..50501b4 100644 --- a/registry/widgets/controls/colors-input-widget.tsx +++ b/registry/widgets/controls/colors-input-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * ColorsInput widget - multi-value color input. * diff --git a/registry/widgets/controls/combobox-widget.tsx b/registry/widgets/controls/combobox-widget.tsx index b15996b..5140965 100644 --- a/registry/widgets/controls/combobox-widget.tsx +++ b/registry/widgets/controls/combobox-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Combobox widget - text input with autocomplete suggestions. * diff --git a/registry/widgets/controls/controller-axis-widget.tsx b/registry/widgets/controls/controller-axis-widget.tsx index a085465..ba219b0 100644 --- a/registry/widgets/controls/controller-axis-widget.tsx +++ b/registry/widgets/controls/controller-axis-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * ControllerAxis widget - displays a gamepad axis value. * diff --git a/registry/widgets/controls/controller-button-widget.tsx b/registry/widgets/controls/controller-button-widget.tsx index a2c95b7..e664a81 100644 --- a/registry/widgets/controls/controller-button-widget.tsx +++ b/registry/widgets/controls/controller-button-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * ControllerButton widget - displays a gamepad button state. * diff --git a/registry/widgets/controls/controller-widget.tsx b/registry/widgets/controls/controller-widget.tsx index 1dea77a..ee25328 100644 --- a/registry/widgets/controls/controller-widget.tsx +++ b/registry/widgets/controls/controller-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Controller widget - gamepad input via Web Gamepad API. * diff --git a/registry/widgets/controls/date-picker-widget.tsx b/registry/widgets/controls/date-picker-widget.tsx index 5d73575..7636818 100644 --- a/registry/widgets/controls/date-picker-widget.tsx +++ b/registry/widgets/controls/date-picker-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * DatePicker widget - renders a date input field. * diff --git a/registry/widgets/controls/datetime-widget.tsx b/registry/widgets/controls/datetime-widget.tsx index db64a15..1e627d4 100644 --- a/registry/widgets/controls/datetime-widget.tsx +++ b/registry/widgets/controls/datetime-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Datetime widget - renders a datetime-local input field. * diff --git a/registry/widgets/controls/dropdown-widget.tsx b/registry/widgets/controls/dropdown-widget.tsx index e788363..788d364 100644 --- a/registry/widgets/controls/dropdown-widget.tsx +++ b/registry/widgets/controls/dropdown-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Dropdown widget - renders a native select dropdown. * diff --git a/registry/widgets/controls/file-upload-widget.tsx b/registry/widgets/controls/file-upload-widget.tsx index 75f5fe5..e0c7f82 100644 --- a/registry/widgets/controls/file-upload-widget.tsx +++ b/registry/widgets/controls/file-upload-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * FileUpload widget - file upload button. * diff --git a/registry/widgets/controls/float-log-slider.tsx b/registry/widgets/controls/float-log-slider.tsx index 2e88492..08d617c 100644 --- a/registry/widgets/controls/float-log-slider.tsx +++ b/registry/widgets/controls/float-log-slider.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * FloatLogSlider widget - renders a logarithmic scale slider. * diff --git a/registry/widgets/controls/float-progress.tsx b/registry/widgets/controls/float-progress.tsx index ce1d681..6a4b8c3 100644 --- a/registry/widgets/controls/float-progress.tsx +++ b/registry/widgets/controls/float-progress.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * FloatProgress widget - renders a floating point progress bar. * diff --git a/registry/widgets/controls/float-range-slider.tsx b/registry/widgets/controls/float-range-slider.tsx index 7ab5456..ecdda79 100644 --- a/registry/widgets/controls/float-range-slider.tsx +++ b/registry/widgets/controls/float-range-slider.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * FloatRangeSlider widget - renders a dual-handle range slider for floats. * diff --git a/registry/widgets/controls/float-slider.tsx b/registry/widgets/controls/float-slider.tsx index 0d89356..5a3de2b 100644 --- a/registry/widgets/controls/float-slider.tsx +++ b/registry/widgets/controls/float-slider.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * FloatSlider widget - renders a floating point slider. * diff --git a/registry/widgets/controls/float-text-widget.tsx b/registry/widgets/controls/float-text-widget.tsx index d707646..27b7f52 100644 --- a/registry/widgets/controls/float-text-widget.tsx +++ b/registry/widgets/controls/float-text-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * FloatText widget - renders a numeric text input for floats. * diff --git a/registry/widgets/controls/floats-input-widget.tsx b/registry/widgets/controls/floats-input-widget.tsx index 9349713..6557fbe 100644 --- a/registry/widgets/controls/floats-input-widget.tsx +++ b/registry/widgets/controls/floats-input-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * FloatsInput widget - multi-value float tag input. * diff --git a/registry/widgets/controls/gridbox-widget.tsx b/registry/widgets/controls/gridbox-widget.tsx index 71d414d..f6a4cbe 100644 --- a/registry/widgets/controls/gridbox-widget.tsx +++ b/registry/widgets/controls/gridbox-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * GridBox widget - CSS grid container. * diff --git a/registry/widgets/controls/hbox-widget.tsx b/registry/widgets/controls/hbox-widget.tsx index cca35ad..7a7e2d2 100644 --- a/registry/widgets/controls/hbox-widget.tsx +++ b/registry/widgets/controls/hbox-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * HBox widget - horizontal flex container. * diff --git a/registry/widgets/controls/html-math-widget.tsx b/registry/widgets/controls/html-math-widget.tsx index a642563..349710b 100644 --- a/registry/widgets/controls/html-math-widget.tsx +++ b/registry/widgets/controls/html-math-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * HTMLMath widget - renders HTML content with LaTeX math support. * diff --git a/registry/widgets/controls/html-widget.tsx b/registry/widgets/controls/html-widget.tsx index 0abcb21..f56e917 100644 --- a/registry/widgets/controls/html-widget.tsx +++ b/registry/widgets/controls/html-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * HTML widget - renders arbitrary HTML content. * diff --git a/registry/widgets/controls/image-widget.tsx b/registry/widgets/controls/image-widget.tsx index f4767c0..269d121 100644 --- a/registry/widgets/controls/image-widget.tsx +++ b/registry/widgets/controls/image-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Image widget - displays images from the kernel. * diff --git a/registry/widgets/controls/index.ts b/registry/widgets/controls/index.ts index b70abb1..e6b3c49 100644 --- a/registry/widgets/controls/index.ts +++ b/registry/widgets/controls/index.ts @@ -1,10 +1,3 @@ -/** - * Built-in widget components for @jupyter-widgets/controls. - * - * This module registers all built-in widget components with the widget registry. - * Import this module to enable rendering of standard ipywidgets. - */ - import { registerWidget } from "../widget-registry"; import { AccordionWidget } from "./accordion-widget"; import { AudioWidget } from "./audio-widget"; diff --git a/registry/widgets/controls/int-progress.tsx b/registry/widgets/controls/int-progress.tsx index 7edc0b4..a0e4f0b 100644 --- a/registry/widgets/controls/int-progress.tsx +++ b/registry/widgets/controls/int-progress.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * IntProgress widget - renders an integer progress bar. * diff --git a/registry/widgets/controls/int-range-slider.tsx b/registry/widgets/controls/int-range-slider.tsx index a6122f3..36a9913 100644 --- a/registry/widgets/controls/int-range-slider.tsx +++ b/registry/widgets/controls/int-range-slider.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * IntRangeSlider widget - renders a dual-handle range slider for integers. * diff --git a/registry/widgets/controls/int-slider.tsx b/registry/widgets/controls/int-slider.tsx index de28597..cf73b82 100644 --- a/registry/widgets/controls/int-slider.tsx +++ b/registry/widgets/controls/int-slider.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * IntSlider widget - renders an integer slider. * diff --git a/registry/widgets/controls/int-text-widget.tsx b/registry/widgets/controls/int-text-widget.tsx index 4978b2e..1a41c08 100644 --- a/registry/widgets/controls/int-text-widget.tsx +++ b/registry/widgets/controls/int-text-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * IntText widget - renders a numeric text input for integers. * diff --git a/registry/widgets/controls/ints-input-widget.tsx b/registry/widgets/controls/ints-input-widget.tsx index 45aa1c2..88a3795 100644 --- a/registry/widgets/controls/ints-input-widget.tsx +++ b/registry/widgets/controls/ints-input-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * IntsInput widget - multi-value integer tag input. * diff --git a/registry/widgets/controls/label-widget.tsx b/registry/widgets/controls/label-widget.tsx index 8155aa4..509a6c6 100644 --- a/registry/widgets/controls/label-widget.tsx +++ b/registry/widgets/controls/label-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Label widget - renders plain text content. * diff --git a/registry/widgets/controls/link-widget.tsx b/registry/widgets/controls/link-widget.tsx index ddba0df..b36d1dc 100644 --- a/registry/widgets/controls/link-widget.tsx +++ b/registry/widgets/controls/link-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Link widgets — frontend-only property synchronization. * diff --git a/registry/widgets/controls/output-widget.tsx b/registry/widgets/controls/output-widget.tsx index 2cb3d23..2b95185 100644 --- a/registry/widgets/controls/output-widget.tsx +++ b/registry/widgets/controls/output-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Output widget - renders captured Jupyter outputs. * @@ -17,8 +15,8 @@ */ import { useEffect, useRef, useState } from "react"; -import { cn } from "@/lib/utils"; import { type JupyterOutput, OutputArea } from "@/registry/cell/OutputArea"; +import { cn } from "@/lib/utils"; import type { WidgetComponentProps } from "../widget-registry"; import { useWidgetModelValue, diff --git a/registry/widgets/controls/password-widget.tsx b/registry/widgets/controls/password-widget.tsx index 88886b5..ae39f1b 100644 --- a/registry/widgets/controls/password-widget.tsx +++ b/registry/widgets/controls/password-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Password widget - renders a masked text input field. * diff --git a/registry/widgets/controls/play-widget.tsx b/registry/widgets/controls/play-widget.tsx index e8f6b00..7ce58d1 100644 --- a/registry/widgets/controls/play-widget.tsx +++ b/registry/widgets/controls/play-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Play widget - animation control with play/pause/step. * diff --git a/registry/widgets/controls/radio-buttons-widget.tsx b/registry/widgets/controls/radio-buttons-widget.tsx index 20c1743..9c4b6f5 100644 --- a/registry/widgets/controls/radio-buttons-widget.tsx +++ b/registry/widgets/controls/radio-buttons-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * RadioButtons widget - renders a group of radio buttons. * diff --git a/registry/widgets/controls/select-multiple-widget.tsx b/registry/widgets/controls/select-multiple-widget.tsx index 22ada8e..bcfbd4d 100644 --- a/registry/widgets/controls/select-multiple-widget.tsx +++ b/registry/widgets/controls/select-multiple-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * SelectMultiple widget - renders a multi-select listbox. * diff --git a/registry/widgets/controls/select-widget.tsx b/registry/widgets/controls/select-widget.tsx index 7153185..5cbe168 100644 --- a/registry/widgets/controls/select-widget.tsx +++ b/registry/widgets/controls/select-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Select widget - renders a single-selection listbox. * diff --git a/registry/widgets/controls/selection-range-slider-widget.tsx b/registry/widgets/controls/selection-range-slider-widget.tsx index da6a609..f0a2ff1 100644 --- a/registry/widgets/controls/selection-range-slider-widget.tsx +++ b/registry/widgets/controls/selection-range-slider-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * SelectionRangeSlider widget - range slider that selects from discrete options. * diff --git a/registry/widgets/controls/selection-slider-widget.tsx b/registry/widgets/controls/selection-slider-widget.tsx index a5e42fc..3048494 100644 --- a/registry/widgets/controls/selection-slider-widget.tsx +++ b/registry/widgets/controls/selection-slider-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * SelectionSlider widget - slider that selects from discrete options. * diff --git a/registry/widgets/controls/stack-widget.tsx b/registry/widgets/controls/stack-widget.tsx index c10b229..ec401ec 100644 --- a/registry/widgets/controls/stack-widget.tsx +++ b/registry/widgets/controls/stack-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Stack widget - single-child container showing one child at a time. * diff --git a/registry/widgets/controls/tab-widget.tsx b/registry/widgets/controls/tab-widget.tsx index 6789a62..967d3a7 100644 --- a/registry/widgets/controls/tab-widget.tsx +++ b/registry/widgets/controls/tab-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Tab widget - tabbed panel container. * diff --git a/registry/widgets/controls/tags-input-widget.tsx b/registry/widgets/controls/tags-input-widget.tsx index 80228d6..744de12 100644 --- a/registry/widgets/controls/tags-input-widget.tsx +++ b/registry/widgets/controls/tags-input-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * TagsInput widget - multi-value string tag input. * diff --git a/registry/widgets/controls/text-widget.tsx b/registry/widgets/controls/text-widget.tsx index 40bfcb4..2a38a53 100644 --- a/registry/widgets/controls/text-widget.tsx +++ b/registry/widgets/controls/text-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Text widget - renders a text input field. * diff --git a/registry/widgets/controls/textarea-widget.tsx b/registry/widgets/controls/textarea-widget.tsx index 2cf7fee..99f7989 100644 --- a/registry/widgets/controls/textarea-widget.tsx +++ b/registry/widgets/controls/textarea-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Textarea widget - renders a multi-line text input. * diff --git a/registry/widgets/controls/time-picker-widget.tsx b/registry/widgets/controls/time-picker-widget.tsx index 8a33b1f..0443f9d 100644 --- a/registry/widgets/controls/time-picker-widget.tsx +++ b/registry/widgets/controls/time-picker-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * TimePicker widget - renders a time input field. * diff --git a/registry/widgets/controls/toggle-button-widget.tsx b/registry/widgets/controls/toggle-button-widget.tsx index 2659567..28a665f 100644 --- a/registry/widgets/controls/toggle-button-widget.tsx +++ b/registry/widgets/controls/toggle-button-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * ToggleButton widget - renders a single toggle button. * diff --git a/registry/widgets/controls/toggle-buttons-widget.tsx b/registry/widgets/controls/toggle-buttons-widget.tsx index 0a4e567..edec4ab 100644 --- a/registry/widgets/controls/toggle-buttons-widget.tsx +++ b/registry/widgets/controls/toggle-buttons-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * ToggleButtons widget - renders a group of toggle buttons (single selection). * diff --git a/registry/widgets/controls/valid-widget.tsx b/registry/widgets/controls/valid-widget.tsx index 70fafd5..af0a584 100644 --- a/registry/widgets/controls/valid-widget.tsx +++ b/registry/widgets/controls/valid-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Valid widget - displays a validation indicator (checkmark or X). * diff --git a/registry/widgets/controls/vbox-widget.tsx b/registry/widgets/controls/vbox-widget.tsx index 879a837..ea1239d 100644 --- a/registry/widgets/controls/vbox-widget.tsx +++ b/registry/widgets/controls/vbox-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * VBox widget - vertical flex container. * diff --git a/registry/widgets/controls/video-widget.tsx b/registry/widgets/controls/video-widget.tsx index 37599e3..206f11c 100644 --- a/registry/widgets/controls/video-widget.tsx +++ b/registry/widgets/controls/video-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * Video widget - plays video from the kernel. * From 64d2824ff187d827aafb0486379484505a99d958 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 09:52:30 -0800 Subject: [PATCH 07/13] sync(widgets/ipycanvas): update ipycanvas from desktop Syncs ipycanvas widget components from desktop app. --- registry/widgets/ipycanvas/canvas-widget.tsx | 2 -- registry/widgets/ipycanvas/index.ts | 7 ------- 2 files changed, 9 deletions(-) diff --git a/registry/widgets/ipycanvas/canvas-widget.tsx b/registry/widgets/ipycanvas/canvas-widget.tsx index dbca5e0..043507d 100644 --- a/registry/widgets/ipycanvas/canvas-widget.tsx +++ b/registry/widgets/ipycanvas/canvas-widget.tsx @@ -1,5 +1,3 @@ -"use client"; - /** * ipycanvas Canvas widget. * diff --git a/registry/widgets/ipycanvas/index.ts b/registry/widgets/ipycanvas/index.ts index 89297db..74167d5 100644 --- a/registry/widgets/ipycanvas/index.ts +++ b/registry/widgets/ipycanvas/index.ts @@ -1,10 +1,3 @@ -/** - * ipycanvas widget registration. - * - * Registers CanvasModel and CanvasManagerModel with the widget registry. - * Import this module to enable rendering of ipycanvas widgets. - */ - import { registerWidget } from "../widget-registry"; import { CanvasManagerWidget, CanvasWidget } from "./canvas-widget"; From e89a9edbd8ca871a1995fbce68a34fc79419e1c5 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 09:55:59 -0800 Subject: [PATCH 08/13] registry: add highlight-text to registry dependencies Adds highlight-text as a registry component and includes it as a dependency of output-area for search highlighting functionality. --- registry.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/registry.json b/registry.json index 0c939c8..0adac32 100644 --- a/registry.json +++ b/registry.json @@ -345,7 +345,8 @@ "@nteract/isolated-frame", "@nteract/widget-store", "@nteract/markdown-output", - "@nteract/error-boundary" + "@nteract/error-boundary", + "@nteract/highlight-text" ], "files": [ { @@ -948,6 +949,19 @@ } ] }, + { + "name": "highlight-text", + "type": "registry:lib", + "title": "Highlight Text", + "description": "DOM utility for highlighting search matches in text content with customizable styling.", + "files": [ + { + "path": "registry/lib/highlight-text.ts", + "type": "registry:lib", + "target": "lib/highlight-text.ts" + } + ] + }, { "name": "isolated-renderer", "type": "registry:component", From 31746c74c75e50cf5ef35d39d2979d949ec81a89 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 10:11:09 -0800 Subject: [PATCH 09/13] docs: restore module-level documentation comments Preserves the module-level JSDoc comments that document the purpose and usage of each module. These were accidentally overwritten during the desktop sync. Restored comments in: - comm-bridge-manager.ts: parent-side comm bridge overview - frame-bridge.ts: message protocol types description - frame-html.ts: HTML template generator and security notes - buffer-utils.ts: Jupyter buffer_paths protocol documentation - canvas-manager-subscriptions.ts: ipycanvas routing explanation - button-style-utils.ts: shadcn button style mapping - link-subscriptions.ts: jslink/jsdlink subscription pattern - widget-registry.ts: model name to component mapping - widget-store.ts: React widget store architecture --- .../outputs/isolated/comm-bridge-manager.ts | 14 ++++++++++ registry/outputs/isolated/frame-bridge.ts | 13 ++++++++++ registry/outputs/isolated/frame-html.ts | 11 ++++++++ registry/widgets/buffer-utils.ts | 26 +++++++++++++++++++ .../widgets/canvas-manager-subscriptions.ts | 19 ++++++++++++++ .../widgets/controls/button-style-utils.ts | 10 +++++++ registry/widgets/link-subscriptions.ts | 17 ++++++++++++ registry/widgets/widget-registry.ts | 6 +++++ registry/widgets/widget-store.ts | 9 +++++++ 9 files changed, 125 insertions(+) diff --git a/registry/outputs/isolated/comm-bridge-manager.ts b/registry/outputs/isolated/comm-bridge-manager.ts index 73d7234..5c95e40 100644 --- a/registry/outputs/isolated/comm-bridge-manager.ts +++ b/registry/outputs/isolated/comm-bridge-manager.ts @@ -1,3 +1,17 @@ +/** + * Comm Bridge Manager - Parent Side + * + * This module manages the communication bridge between the parent window's + * widget system and an isolated iframe. It: + * - Buffers comm messages until iframe sends `widget_ready` + * - Syncs all existing widget models to iframe on ready + * - Forwards comm messages from kernel to iframe + * - Handles widget messages from iframe and updates parent store + kernel + * + * Security: The iframe cannot access Tauri APIs directly. All widget + * communication must go through this controlled postMessage bridge. + */ + import type { WidgetStore } from "@/registry/widgets/widget-store"; import type { CommCloseMessage, diff --git a/registry/outputs/isolated/frame-bridge.ts b/registry/outputs/isolated/frame-bridge.ts index 6344a63..3cfa119 100644 --- a/registry/outputs/isolated/frame-bridge.ts +++ b/registry/outputs/isolated/frame-bridge.ts @@ -1,3 +1,16 @@ +/** + * Message protocol types for parent ↔ iframe communication. + * + * This module defines the contract between the parent window and isolated output frames. + * All communication happens via postMessage with structured message types. + */ + +// --- Message Types: Parent → Iframe --- + +/** + * Bootstrap the iframe with JavaScript code. + * Used to inject the ESM renderer bundle into the iframe. + */ export interface EvalMessage { type: "eval"; payload: { diff --git a/registry/outputs/isolated/frame-html.ts b/registry/outputs/isolated/frame-html.ts index b9a77ba..4e9aa8d 100644 --- a/registry/outputs/isolated/frame-html.ts +++ b/registry/outputs/isolated/frame-html.ts @@ -1,3 +1,14 @@ +/** + * HTML template generator for isolated output frames. + * + * Creates the minimal HTML document that runs inside the blob URL iframe. + * This document handles the message protocol and provides a render target + * for output content. + * + * Security: This code runs in an isolated origin (blob:) with sandbox + * restrictions, so it cannot access Tauri APIs or the parent DOM. + */ + export interface FrameHtmlOptions { /** * Whether to include dark mode styles by default. diff --git a/registry/widgets/buffer-utils.ts b/registry/widgets/buffer-utils.ts index 4b06ae0..71aa786 100644 --- a/registry/widgets/buffer-utils.ts +++ b/registry/widgets/buffer-utils.ts @@ -1,3 +1,29 @@ +/** + * Buffer path utilities for Jupyter widget protocol. + * + * Handles the buffer_paths field in comm messages which specifies + * where binary buffers should be inserted into the JSON message data. + * + * @see https://jupyter-widgets.readthedocs.io/en/latest/examples/Widget%20Low%20Level.html + */ + +/** + * Apply buffers to message data at specified paths. + * + * The Jupyter widget protocol sends binary data separately from JSON. + * The buffer_paths field specifies where each buffer should be inserted. + * + * @example + * // buffer_paths: [["state", "data"], ["content", "blob"]] + * // buffers: [ArrayBuffer1, ArrayBuffer2] + * // data: { state: {}, content: {} } + * // Result: { state: { data: ArrayBuffer1 }, content: { blob: ArrayBuffer2 } } + * + * @param data - The message data object to modify (mutated in place) + * @param bufferPaths - Array of paths, each path is an array of keys + * @param buffers - Array of buffers to insert at the corresponding paths + * @returns The modified data object (same reference as input) + */ export function applyBufferPaths( data: Record, bufferPaths: string[][] | undefined, diff --git a/registry/widgets/canvas-manager-subscriptions.ts b/registry/widgets/canvas-manager-subscriptions.ts index fc895e4..55b93e4 100644 --- a/registry/widgets/canvas-manager-subscriptions.ts +++ b/registry/widgets/canvas-manager-subscriptions.ts @@ -1,3 +1,22 @@ +/** + * Store-level routing for ipycanvas CanvasManagerModel. + * + * CanvasManagerModel is a headless widget (_view_name: null) that receives + * ALL drawing commands from Python. This module subscribes to each manager's + * custom messages, parses switchCanvas targets, and re-emits to each target + * canvas's comm_id — isolating canvases from each other. + * + * Same pattern as link-subscriptions.ts for LinkModel/DirectionalLinkModel. + * + * Usage: + * const cleanup = createCanvasManagerRouter(store); + * // ... later, to tear down all routing: + * cleanup(); + * + * WidgetStoreProvider calls this automatically. For non-React integrations + * (e.g. iframe isolation), call createCanvasManagerRouter directly. + */ + import type { WidgetStore } from "./widget-store"; // ipycanvas drawing command names indexed by protocol number. diff --git a/registry/widgets/controls/button-style-utils.ts b/registry/widgets/controls/button-style-utils.ts index 6f77386..b2bf71c 100644 --- a/registry/widgets/controls/button-style-utils.ts +++ b/registry/widgets/controls/button-style-utils.ts @@ -1,3 +1,13 @@ +/** + * Shared utility for mapping ipywidgets button_style to shadcn Button + * variant + Tailwind className overrides. + * + * The shadcn Button only has default, destructive, outline, secondary, ghost, + * link variants — no info/success/warning. We use the "default" variant as a + * base and apply Tailwind color classes via className. tailwind-merge resolves + * the conflict in favor of our overrides. + */ + type ButtonStyleVariant = "default" | "destructive" | "outline"; interface ButtonStyleResult { diff --git a/registry/widgets/link-subscriptions.ts b/registry/widgets/link-subscriptions.ts index 3f90918..0942498 100644 --- a/registry/widgets/link-subscriptions.ts +++ b/registry/widgets/link-subscriptions.ts @@ -1,3 +1,20 @@ +/** + * Store-level link subscriptions for frontend-only property synchronization. + * + * Manages LinkModel (jslink) and DirectionalLinkModel (jsdlink) at the + * store level so links work without React component mounting. This is + * critical because link widgets are headless (_view_name: null) and won't + * appear in any container widget's children. + * + * Usage: + * const cleanup = createLinkManager(store); + * // ... later, to tear down all links: + * cleanup(); + * + * WidgetStoreProvider calls this automatically. For non-React integrations + * (e.g. iframe isolation), call createLinkManager directly. + */ + import { parseModelRef, type WidgetStore } from "./widget-store"; /** diff --git a/registry/widgets/widget-registry.ts b/registry/widgets/widget-registry.ts index e9110fd..06690ce 100644 --- a/registry/widgets/widget-registry.ts +++ b/registry/widgets/widget-registry.ts @@ -1,3 +1,9 @@ +/** + * Registry mapping widget model names to React components. + * + * This maps _model_name from ipywidgets to our shadcn-backed implementations. + */ + import type { ComponentType } from "react"; export interface WidgetComponentProps { diff --git a/registry/widgets/widget-store.ts b/registry/widgets/widget-store.ts index de1d97e..f7f0a67 100644 --- a/registry/widgets/widget-store.ts +++ b/registry/widgets/widget-store.ts @@ -1,3 +1,12 @@ +/** + * Pure React widget model store for Jupyter widgets. + * + * This replaces the Backbone.js-based model system from @jupyter-widgets/html-manager + * with a pure JavaScript store that integrates with React via useSyncExternalStore. + */ + +// === Types === + export interface WidgetModel { /** comm_id from the Jupyter protocol */ id: string; From e2eb73f95aaeaabab05af8074a6b1aae495d3ea1 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 10:47:16 -0800 Subject: [PATCH 10/13] fix: add "use client" directive for Next.js App Router compatibility Components using React hooks (useState, useEffect, useContext) require the "use client" directive for Next.js App Router. The desktop app had removed these directives but they're needed for the elements registry. Fixes build error: "You're importing a component that needs useState. This React Hook only works in a Client Component." --- registry/outputs/html-output.tsx | 2 ++ registry/outputs/json-output.tsx | 2 ++ registry/outputs/markdown-output.tsx | 2 ++ registry/outputs/media-provider.tsx | 2 ++ registry/outputs/svg-output.tsx | 2 ++ registry/widgets/anywidget-view.tsx | 2 ++ registry/widgets/controls/bounded-float-text-widget.tsx | 2 ++ registry/widgets/controls/bounded-int-text-widget.tsx | 2 ++ registry/widgets/controls/colors-input-widget.tsx | 2 ++ registry/widgets/controls/combobox-widget.tsx | 2 ++ registry/widgets/controls/controller-widget.tsx | 2 ++ registry/widgets/controls/float-text-widget.tsx | 2 ++ registry/widgets/controls/floats-input-widget.tsx | 2 ++ registry/widgets/controls/int-text-widget.tsx | 2 ++ registry/widgets/controls/ints-input-widget.tsx | 2 ++ registry/widgets/controls/output-widget.tsx | 2 ++ registry/widgets/controls/password-widget.tsx | 2 ++ registry/widgets/controls/play-widget.tsx | 2 ++ registry/widgets/controls/tags-input-widget.tsx | 2 ++ registry/widgets/controls/text-widget.tsx | 2 ++ registry/widgets/controls/textarea-widget.tsx | 2 ++ registry/widgets/widget-store-context.tsx | 2 ++ 22 files changed, 44 insertions(+) diff --git a/registry/outputs/html-output.tsx b/registry/outputs/html-output.tsx index 32d8c97..59de859 100644 --- a/registry/outputs/html-output.tsx +++ b/registry/outputs/html-output.tsx @@ -1,3 +1,5 @@ +"use client"; + import { useEffect, useRef } from "react"; import { cn } from "@/lib/utils"; diff --git a/registry/outputs/json-output.tsx b/registry/outputs/json-output.tsx index bfa7f6e..db28afa 100644 --- a/registry/outputs/json-output.tsx +++ b/registry/outputs/json-output.tsx @@ -1,3 +1,5 @@ +"use client"; + import { ChevronRightIcon } from "lucide-react"; import { createContext, diff --git a/registry/outputs/markdown-output.tsx b/registry/outputs/markdown-output.tsx index 2e40f3a..1398d78 100644 --- a/registry/outputs/markdown-output.tsx +++ b/registry/outputs/markdown-output.tsx @@ -1,3 +1,5 @@ +"use client"; + import { Check, Copy } from "lucide-react"; import { useState } from "react"; import ReactMarkdown from "react-markdown"; diff --git a/registry/outputs/media-provider.tsx b/registry/outputs/media-provider.tsx index d4e8bdb..39c1af9 100644 --- a/registry/outputs/media-provider.tsx +++ b/registry/outputs/media-provider.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * React context provider for shared media rendering configuration. * diff --git a/registry/outputs/svg-output.tsx b/registry/outputs/svg-output.tsx index b98b425..b110cd6 100644 --- a/registry/outputs/svg-output.tsx +++ b/registry/outputs/svg-output.tsx @@ -1,3 +1,5 @@ +"use client"; + import { useEffect, useRef } from "react"; import { cn } from "@/lib/utils"; diff --git a/registry/widgets/anywidget-view.tsx b/registry/widgets/anywidget-view.tsx index 25b7af2..ef04bb7 100644 --- a/registry/widgets/anywidget-view.tsx +++ b/registry/widgets/anywidget-view.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * anywidget ESM loader and AFM (AnyWidget Frontend Module) interface. * diff --git a/registry/widgets/controls/bounded-float-text-widget.tsx b/registry/widgets/controls/bounded-float-text-widget.tsx index 23c4178..2196499 100644 --- a/registry/widgets/controls/bounded-float-text-widget.tsx +++ b/registry/widgets/controls/bounded-float-text-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * BoundedFloatText widget - renders a bounded numeric text input for floats. * diff --git a/registry/widgets/controls/bounded-int-text-widget.tsx b/registry/widgets/controls/bounded-int-text-widget.tsx index 72dbe50..9d56b3b 100644 --- a/registry/widgets/controls/bounded-int-text-widget.tsx +++ b/registry/widgets/controls/bounded-int-text-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * BoundedIntText widget - renders a bounded numeric text input for integers. * diff --git a/registry/widgets/controls/colors-input-widget.tsx b/registry/widgets/controls/colors-input-widget.tsx index 50501b4..ef0a372 100644 --- a/registry/widgets/controls/colors-input-widget.tsx +++ b/registry/widgets/controls/colors-input-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * ColorsInput widget - multi-value color input. * diff --git a/registry/widgets/controls/combobox-widget.tsx b/registry/widgets/controls/combobox-widget.tsx index 5140965..b15996b 100644 --- a/registry/widgets/controls/combobox-widget.tsx +++ b/registry/widgets/controls/combobox-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * Combobox widget - text input with autocomplete suggestions. * diff --git a/registry/widgets/controls/controller-widget.tsx b/registry/widgets/controls/controller-widget.tsx index ee25328..1dea77a 100644 --- a/registry/widgets/controls/controller-widget.tsx +++ b/registry/widgets/controls/controller-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * Controller widget - gamepad input via Web Gamepad API. * diff --git a/registry/widgets/controls/float-text-widget.tsx b/registry/widgets/controls/float-text-widget.tsx index 27b7f52..d707646 100644 --- a/registry/widgets/controls/float-text-widget.tsx +++ b/registry/widgets/controls/float-text-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * FloatText widget - renders a numeric text input for floats. * diff --git a/registry/widgets/controls/floats-input-widget.tsx b/registry/widgets/controls/floats-input-widget.tsx index 6557fbe..9349713 100644 --- a/registry/widgets/controls/floats-input-widget.tsx +++ b/registry/widgets/controls/floats-input-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * FloatsInput widget - multi-value float tag input. * diff --git a/registry/widgets/controls/int-text-widget.tsx b/registry/widgets/controls/int-text-widget.tsx index 1a41c08..4978b2e 100644 --- a/registry/widgets/controls/int-text-widget.tsx +++ b/registry/widgets/controls/int-text-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * IntText widget - renders a numeric text input for integers. * diff --git a/registry/widgets/controls/ints-input-widget.tsx b/registry/widgets/controls/ints-input-widget.tsx index 88a3795..45aa1c2 100644 --- a/registry/widgets/controls/ints-input-widget.tsx +++ b/registry/widgets/controls/ints-input-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * IntsInput widget - multi-value integer tag input. * diff --git a/registry/widgets/controls/output-widget.tsx b/registry/widgets/controls/output-widget.tsx index 2b95185..f7e8928 100644 --- a/registry/widgets/controls/output-widget.tsx +++ b/registry/widgets/controls/output-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * Output widget - renders captured Jupyter outputs. * diff --git a/registry/widgets/controls/password-widget.tsx b/registry/widgets/controls/password-widget.tsx index ae39f1b..88886b5 100644 --- a/registry/widgets/controls/password-widget.tsx +++ b/registry/widgets/controls/password-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * Password widget - renders a masked text input field. * diff --git a/registry/widgets/controls/play-widget.tsx b/registry/widgets/controls/play-widget.tsx index 7ce58d1..e8f6b00 100644 --- a/registry/widgets/controls/play-widget.tsx +++ b/registry/widgets/controls/play-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * Play widget - animation control with play/pause/step. * diff --git a/registry/widgets/controls/tags-input-widget.tsx b/registry/widgets/controls/tags-input-widget.tsx index 744de12..80228d6 100644 --- a/registry/widgets/controls/tags-input-widget.tsx +++ b/registry/widgets/controls/tags-input-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * TagsInput widget - multi-value string tag input. * diff --git a/registry/widgets/controls/text-widget.tsx b/registry/widgets/controls/text-widget.tsx index 2a38a53..40bfcb4 100644 --- a/registry/widgets/controls/text-widget.tsx +++ b/registry/widgets/controls/text-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * Text widget - renders a text input field. * diff --git a/registry/widgets/controls/textarea-widget.tsx b/registry/widgets/controls/textarea-widget.tsx index 99f7989..2cf7fee 100644 --- a/registry/widgets/controls/textarea-widget.tsx +++ b/registry/widgets/controls/textarea-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * Textarea widget - renders a multi-line text input. * diff --git a/registry/widgets/widget-store-context.tsx b/registry/widgets/widget-store-context.tsx index 4b6f5c7..69d8434 100644 --- a/registry/widgets/widget-store-context.tsx +++ b/registry/widgets/widget-store-context.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * React context and hooks for the widget model store. * From 2c8b691973f981d47d1e7eb8f195a8a337d2be04 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 10:55:18 -0800 Subject: [PATCH 11/13] fix: restore remaining "use client" directives and JSDoc comment Adds "use client" to 10 more files that were missed in the previous fix: - registry/cell/OutputArea.tsx - registry/editor/codemirror-editor.tsx - registry/outputs/isolated/IsolationTest.tsx - registry/outputs/isolated/isolated-frame.tsx - registry/outputs/isolated/isolated-renderer-context.tsx - registry/widgets/controls/date-picker-widget.tsx - registry/widgets/controls/datetime-widget.tsx - registry/widgets/controls/file-upload-widget.tsx - registry/widgets/controls/time-picker-widget.tsx - registry/widgets/ipycanvas/canvas-widget.tsx Also restores the module-level JSDoc comment for registry/widgets/controls/index.ts. --- registry/cell/OutputArea.tsx | 2 ++ registry/editor/codemirror-editor.tsx | 2 ++ registry/outputs/isolated/IsolationTest.tsx | 2 ++ registry/outputs/isolated/isolated-frame.tsx | 2 ++ registry/outputs/isolated/isolated-renderer-context.tsx | 2 ++ registry/widgets/controls/date-picker-widget.tsx | 2 ++ registry/widgets/controls/datetime-widget.tsx | 2 ++ registry/widgets/controls/file-upload-widget.tsx | 2 ++ registry/widgets/controls/index.ts | 7 +++++++ registry/widgets/controls/time-picker-widget.tsx | 2 ++ registry/widgets/ipycanvas/canvas-widget.tsx | 2 ++ 11 files changed, 27 insertions(+) diff --git a/registry/cell/OutputArea.tsx b/registry/cell/OutputArea.tsx index 82a3ae2..065eaa5 100644 --- a/registry/cell/OutputArea.tsx +++ b/registry/cell/OutputArea.tsx @@ -1,3 +1,5 @@ +"use client"; + import { ChevronDown, ChevronRight } from "lucide-react"; import { type ReactNode, diff --git a/registry/editor/codemirror-editor.tsx b/registry/editor/codemirror-editor.tsx index c76b3b7..92c85d8 100644 --- a/registry/editor/codemirror-editor.tsx +++ b/registry/editor/codemirror-editor.tsx @@ -1,3 +1,5 @@ +"use client"; + import { EditorView, type KeyBinding, diff --git a/registry/outputs/isolated/IsolationTest.tsx b/registry/outputs/isolated/IsolationTest.tsx index 5f411a9..a70fce3 100644 --- a/registry/outputs/isolated/IsolationTest.tsx +++ b/registry/outputs/isolated/IsolationTest.tsx @@ -1,3 +1,5 @@ +"use client"; + import { useEffect, useRef, useState } from "react"; import { IsolatedFrame, type IsolatedFrameHandle } from "./isolated-frame"; diff --git a/registry/outputs/isolated/isolated-frame.tsx b/registry/outputs/isolated/isolated-frame.tsx index e9fddfa..54b669e 100644 --- a/registry/outputs/isolated/isolated-frame.tsx +++ b/registry/outputs/isolated/isolated-frame.tsx @@ -1,3 +1,5 @@ +"use client"; + import { forwardRef, useCallback, diff --git a/registry/outputs/isolated/isolated-renderer-context.tsx b/registry/outputs/isolated/isolated-renderer-context.tsx index 89871c0..1a3c5fc 100644 --- a/registry/outputs/isolated/isolated-renderer-context.tsx +++ b/registry/outputs/isolated/isolated-renderer-context.tsx @@ -1,3 +1,5 @@ +"use client"; + import { createContext, type ReactNode, diff --git a/registry/widgets/controls/date-picker-widget.tsx b/registry/widgets/controls/date-picker-widget.tsx index 7636818..5d73575 100644 --- a/registry/widgets/controls/date-picker-widget.tsx +++ b/registry/widgets/controls/date-picker-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * DatePicker widget - renders a date input field. * diff --git a/registry/widgets/controls/datetime-widget.tsx b/registry/widgets/controls/datetime-widget.tsx index 1e627d4..db64a15 100644 --- a/registry/widgets/controls/datetime-widget.tsx +++ b/registry/widgets/controls/datetime-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * Datetime widget - renders a datetime-local input field. * diff --git a/registry/widgets/controls/file-upload-widget.tsx b/registry/widgets/controls/file-upload-widget.tsx index e0c7f82..75f5fe5 100644 --- a/registry/widgets/controls/file-upload-widget.tsx +++ b/registry/widgets/controls/file-upload-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * FileUpload widget - file upload button. * diff --git a/registry/widgets/controls/index.ts b/registry/widgets/controls/index.ts index e6b3c49..b70abb1 100644 --- a/registry/widgets/controls/index.ts +++ b/registry/widgets/controls/index.ts @@ -1,3 +1,10 @@ +/** + * Built-in widget components for @jupyter-widgets/controls. + * + * This module registers all built-in widget components with the widget registry. + * Import this module to enable rendering of standard ipywidgets. + */ + import { registerWidget } from "../widget-registry"; import { AccordionWidget } from "./accordion-widget"; import { AudioWidget } from "./audio-widget"; diff --git a/registry/widgets/controls/time-picker-widget.tsx b/registry/widgets/controls/time-picker-widget.tsx index 0443f9d..8a33b1f 100644 --- a/registry/widgets/controls/time-picker-widget.tsx +++ b/registry/widgets/controls/time-picker-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * TimePicker widget - renders a time input field. * diff --git a/registry/widgets/ipycanvas/canvas-widget.tsx b/registry/widgets/ipycanvas/canvas-widget.tsx index 043507d..dbca5e0 100644 --- a/registry/widgets/ipycanvas/canvas-widget.tsx +++ b/registry/widgets/ipycanvas/canvas-widget.tsx @@ -1,3 +1,5 @@ +"use client"; + /** * ipycanvas Canvas widget. * From 8027da7e0fb1be980a0ee12f43764f1df61c0719 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 11:01:59 -0800 Subject: [PATCH 12/13] style: fix import organization (biome auto-fix) --- registry/cell/CellTypeSelector.tsx | 5 +--- registry/cell/OutputArea.tsx | 23 ++++++++----------- .../outputs/isolated/comm-bridge-manager.ts | 4 +++- registry/widgets/controls/output-widget.tsx | 2 +- registry/widgets/widget-view.tsx | 2 +- 5 files changed, 16 insertions(+), 20 deletions(-) diff --git a/registry/cell/CellTypeSelector.tsx b/registry/cell/CellTypeSelector.tsx index a3a7d86..88fb923 100644 --- a/registry/cell/CellTypeSelector.tsx +++ b/registry/cell/CellTypeSelector.tsx @@ -1,8 +1,4 @@ import { Bot, ChevronDown, Code, Database, FileText } from "lucide-react"; -import { - type CellType, - cellTypeStyles, -} from "@/registry/cell/CellTypeButton"; import { Button } from "@/components/ui/button"; import { DropdownMenu, @@ -11,6 +7,7 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { cn } from "@/lib/utils"; +import { type CellType, cellTypeStyles } from "@/registry/cell/CellTypeButton"; const allCellTypes: CellType[] = ["code", "markdown", "sql", "ai"]; diff --git a/registry/cell/OutputArea.tsx b/registry/cell/OutputArea.tsx index 065eaa5..fe706b5 100644 --- a/registry/cell/OutputArea.tsx +++ b/registry/cell/OutputArea.tsx @@ -9,26 +9,23 @@ import { useRef, useState, } from "react"; +import { isDarkMode as detectDarkMode } from "@/lib/dark-mode"; +import { cn } from "@/lib/utils"; +import { ErrorBoundary } from "@/registry/lib/error-boundary"; +import { highlightTextInDom } from "@/registry/lib/highlight-text"; +import { OutputErrorFallback } from "@/registry/lib/output-error-fallback"; +import { + AnsiErrorOutput, + AnsiStreamOutput, +} from "@/registry/outputs/ansi-output"; import { CommBridgeManager, type IframeToParentMessage, IsolatedFrame, type IsolatedFrameHandle, } from "@/registry/outputs/isolated"; -import { - AnsiErrorOutput, - AnsiStreamOutput, -} from "@/registry/outputs/ansi-output"; -import { - DEFAULT_PRIORITY, - MediaRouter, -} from "@/registry/outputs/media-router"; +import { DEFAULT_PRIORITY, MediaRouter } from "@/registry/outputs/media-router"; import { useWidgetStore } from "@/registry/widgets/widget-store-context"; -import { isDarkMode as detectDarkMode } from "@/lib/dark-mode"; -import { ErrorBoundary } from "@/registry/lib/error-boundary"; -import { highlightTextInDom } from "@/registry/lib/highlight-text"; -import { OutputErrorFallback } from "@/registry/lib/output-error-fallback"; -import { cn } from "@/lib/utils"; /** * Jupyter output types based on the nbformat spec. diff --git a/registry/outputs/isolated/comm-bridge-manager.ts b/registry/outputs/isolated/comm-bridge-manager.ts index 5c95e40..45d534a 100644 --- a/registry/outputs/isolated/comm-bridge-manager.ts +++ b/registry/outputs/isolated/comm-bridge-manager.ts @@ -372,7 +372,9 @@ export class CommBridgeManager { commId, (content: Record, buffers?: DataView[]) => { // Convert DataView[] to ArrayBuffer[] for postMessage - const arrayBuffers = buffers?.map((dv: DataView) => dv.buffer as ArrayBuffer); + const arrayBuffers = buffers?.map( + (dv: DataView) => dv.buffer as ArrayBuffer, + ); // Forward custom message to iframe this.sendCommMsg(commId, "custom", content, arrayBuffers); }, diff --git a/registry/widgets/controls/output-widget.tsx b/registry/widgets/controls/output-widget.tsx index f7e8928..2cb3d23 100644 --- a/registry/widgets/controls/output-widget.tsx +++ b/registry/widgets/controls/output-widget.tsx @@ -17,8 +17,8 @@ */ import { useEffect, useRef, useState } from "react"; -import { type JupyterOutput, OutputArea } from "@/registry/cell/OutputArea"; import { cn } from "@/lib/utils"; +import { type JupyterOutput, OutputArea } from "@/registry/cell/OutputArea"; import type { WidgetComponentProps } from "../widget-registry"; import { useWidgetModelValue, diff --git a/registry/widgets/widget-view.tsx b/registry/widgets/widget-view.tsx index f3d7f3e..1d65489 100644 --- a/registry/widgets/widget-view.tsx +++ b/registry/widgets/widget-view.tsx @@ -7,8 +7,8 @@ * - Unknown widgets → UnsupportedWidget fallback */ -import { ErrorBoundary } from "@/registry/lib/error-boundary"; import { cn } from "@/lib/utils"; +import { ErrorBoundary } from "@/registry/lib/error-boundary"; import { WidgetErrorFallback } from "@/registry/lib/widget-error-fallback"; import { AnyWidgetView, isAnyWidget } from "./anywidget-view"; import { useLayoutStyles } from "./use-layout-styles"; From fa8727b47bc5b46962930e215fec8069eef483c8 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Wed, 4 Mar 2026 11:04:36 -0800 Subject: [PATCH 13/13] chore: add noAutofocus rule to biome config (sync with desktop) --- biome.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/biome.json b/biome.json index 9f2044a..a1804f6 100644 --- a/biome.json +++ b/biome.json @@ -38,7 +38,8 @@ "noSvgWithoutTitle": "off", "useButtonType": "off", "useFocusableInteractive": "off", - "useKeyWithClickEvents": "off" + "useKeyWithClickEvents": "off", + "noAutofocus": "off" }, "suspicious": { "noArrayIndexKey": "off",