Skip to content

feat(core): replace InputBlock with explicit PromptProps#131

Merged
zrosenbauer merged 6 commits intomainfrom
feat/input-isolation-prompt-props
Mar 31, 2026
Merged

feat(core): replace InputBlock with explicit PromptProps#131
zrosenbauer merged 6 commits intomainfrom
feat/input-isolation-prompt-props

Conversation

@zrosenbauer
Copy link
Copy Markdown
Member

@zrosenbauer zrosenbauer commented Mar 31, 2026

Summary

  • Add shared PromptProps interface (focused, disabled) extended by all 9 prompt components
  • Remove InputBlock / useInputBlock context-based input gating and @inkjs/ui dependency
  • Remove useInput proxy — all components import useInput directly from ink
  • Fix backspace on macOS: both key.backspace and key.delete now do backspace (macOS sends \x7f which ink reports as key.delete). Forward-delete uses Ctrl+D.
  • Add preview mode to stories viewer (browse → preview → edit flow)
  • Stories viewer shortcuts only fire in the appropriate mode — clean text input in edit mode
  • Props visible but read-only in preview mode, hidden in interactive mode
  • Rename isDisableddisabled across all prompts and stories
  • Add *.bun-build to .gitignore

Mode flow

browse ──Enter──▶ preview ──Enter──▶ edit
  ▲                 │  ▲               │
  ◀──────Esc────────┘  └─────Esc───────┘
                    │
                    i
                    ▼
              interactive
           (Esc Esc → preview)

Test plan

  • pnpm check passes (typecheck + lint + format)
  • pnpm test passes (1339 tests)
  • Stories viewer: browse mode — sidebar navigates, shortcuts work
  • Stories viewer: preview mode — Enter edits props, i enters interactive, Esc returns to browse
  • Stories viewer: edit mode — TextInput handles backspace/enter correctly, only Esc exits
  • Stories viewer: interactive mode — story has full input control, Esc Esc returns to preview
  • Normal CLI: prompts work with focused defaulting to true

…olation

Remove context-based input gating (InputBlock/useInputBlock) and useFocus
from all prompt components. Instead, every prompt extends PromptProps with
`focused` and `disabled` fields. The stories viewer passes `focused`
explicitly based on the active mode/panel.

- Add PromptProps interface (focused, disabled) shared by all prompts
- Remove InputBlock, useInputBlock, and input-gate.tsx
- Remove useFocus from 9 prompt components
- Remove @inkjs/ui dependency
- Rename isDisabled → disabled across prompts, stories, and internals
- Preview passes focused={false} to story component (visual-only)
- Interactive mode omits focused (defaults true, full control)

Co-Authored-By: Claude <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 31, 2026

🦋 Changeset detected

Latest commit: 4ff8cac

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@kidd-cli/core Minor
@kidd-cli/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
oss-kidd Ignored Ignored Preview Mar 31, 2026 3:57pm

Request Review

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 31, 2026

Merging this PR will not alter performance

✅ 2 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing feat/input-isolation-prompt-props (4ff8cac) with main (d03ed9d)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Centralizes prompt props into a new PromptProps type (focused, disabled) and replaces per-component isDisabled usage with focused/disabled across prompt components, stories, and prompt type exports. Renames useKeyBinding → useHotkey (UseKeyBindingArgs → UseHotkeyArgs) and removes useKeyInput, updating tests and the public UI export surface. Swaps some @inkjs/ui prompt imports for local prompt implementations and updates field-control usages accordingly. Introduces a new viewer "preview" mode with enter/exit APIs, updates viewer mode transitions and keyboard handling, and adds an editable prop to Preview. Updates input-state logic (unifies backspace/delete, adds Ctrl+D forward-delete). Adds *.bun-build to .gitignore.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(core): replace InputBlock with explicit PromptProps' accurately summarizes the primary change—removing InputBlock and adding a PromptProps interface across prompt components.
Description check ✅ Passed The description comprehensively relates to the changeset, detailing the InputBlock removal, PromptProps addition, mode flow changes, prop renames, and test plan.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/input-isolation-prompt-props

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/ui/prompts/group-multi-select.tsx (1)

