Skip to content

Commit 8a45283

Browse files
authored
ct-cell-context debugging tool (commontoolsinc#2164)
* Implement `ct-cell-context` component and basic debug feature * Watch cells * Working-end-to-end * Format pass * Wrap interesting use-sites in `ct-cell-context` for testing * Add `label` to `jsx.d.ts` * Fix lint * Auto-insert into ct-render? * Automatically wrap anything with [UI] in cell-context * Format pass * Remove beads files * Write to `$cell` * Action cubic review * Add missing jsx.d.ts definition
1 parent d698bb0 commit 8a45283

File tree

21 files changed

+1075
-325
lines changed

21 files changed

+1075
-325
lines changed

packages/html/src/jsx.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2888,6 +2888,7 @@ interface CTToolbarElement extends CTHTMLElement {}
28882888
interface CTKbdElement extends CTHTMLElement {}
28892889
interface CTKeybindElement extends CTHTMLElement {}
28902890
interface CTRenderElement extends CTHTMLElement {}
2891+
interface CTCellContextElement extends CTHTMLElement {}
28912892
interface CTChatMessageElement extends CTHTMLElement {}
28922893
interface CTMarkdownElement extends CTHTMLElement {}
28932894
interface CTVScrollElement extends CTHTMLElement {}
@@ -3156,6 +3157,12 @@ interface CTRenderAttributes<T> extends CTHTMLAttributes<T> {
31563157
"$cell": CellLike<any>;
31573158
}
31583159

3160+
interface CTCellContextAttributes<T> extends CTHTMLAttributes<T> {
3161+
"$cell": CellLike<any>;
3162+
"label"?: string;
3163+
"inline"?: boolean;
3164+
}
3165+
31593166
interface CTListAttributes<T> extends CTHTMLAttributes<T> {
31603167
"$value": CellLike<CtListItem[]>;
31613168
/** setting this allows editing items inline */
@@ -3879,6 +3886,10 @@ declare global {
38793886
CTRenderAttributes<CTRenderElement>,
38803887
CTRenderElement
38813888
>;
3889+
"ct-cell-context": CTDOM.DetailedHTMLProps<
3890+
CTCellContextAttributes<CTCellContextElement>,
3891+
CTCellContextElement
3892+
>;
38823893
"ct-vscroll": CTDOM.DetailedHTMLProps<
38833894
CTScrollAttributes<CTVScrollElement>,
38843895
CTVScrollElement

packages/html/src/render.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export type SetPropHandler = <T>(
2121
export interface RenderOptions {
2222
setProp?: SetPropHandler;
2323
document?: Document;
24+
/** The root cell for auto-wrapping with ct-cell-context on [UI] traversal */
25+
rootCell?: Cell;
2426
}
2527

2628
export const vdomSchema: JSONSchema = {
@@ -63,13 +65,20 @@ export const render = (
6365
): Cancel => {
6466
// Initialize visited set with the original cell for cycle detection
6567
const visited = new Set<object>();
68+
let rootCell: Cell | undefined;
69+
6670
if (isCell(view)) {
6771
visited.add(view);
72+
rootCell = view; // Capture the original cell for ct-cell-context wrapping
6873
view = view.asSchema(vdomSchema);
6974
}
75+
76+
// Pass rootCell through options if we have one
77+
const optionsWithCell = rootCell ? { ...options, rootCell } : options;
78+
7079
return effect(
7180
view,
72-
(view: VNode) => renderImpl(parent, view, options, visited),
81+
(view: VNode) => renderImpl(parent, view, optionsWithCell, visited),
7382
);
7483
};
7584

@@ -141,6 +150,10 @@ const renderNode = (
141150

142151
const document = options.document ?? globalThis.document;
143152

153+
// Check if we should wrap with ct-cell-context (when traversing [UI] with a rootCell)
154+
const shouldWrapWithContext = node[UI] && options.rootCell;
155+
const cellForContext = shouldWrapWithContext ? options.rootCell : undefined;
156+
144157
// Follow `[UI]` to actual vdom. Do this before otherwise parsing the vnode,
145158
// so that if there are both, the `[UI]` annotation takes precedence (avoids
146159
// accidental collision with the otherwise quite generic property names)
@@ -190,6 +203,16 @@ const renderNode = (
190203
addCancel(cancelChildren);
191204
}
192205

206+
// Wrap with ct-cell-context if we traversed [UI] with a rootCell
207+
if (cellForContext && element) {
208+
const wrapper = document.createElement(
209+
"ct-cell-context",
210+
) as HTMLElement & { cell?: Cell };
211+
wrapper.cell = cellForContext;
212+
wrapper.appendChild(element);
213+
return [wrapper, cancel];
214+
}
215+
193216
return [element, cancel];
194217
};
195218

packages/patterns/chatbot.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,9 @@ export default pattern<ChatInput, ChatOutput>(
241241

242242
const attachmentsAndTools = (
243243
<ct-hstack align="center" gap="1">
244-
<ct-attachments-bar pinnedCells={pinnedCells} />
244+
<ct-cell-context $cell={pinnedCells}>
245+
<ct-attachments-bar pinnedCells={pinnedCells} />
246+
</ct-cell-context>
245247
<ct-tools-chip tools={flattenedTools} />
246248
<ct-button
247249
variant="pill"

packages/patterns/compiler.tsx

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,25 @@ export default recipe<Input>(
5858
[NAME]: "My First Compiler",
5959
[UI]: (
6060
<div>
61-
<ct-code-editor
62-
value={code}
63-
language="text/x.typescript"
64-
onChange={updateCode({ code })}
65-
//errors={errors}
66-
/>
67-
{ifElse(
68-
error,
69-
<b>fix the error: {error}</b>,
70-
<ct-button
71-
onClick={visit({ result })}
72-
>
73-
Navigate To Charm
74-
</ct-button>,
75-
)}
61+
<ct-cell-context $cell={code} label="Source Code">
62+
<ct-code-editor
63+
value={code}
64+
language="text/x.typescript"
65+
onChange={updateCode({ code })}
66+
//errors={errors}
67+
/>
68+
</ct-cell-context>
69+
<ct-cell-context $cell={result} label="Compile Result">
70+
{ifElse(
71+
error,
72+
<b>fix the error: {error}</b>,
73+
<ct-button
74+
onClick={visit({ result })}
75+
>
76+
Navigate To Charm
77+
</ct-button>,
78+
)}
79+
</ct-cell-context>
7680
</div>
7781
),
7882
code,

packages/patterns/counter.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@ export default recipe<RecipeState, RecipeOutput>((state) => {
2020
<ct-button onClick={decrement(state)}>
2121
dec to {previous(state.value)}
2222
</ct-button>
23-
<span id="counter-result">
24-
Counter is the {nth(state.value)} number
25-
</span>
23+
<ct-cell-context $cell={state.value} inline>
24+
<span id="counter-result">
25+
Counter is the {nth(state.value)} number
26+
</span>
27+
</ct-cell-context>
2628
<ct-button onClick={increment({ value: state.value })}>
2729
inc to {(state.value ?? 0) + 1}
2830
</ct-button>

packages/patterns/default-app.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ interface CharmsListOutput {
3333
fabUI: unknown;
3434
}
3535

36-
const visit = handler<
36+
const _visit = handler<
3737
Record<string, never>,
3838
{ charm: Cell<MinimalCharm> }
3939
>((_, state) => {
@@ -177,12 +177,9 @@ export default recipe<CharmsListInput, CharmsListOutput>(
177177
{allCharms.map((charm) => (
178178
<tr>
179179
<td>
180-
<a
181-
className="pattern-link"
182-
onClick={visit({ charm })}
183-
>
184-
{charm?.[NAME] || "Untitled Charm"}
185-
</a>
180+
<ct-cell-context $cell={charm}>
181+
<ct-cell-link $cell={charm} />
182+
</ct-cell-context>
186183
</td>
187184
<td>
188185
<ct-button

packages/patterns/favorites-manager.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,20 @@ export default pattern<Record<string, never>>((_) => {
2020
[UI]: (
2121
<div>
2222
{wishResult.result.map((item) => (
23-
<div>
24-
<ct-cell-link $cell={item.cell} />
25-
<ct-button
26-
onClick={onRemoveFavorite({
27-
favorites: wishResult.result,
28-
item: item.cell,
29-
})}
30-
>
31-
Remove
32-
</ct-button>
33-
<pre>{item.description}</pre>
34-
</div>
23+
<ct-cell-context $cell={item.cell}>
24+
<div>
25+
<ct-cell-link $cell={item.cell} />
26+
<ct-button
27+
onClick={onRemoveFavorite({
28+
favorites: wishResult.result,
29+
item: item.cell,
30+
})}
31+
>
32+
Remove
33+
</ct-button>
34+
<pre>{item.description}</pre>
35+
</div>
36+
</ct-cell-context>
3537
))}
3638
</div>
3739
),

packages/patterns/fetch-data.tsx

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -203,37 +203,39 @@ export default recipe<
203203
/>
204204
</div>
205205

206-
<div>
207-
<h3 id="github-title">
208-
{validData.name}
209-
</h3>
210-
<p>
211-
by {validData.owner.login}
212-
</p>
213-
<p>{validData.description}</p>
206+
<ct-cell-context $cell={validData}>
214207
<div>
208+
<h3 id="github-title">
209+
{validData.name}
210+
</h3>
211+
<p>
212+
by {validData.owner.login}
213+
</p>
214+
<p>{validData.description}</p>
215215
<div>
216-
<span></span>
217-
<strong>{validData.stargazers_count}</strong> stars
218-
</div>
219-
<div>
220-
<span>🍴</span>
221-
<strong>{validData.forks_count}</strong> forks
222-
</div>
223-
<div>
224-
<span>🔤</span>
225-
<strong>{validData.language}</strong>
226-
</div>
227-
<div>
228-
<a
229-
href={validData.html_url}
230-
target="_blank"
231-
>
232-
View on GitHub →
233-
</a>
216+
<div>
217+
<span></span>
218+
<strong>{validData.stargazers_count}</strong> stars
219+
</div>
220+
<div>
221+
<span>🍴</span>
222+
<strong>{validData.forks_count}</strong> forks
223+
</div>
224+
<div>
225+
<span>🔤</span>
226+
<strong>{validData.language}</strong>
227+
</div>
228+
<div>
229+
<a
230+
href={validData.html_url}
231+
target="_blank"
232+
>
233+
View on GitHub →
234+
</a>
235+
</div>
234236
</div>
235237
</div>
236-
</div>
238+
</ct-cell-context>
237239
</div>
238240
),
239241
repo: validData,

0 commit comments

Comments
 (0)