Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/reorganize-ui-components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@kidd-cli/core': minor
---

Reorganize UI components into prompts, display, and layout modules. Add new prompt components (Autocomplete, GroupMultiSelect, PathInput, SelectKey), display components (Alert, ProgressBar, Spinner, StatusMessage), and extract screen module with provider and context.
675 changes: 675 additions & 0 deletions docs/designs/component-library.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/diagnostic-output/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
"tsx": "catalog:",
"typescript": "catalog:"
}
}
}
1 change: 0 additions & 1 deletion packages/core/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ export async function cli<TSchema extends z.ZodType = z.ZodType>(
middleware: options.middleware,
name: options.name,
prompts: options.prompts,
spinner: options.spinner,
status: options.status,
version,
})
Expand Down
10 changes: 1 addition & 9 deletions packages/core/src/context/create-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import type {
Log,
Meta,
Prompts,
Spinner,
Status,
Store,
StoreMap,
Expand Down Expand Up @@ -45,11 +44,6 @@ export interface CreateContextOptions<TArgs extends AnyRecord, TConfig extends A
readonly log?: Log
readonly prompts?: Prompts
readonly status?: Status
/**
* @deprecated Use `status` instead. When provided, creates a Status
* wrapper around this spinner for backwards compatibility.
*/
readonly spinner?: Spinner
}

/**
Expand Down Expand Up @@ -141,8 +135,7 @@ function resolveCommonDefaults(dc: DisplayConfig): {
}

/**
* Resolve the Status instance from options, supporting the deprecated
* `spinner` override for backwards compatibility.
* Resolve the Status instance from options or create a default one.
*
* @private
* @param options - The create context options.
Expand All @@ -162,7 +155,6 @@ function resolveStatus<TArgs extends AnyRecord, TConfig extends AnyRecord>(
return createContextStatus({
defaults: commonDefaults,
progressConfig: dc.progress,
spinner: options.spinner,
spinnerConfig: dc.spinner,
})
}
3 changes: 3 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export { autoload } from './autoload.js'
export { decorateContext } from './context/decorate.js'
export { middleware } from './middleware.js'
export { defineConfig } from '@kidd-cli/config'
export { screen, useScreenContext } from './screen/index.js'
export type { ScreenDef, ScreenExit } from './screen/index.js'
export type {
CliConfig,
Command,
Expand All @@ -29,6 +31,7 @@ export type {
ProgressBar,
ProgressOptions,
Prompts,
ScreenContext,
SelectOptions,
Spinner,
Status,
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/runtime/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export async function createRuntime<TSchema extends z.ZodType>(
version: options.version,
},
prompts: options.prompts,
spinner: options.spinner,
status: options.status,
})

Expand Down
10 changes: 1 addition & 9 deletions packages/core/src/runtime/types.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import type { AsyncResult, Result } from '@kidd-cli/utils/fp'
import type { z } from 'zod'

import type {
CommandContext,
DisplayConfig,
Log,
Prompts,
Spinner,
Status,
} from '@/context/types.js'
import type { CommandContext, DisplayConfig, Log, Prompts, Status } from '@/context/types.js'
import type {
ArgsDef,
CliConfigOptions,
Expand All @@ -30,7 +23,6 @@ export interface RuntimeOptions<TSchema extends z.ZodType = z.ZodType> {
readonly log?: Log
readonly prompts?: Prompts
readonly status?: Status
readonly spinner?: Spinner
}

/**
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/screen/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Screen runtime — mounts Ink, wires context, manages the output store.
*
* A peer to `command/` at the core level. Users never import from
* `screen/output/` directly.
*
* @module
*/

export { screen } from './screen.js'
export type { ScreenDef, ScreenExit } from './screen.js'

export { useScreenContext } from './provider.js'
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
* @module
*/

export { Output } from './output.js'

export { useOutputStore } from './use-output-store.js'

export { createOutputStore } from './store.js'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ const OUTPUT_STORE_KEY: unique symbol = Symbol('kidd.outputStore')
* Options for {@link injectOutputStore}.
*/
interface InjectOutputStoreOptions {
/** The screen context record to extend. */
/**
* The screen context record to extend.
*/
readonly ctx: Record<string | symbol, unknown>
/** The output store to attach. */
/**
* The output store to attach.
*/
readonly store: OutputStore
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { match } from 'ts-pattern'

import type { CommandContext, ImperativeContextKeys, ScreenContext } from '../context/types.js'
import type { ArgsDef, Command, InferArgsMerged, Resolvable } from '../types/index.js'
import { FullScreen, LEAVE_ALT_SCREEN } from './fullscreen.js'
import { FullScreen, LEAVE_ALT_SCREEN } from '../ui/layout/fullscreen.js'
import { createScreenLog } from './output/screen-log.js'
import { createScreenReport } from './output/screen-report.js'
import { createScreenSpinner } from './output/screen-spinner.js'
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/stories/decorators.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import type { ComponentType, ReactElement } from 'react'
import React from 'react'

import type { ScreenContext } from '../context/types.js'
import { FullScreen } from '../ui/fullscreen.js'
import { KiddProvider } from '../ui/provider.js'
import { KiddProvider } from '../screen/provider.js'
import { FullScreen } from '../ui/layout/fullscreen.js'
import type { Decorator } from './types.js'

// ---------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import type { Option } from '@inkjs/ui'
import { ConfirmInput, MultiSelect, Select, TextInput } from '@inkjs/ui'
import { Box, Text } from 'ink'
import type { ReactElement } from 'react'
import { match } from 'ts-pattern'

import { ConfirmInput } from '../../../ui/confirm.js'
import { MultiSelect } from '../../../ui/multi-select.js'
import { Select } from '../../../ui/select.js'
import { TextInput } from '../../../ui/text-input.js'
import type { FieldControlKind } from '../../types.js'

// ---------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/stories/viewer/components/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import type { ComponentType, ReactElement } from 'react'
import { useMemo, useRef } from 'react'
import { match } from 'ts-pattern'

import { ScrollArea } from '../../../ui/scroll-area.js'
import { useSize } from '../../../ui/use-size.js'
import { ScrollArea } from '../../../ui/layout/scroll-area.js'
import { useSize } from '../../../ui/layout/use-size.js'
import type { FieldDescriptor, Story } from '../../types.js'
import type { FieldError } from '../../validate.js'
import { applyDecorators } from '../utils.js'
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/stories/viewer/components/props-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { Box, Text } from 'ink'
import type { ReactElement } from 'react'
import { match } from 'ts-pattern'

import type { TabItem } from '../../../ui/tabs.js'
import { Tabs } from '../../../ui/tabs.js'
import type { TabItem } from '../../../ui/layout/tabs.js'
import { Tabs } from '../../../ui/layout/tabs.js'
import type { FieldControlKind, FieldDescriptor } from '../../types.js'
import type { FieldError } from '../../validate.js'
import { FieldControl } from './field-control.js'
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/stories/viewer/components/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import type { ReactElement } from 'react'
import { useEffect, useMemo, useRef, useState } from 'react'
import { match } from 'ts-pattern'

import { ScrollArea } from '../../../ui/scroll-area.js'
import { useSize } from '../../../ui/use-size.js'
import { ScrollArea } from '../../../ui/layout/scroll-area.js'
import { useSize } from '../../../ui/layout/use-size.js'
import type { Story, StoryEntry, StoryGroup } from '../../types.js'

// ---------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/stories/viewer/stories-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { ReactElement } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { match } from 'ts-pattern'

import { FullScreen } from '../../ui/fullscreen.js'
import { FullScreen } from '../../ui/layout/fullscreen.js'
import type { StoryRegistry } from '../registry.js'
import { schemaToFieldDescriptors } from '../schema.js'
import type { Story, StoryEntry, StoryGroup } from '../types.js'
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/stories/viewer/stories-check.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import type { ReactElement } from 'react'
import { useEffect, useRef } from 'react'
import { match } from 'ts-pattern'

import { Output } from '../../ui/output/index.js'
import { useScreenContext } from '../../ui/provider.js'
import { useScreenContext } from '../../screen/provider.js'
import { Output } from '../../ui/output.js'
import { checkStories } from '../check.js'
import { discoverStories } from '../discover.js'
import { createStoryImporter } from '../importer.js'
Expand Down
8 changes: 1 addition & 7 deletions packages/core/src/test/context.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest'

import { createTestContext, mockLog, mockPrompts, mockSpinner, mockStatus } from './context.js'
import { createTestContext, mockLog, mockPrompts, mockStatus } from './context.js'

describe('test context factory', () => {
it('should return a context with default args', () => {
Expand Down Expand Up @@ -54,12 +54,6 @@ describe('test context factory', () => {
expect(ctx.status).toBe(status)
})

it('should accept custom spinner via deprecated option', () => {
const spinner = mockSpinner()
const { ctx } = createTestContext({ spinner })
expect(ctx.status.spinner).toBe(spinner)
})

it('should provide status with stub methods by default', () => {
const { ctx } = createTestContext()
expect(() => ctx.status.spinner.start('loading...')).not.toThrow()
Expand Down
24 changes: 12 additions & 12 deletions packages/core/src/test/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,16 +169,20 @@ export function mockStatus(spinnerOverride?: Spinner): Status {
isCancelled: false,
})),
tasks: vi.fn(async () => {}),
taskLog: vi.fn((): TaskLogHandle => ({
message: vi.fn(),
success: vi.fn(),
error: vi.fn(),
group: vi.fn((): TaskLogGroupHandle => ({
taskLog: vi.fn(
(): TaskLogHandle => ({
message: vi.fn(),
success: vi.fn(),
error: vi.fn(),
})),
})),
group: vi.fn(
(): TaskLogGroupHandle => ({
message: vi.fn(),
success: vi.fn(),
error: vi.fn(),
})
),
})
),
} as Status
}

Expand Down Expand Up @@ -216,8 +220,7 @@ function resolvePrompts(opts: TestContextOptions): Prompts {
}

/**
* Resolve the status instance from overrides, supporting the deprecated
* `spinner` override for backwards compatibility.
* Resolve the status instance from overrides or create a mock.
*
* @private
* @param opts - Test context options.
Expand All @@ -227,9 +230,6 @@ function resolveStatus(opts: TestContextOptions): Status {
if (opts.status !== undefined) {
return opts.status
}
if (opts.spinner !== undefined) {
return mockStatus(opts.spinner)
}
return mockStatus()
}

Expand Down
7 changes: 1 addition & 6 deletions packages/core/src/test/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { vi } from 'vitest'

import type { CommandContext, Log, Prompts, Spinner, Status } from '@/context/types.js'
import type { CommandContext, Log, Prompts, Status } from '@/context/types.js'
import type {
AnyRecord,
CliConfigOptions,
Expand Down Expand Up @@ -33,11 +33,6 @@ export interface TestContextOptions<
readonly log?: Log
readonly prompts?: Prompts
readonly status?: Status
/**
* @deprecated Use `status` instead. When provided, creates a Status
* wrapper around this spinner for backwards compatibility.
*/
readonly spinner?: Spinner
}

/**
Expand Down
7 changes: 1 addition & 6 deletions packages/core/src/types/cli.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { z } from 'zod'

import type { DisplayConfig, Log, Prompts, Spinner, Status } from '@/context/types.js'
import type { DisplayConfig, Log, Prompts, Status } from '@/context/types.js'

import type { CommandMap, CommandsConfig } from './command.js'
import type { Middleware } from './middleware.js'
Expand Down Expand Up @@ -167,11 +167,6 @@ export interface CliOptions<TSchema extends z.ZodType = z.ZodType> {
* `@clack/prompts`-backed status indicators are created automatically.
*/
readonly status?: Status
/**
* @deprecated Use `status` instead. When provided, creates a Status
* wrapper around this spinner for backwards compatibility.
*/
readonly spinner?: Spinner
/**
* When `true` (the default), yargs rejects unknown flags with an error.
* Set to `false` to allow unknown flags to pass through unchecked.
Expand Down
11 changes: 0 additions & 11 deletions packages/core/src/ui/confirm.tsx

This file was deleted.

Loading
Loading