19-23: ⚠️ Potential issue | 🟠 Major

Public prop rename introduces a breaking API at compile time.

Line 19 and Line 61 remove support for isDisabled on an exported component contract. Existing consumers passing isDisabled will fail type-checking after upgrade. Add a deprecated alias during a transition window.

Proposed compatibility patch
 export interface GroupMultiSelectProps<TValue> extends PromptProps {
+  /** `@deprecated` Use `disabled` instead. */
+  readonly isDisabled?: boolean
   /** Options organized by group name. */
   readonly options: Readonly<Record<string, readonly PromptOption<TValue>[]>>
@@
 export function GroupMultiSelect<TValue>({
   options,
   defaultValue = [],
   required = false,
   selectableGroups = false,
   onChange,
   onSubmit,
-  focused = true,
-  disabled = false,
+  focused = true,
+  disabled,
+  isDisabled,
 }: GroupMultiSelectProps<TValue>): ReactElement {
+  const resolvedDisabled = disabled ?? isDisabled ?? false
@@
-    { isActive: focused && !disabled }
+    { isActive: focused && !resolvedDisabled }
   )
@@
-            disabled={disabled}
+            disabled={resolvedDisabled}
           />

As per coding guidelines "Review with high signal only. Flag only: ... Breaking changes (incompatible API changes, removed exports)."

Also applies to: 54-63

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/ui/prompts/group-multi-select.tsx` around lines 19 - 23,
The exported GroupMultiSelectProps<TValue> interface removed the public
isDisabled prop causing a breaking TypeScript change; restore backward
compatibility by adding a deprecated alias for isDisabled (e.g., keep the new
prop name but add an optional readonly isDisabled?: boolean mapped to the new
property) in GroupMultiSelectProps and ensure the GroupMultiSelect component
props accept and forward isDisabled to the internal implementation (preserve
behavior in the component that consumes options and selection), mark the alias
as deprecated in comments so consumers can migrate while avoiding compile
errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/ui/index.ts`:
- Line 19: The public export renamed Ink's useInput to useInkInput and replaced
the previous key-binding API with useHotkey/UseHotkeyArgs, which breaks
downstream consumers; restore backward compatibility by re-exporting the
original symbols as aliases (export { useInkInput as useInput } and export {
useHotkey, UseHotkeyArgs } alongside any new names) or add compatibility
wrappers that forward to the new implementations so existing imports still work
while keeping the new names available; update the barrel exports around
useInkInput/useInput and useHotkey/UseHotkeyArgs to include both names.

In `@packages/core/src/ui/prompts/autocomplete.tsx`:
- Around line 22-23: The export AutocompleteProps<TValue> removed the previously
exported prop isDisabled which is a breaking change; restore backward
compatibility by reintroducing an optional isDisabled?: boolean on
AutocompleteProps and inside the Autocomplete component (or any function
handling props like the component that reads disabled) prefer the new name but
accept the old alias by resolving disabledValue = disabled ?? isDisabled and use
disabledValue everywhere; mark isDisabled as deprecated in the type comment so
it can be removed in a later release.

---

Outside diff comments:
In `@packages/core/src/ui/prompts/group-multi-select.tsx`:
- Around line 19-23: The exported GroupMultiSelectProps<TValue> interface
removed the public isDisabled prop causing a breaking TypeScript change; restore
backward compatibility by adding a deprecated alias for isDisabled (e.g., keep
the new prop name but add an optional readonly isDisabled?: boolean mapped to
the new property) in GroupMultiSelectProps and ensure the GroupMultiSelect
component props accept and forward isDisabled to the internal implementation
(preserve behavior in the component that consumes options and selection), mark
the alias as deprecated in comments so consumers can migrate while avoiding
compile errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8a6a2c6d-8fd3-4f03-a5ba-f63545afd122

📥 Commits

Reviewing files that changed from the base of the PR and between d03ed9d and 12567d1.

⛔ Files ignored due to path filters (2)
  • .changeset/input-isolation-prompt-props.md is excluded by !.changeset/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (37)
  • packages/core/package.json
  • packages/core/src/stories/viewer/components/field-control.tsx
  • packages/core/src/stories/viewer/components/help-overlay.tsx
  • packages/core/src/stories/viewer/components/preview.tsx
  • packages/core/src/stories/viewer/components/sidebar.tsx
  • packages/core/src/stories/viewer/hooks/use-double-escape.ts
  • packages/core/src/stories/viewer/stories-app.tsx
  • packages/core/src/ui/index.ts
  • packages/core/src/ui/layout/tabs.tsx
  • packages/core/src/ui/prompts/autocomplete.stories.tsx
  • packages/core/src/ui/prompts/autocomplete.tsx
  • packages/core/src/ui/prompts/confirm.stories.tsx
  • packages/core/src/ui/prompts/confirm.tsx
  • packages/core/src/ui/prompts/cursor-value.tsx
  • packages/core/src/ui/prompts/group-multi-select.stories.tsx
  • packages/core/src/ui/prompts/group-multi-select.tsx
  • packages/core/src/ui/prompts/index.ts
  • packages/core/src/ui/prompts/multi-select.stories.tsx
  • packages/core/src/ui/prompts/multi-select.tsx
  • packages/core/src/ui/prompts/option-row.tsx
  • packages/core/src/ui/prompts/password-input.stories.tsx
  • packages/core/src/ui/prompts/password-input.tsx
  • packages/core/src/ui/prompts/path-input.stories.tsx
  • packages/core/src/ui/prompts/path-input.tsx
  • packages/core/src/ui/prompts/select-key.stories.tsx
  • packages/core/src/ui/prompts/select-key.tsx
  • packages/core/src/ui/prompts/select.stories.tsx
  • packages/core/src/ui/prompts/select.tsx
  • packages/core/src/ui/prompts/text-input.stories.tsx
  • packages/core/src/ui/prompts/text-input.tsx
  • packages/core/src/ui/prompts/types.ts
  • packages/core/src/ui/use-input.test.ts
  • packages/core/src/ui/use-input.ts
  • packages/core/src/ui/use-key-binding.test.ts
  • packages/core/src/ui/use-key-binding.ts
  • packages/core/src/ui/use-key-input.test.ts
  • packages/core/src/ui/use-key-input.ts
💤 Files with no reviewable changes (3)
  • packages/core/package.json
  • packages/core/src/ui/use-key-input.test.ts
  • packages/core/src/ui/use-key-input.ts

Also add *.bun-build to .gitignore.

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (4)
packages/core/src/ui/index.ts (1)

65-65: ⚠️ Potential issue | 🟠 Major

Public UI barrel introduces incompatible export renames/removals.

Line 137-138 exports only useHotkey/UseHotkeyArgs, so consumers importing previous key-binding symbols from this barrel will break at compile time. Line 65 also reflects the prompt contract surface shift, which compounds public API migration impact. Please provide compatibility aliases (or explicitly treat this as a documented breaking release).

Suggested compatibility alias patch (non-breaking transition)
-export { useHotkey } from './use-key-binding.js'
-export type { UseHotkeyArgs } from './use-key-binding.js'
+export { useHotkey, useHotkey as useKeyBinding } from './use-key-binding.js'
+export type {
+  UseHotkeyArgs,
+  UseHotkeyArgs as UseKeyBindingArgs,
+} from './use-key-binding.js'
As per coding guidelines (`**`: “Flag only … Breaking changes (incompatible API changes, removed exports)”).

Also applies to: 137-138

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/ui/index.ts` at line 65, The public UI barrel
removed/renamed exports (e.g., PromptProps and prior key-binding symbols)
causing breaking changes; add compatibility aliases in
packages/core/src/ui/index.ts by re-exporting the old symbol names to the new
implementations (for example export oldKeyName = useHotkey and oldKeyArgs =
UseHotkeyArgs or re-export PromptProps from its new location) so existing
consumers still compile, or explicitly mark this as a breaking change in the
release notes if you intend to remove them permanently; update the export list
around the useHotkey/UseHotkeyArgs and PromptProps declarations to include these
compatibility aliases.
packages/core/src/ui/prompts/confirm.tsx (1)

16-17: ⚠️ Potential issue | 🟠 Major

Breaking API change: ConfirmProps dropped isDisabled compatibility.

Line 16 and Line 55 introduce an incompatible prop rename for external consumers still using isDisabled. Add a deprecated alias and resolve to disabled internally.

Proposed compatibility patch
 export interface ConfirmProps extends PromptProps {
+  /** `@deprecated` Use `disabled` instead. */
+  readonly isDisabled?: boolean
   /** Label for the affirmative choice. `@default` "Yes" */
   readonly active?: string
@@
 export function Confirm({
@@
   focused = true,
-  disabled = false,
+  disabled,
+  isDisabled,
 }: ConfirmProps): ReactElement {
+  const resolvedDisabled = disabled ?? isDisabled ?? false
   const [value, setValue] = useState(defaultValue)
@@
-    { isActive: focused && !disabled }
+    { isActive: focused && !resolvedDisabled }
   )
@@
-      <ConfirmChoice label={active} isActive={value} disabled={disabled} />
+      <ConfirmChoice label={active} isActive={value} disabled={resolvedDisabled} />
@@
-      <ConfirmChoice label={inactive} isActive={!value} disabled={disabled} />
+      <ConfirmChoice label={inactive} isActive={!value} disabled={resolvedDisabled} />

As per coding guidelines "Review with high signal only. Flag only: Breaking changes (incompatible API changes, removed exports)."

Also applies to: 55-57, 83-83, 88-90

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/ui/prompts/confirm.tsx` around lines 16 - 17, ConfirmProps
removed backward-compatible isDisabled prop causing a breaking API change; add a
deprecated alias so external users can still pass isDisabled. Update the
ConfirmProps type to accept isDisabled?: boolean (marked deprecated) and ensure
the component (Confirm) resolves isDisabled into the existing disabled property
(e.g., const resolvedDisabled = disabled ?? isDisabled) so internal logic and
rendering use resolvedDisabled; also update any prop destructuring/usage
locations (ConfirmProps, Confirm component render/handlers) to reference
resolvedDisabled and add a short deprecation comment for isDisabled.
packages/core/src/ui/prompts/autocomplete.tsx (1)

21-22: ⚠️ Potential issue | 🟠 Major

AutocompleteProps rename (isDisableddisabled) is still a breaking public API change.

Line 21 and Line 67 remove compatibility for existing callers passing isDisabled. This should either ship behind a major-version boundary or keep a deprecated alias temporarily.

Proposed compatibility patch
 export interface AutocompleteProps<TValue> extends PromptProps {
+  /** `@deprecated` Use `disabled` instead. */
+  readonly isDisabled?: boolean
   /** The full list of selectable options. */
   readonly options: readonly PromptOption<TValue>[]
@@
 export function Autocomplete<TValue>({
@@
   focused = true,
-  disabled = false,
+  disabled,
+  isDisabled,
 }: AutocompleteProps<TValue>): ReactElement {
+  const resolvedDisabled = disabled ?? isDisabled ?? false
@@
-    { isActive: focused && !disabled }
+    { isActive: focused && !resolvedDisabled }
   )
@@
-        disabled={disabled}
+        disabled={resolvedDisabled}
@@
-                  disabled={disabled}
+                  disabled={resolvedDisabled}

As per coding guidelines "Review with high signal only. Flag only: Breaking changes (incompatible API changes, removed exports)."

Also applies to: 67-69, 152-152, 160-160, 180-180

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/ui/prompts/autocomplete.tsx` around lines 21 - 22, The
public API change renaming AutocompleteProps property isDisabled → disabled is
breaking; restore backward compatibility by keeping the new disabled property
but accept the old isDisabled as a deprecated alias in AutocompleteProps and in
the consuming component(s) (e.g., wherever AutocompleteProps is
destructured/used) map isDisabled to disabled (preferencing explicit disabled if
both present), add a deprecation comment/JSdoc on isDisabled, and add a small
runtime warning or test to ensure callers using isDisabled continue to work
until the next major release; reference the AutocompleteProps interface and the
component render/handler functions that consume that prop to locate where to add
the alias mapping.
packages/core/src/ui/prompts/select-key.tsx (1)

15-16: ⚠️ Potential issue | 🟠 Major

Breaking API change: isDisabled was removed from exported props without compatibility shim.

Line 15 and Line 41 remove support for previous callers using isDisabled, which is an incompatible public API change. Keep a deprecated alias for at least one release window (or explicitly ship as a major-version break).

Proposed compatibility patch
 export interface SelectKeyProps<TValue extends string> extends PromptProps {
+  /** `@deprecated` Use `disabled` instead. */
+  readonly isDisabled?: boolean
   /** Options where each `value` is a single key character. */
   readonly options: readonly PromptOption<TValue>[]
@@
 export function SelectKey<TValue extends string>({
   options,
   onSubmit,
   focused = true,
-  disabled = false,
+  disabled,
+  isDisabled,
 }: SelectKeyProps<TValue>): ReactElement {
+  const resolvedDisabled = disabled ?? isDisabled ?? false
   useInput(
@@
-    { isActive: focused && !disabled }
+    { isActive: focused && !resolvedDisabled }
   )
@@
-        <KeyOptionRow key={option.value} option={option} disabled={disabled} />
+        <KeyOptionRow key={option.value} option={option} disabled={resolvedDisabled} />
       ))}

As per coding guidelines "Review with high signal only. Flag only: Breaking changes (incompatible API changes, removed exports)."

Also applies to: 41-43, 54-54, 60-60

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/ui/prompts/select-key.tsx` around lines 15 - 16,
SelectKeyProps<TValue> removed the public isDisabled prop, causing a breaking
API change; re-add a deprecated optional isDisabled?: boolean to the exported
SelectKeyProps<TValue> interface as a compatibility alias and ensure the
SelectKey component (and any related handlers) map isDisabled to the existing
disabled/internal prop (e.g., treat props.isDisabled as props.disabled when
present), add a deprecation comment on isDisabled, and keep this shim for at
least one release (or explicitly document as a major-version break) so existing
callers continue to work.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/core/src/ui/index.ts`:
- Line 65: The public UI barrel removed/renamed exports (e.g., PromptProps and
prior key-binding symbols) causing breaking changes; add compatibility aliases
in packages/core/src/ui/index.ts by re-exporting the old symbol names to the new
implementations (for example export oldKeyName = useHotkey and oldKeyArgs =
UseHotkeyArgs or re-export PromptProps from its new location) so existing
consumers still compile, or explicitly mark this as a breaking change in the
release notes if you intend to remove them permanently; update the export list
around the useHotkey/UseHotkeyArgs and PromptProps declarations to include these
compatibility aliases.

In `@packages/core/src/ui/prompts/autocomplete.tsx`:
- Around line 21-22: The public API change renaming AutocompleteProps property
isDisabled → disabled is breaking; restore backward compatibility by keeping the
new disabled property but accept the old isDisabled as a deprecated alias in
AutocompleteProps and in the consuming component(s) (e.g., wherever
AutocompleteProps is destructured/used) map isDisabled to disabled (preferencing
explicit disabled if both present), add a deprecation comment/JSdoc on
isDisabled, and add a small runtime warning or test to ensure callers using
isDisabled continue to work until the next major release; reference the
AutocompleteProps interface and the component render/handler functions that
consume that prop to locate where to add the alias mapping.

In `@packages/core/src/ui/prompts/confirm.tsx`:
- Around line 16-17: ConfirmProps removed backward-compatible isDisabled prop
causing a breaking API change; add a deprecated alias so external users can
still pass isDisabled. Update the ConfirmProps type to accept isDisabled?:
boolean (marked deprecated) and ensure the component (Confirm) resolves
isDisabled into the existing disabled property (e.g., const resolvedDisabled =
disabled ?? isDisabled) so internal logic and rendering use resolvedDisabled;
also update any prop destructuring/usage locations (ConfirmProps, Confirm
component render/handlers) to reference resolvedDisabled and add a short
deprecation comment for isDisabled.

In `@packages/core/src/ui/prompts/select-key.tsx`:
- Around line 15-16: SelectKeyProps<TValue> removed the public isDisabled prop,
causing a breaking API change; re-add a deprecated optional isDisabled?: boolean
to the exported SelectKeyProps<TValue> interface as a compatibility alias and
ensure the SelectKey component (and any related handlers) map isDisabled to the
existing disabled/internal prop (e.g., treat props.isDisabled as props.disabled
when present), add a deprecation comment on isDisabled, and keep this shim for
at least one release (or explicitly document as a major-version break) so
existing callers continue to work.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ea28ebb7-dc3d-47b9-84d0-77194b3adf86

📥 Commits

Reviewing files that changed from the base of the PR and between 12567d1 and 142af6b.

⛔ Files ignored due to path filters (1)
  • .changeset/input-isolation-prompt-props.md is excluded by !.changeset/**
📒 Files selected for processing (12)
  • .gitignore
  • packages/core/src/ui/index.ts
  • packages/core/src/ui/prompts/autocomplete.tsx
  • packages/core/src/ui/prompts/confirm.tsx
  • packages/core/src/ui/prompts/group-multi-select.tsx
  • packages/core/src/ui/prompts/multi-select.tsx
  • packages/core/src/ui/prompts/password-input.tsx
  • packages/core/src/ui/prompts/path-input.tsx
  • packages/core/src/ui/prompts/select-key.tsx
  • packages/core/src/ui/prompts/select.tsx
  • packages/core/src/ui/prompts/text-input.tsx
  • packages/core/src/ui/use-key-binding.ts

zrosenbauer and others added 2 commits March 30, 2026 22:35
- macOS terminals send \x7f (DEL) for Backspace, which ink reports as
  key.delete. Both key.backspace and key.delete now do backspace
  (delete before cursor). Forward-delete uses Ctrl+D.
- Stories-app shortcuts (q/r/b/i/?) now only fire in browse mode,
  preventing key conflicts with TextInput in edit mode.

Co-Authored-By: Claude <noreply@anthropic.com>
Add a new `preview` mode between browse and edit, giving users a
read-only view of the story with props visible but not editable.

Mode flow:
  browse → Enter → preview → Enter → edit
  preview → i → interactive → Esc Esc → preview
  edit → Esc → preview → Esc → browse

- `preview` mode: preview panel highlighted, props visible (read-only),
  shortcuts for i (interactive), Enter (edit), r (reset), Esc (browse)
- `edit` mode: only Esc to exit, no other shortcuts (clean text input)
- `interactive` mode: returns to preview instead of browse
- Updated status bar, help overlay, and keyboard hints for all modes

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/stories/viewer/components/preview.tsx (1)

159-165: ⚠️ Potential issue | 🟠 Major

Preview mode locks tabbed props to the first field.

isFocused={editable} is false in preview mode, and PropsEditor forwards that into the tabbed editor. packages/core/src/ui/layout/tabs.tsx (Lines 60-82) disables tab input when isFocused is false, so any story with multiple prop groups becomes unreadable in preview because users cannot switch tabs. Read-only preview still needs navigation separate from field editability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/stories/viewer/components/preview.tsx` around lines 159 -
165, Preview mode sets isFocused={editable} on PropsEditor causing the tabbed UI
to be disabled when editable is false; change the behavior so navigation remains
enabled in read-only preview. Update PropsEditor to accept a separate prop
(e.g., navigationEnabled or isTabNavigationEnabled) and use that when rendering
the tabbed component instead of forwarding isFocused; alternatively, when
rendering PropsEditor from the preview component, pass isFocused={true} (or the
new navigation prop=true) while keeping editable=false so fields remain
read-only but tabs remain navigable; reference PropsEditor and the tab disabling
logic in the tabbed component (tabs.tsx) to ensure tab input is controlled by
the new navigation flag, not the edit focus flag.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/stories/viewer/components/status-bar.tsx`:
- Around line 52-56: The status bar is rendering QuitHint for edit mode via the
match(...).otherwise branch while the actual 'q' shortcut is only handled in
stories-app.tsx for browse and preview; update the rendering logic in
status-bar.tsx so QuitHint is only shown when mode is 'browse' or 'preview'
(e.g., use match(mode).with('browse', ...).with('preview', ...).otherwise(() =>
null)), or alternatively add the 'q' key handling for edit mode in
stories-app.tsx to match the hint; reference the match(...) call, the mode
variable, and the QuitHint component when making the change.

In `@packages/core/src/stories/viewer/stories-app.tsx`:
- Around line 151-180: The input handler uses multiple chained ifs; replace it
with a ts-pattern match() on the relevant input/key state (e.g., match({ input,
key, selectedStory, showHelp })) and express each branch as a pattern arm: when
showHelp is true return; when key.return && selectedStory != null call
enterEditMode; when key.escape call exitPreviewMode; when input === 'i' &&
selectedStory != null call enterInteractiveMode; when input === 'r' call
handleResetProps; when input === 'q' call exit; when input === '?' call
setShowHelp(true); when input === 'b' toggle sidebar via setShowSidebar(prev =>
!prev). Apply the same conversion for the second useInput handler around the
182-200 region so both multi-branch handlers follow the ts-pattern match()
style.

---

Outside diff comments:
In `@packages/core/src/stories/viewer/components/preview.tsx`:
- Around line 159-165: Preview mode sets isFocused={editable} on PropsEditor
causing the tabbed UI to be disabled when editable is false; change the behavior
so navigation remains enabled in read-only preview. Update PropsEditor to accept
a separate prop (e.g., navigationEnabled or isTabNavigationEnabled) and use that
when rendering the tabbed component instead of forwarding isFocused;
alternatively, when rendering PropsEditor from the preview component, pass
isFocused={true} (or the new navigation prop=true) while keeping editable=false
so fields remain read-only but tabs remain navigable; reference PropsEditor and
the tab disabling logic in the tabbed component (tabs.tsx) to ensure tab input
is controlled by the new navigation flag, not the edit focus flag.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 19bd918c-5ae8-408d-bc07-ab4035acacdf

📥 Commits

Reviewing files that changed from the base of the PR and between 014b90b and 7b33f97.

📒 Files selected for processing (5)
  • packages/core/src/stories/viewer/components/help-overlay.tsx
  • packages/core/src/stories/viewer/components/preview.tsx
  • packages/core/src/stories/viewer/components/status-bar.tsx
  • packages/core/src/stories/viewer/hooks/use-panel-focus.ts
  • packages/core/src/stories/viewer/stories-app.tsx

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@zrosenbauer zrosenbauer merged commit d752216 into main Mar 31, 2026
7 checks passed
@zrosenbauer zrosenbauer deleted the feat/input-isolation-prompt-props branch March 31, 2026 16:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant