Skip to content

Commit c933bd9

Browse files
committed
wip: initial components
1 parent eb79a94 commit c933bd9

File tree

16 files changed

+663
-26
lines changed

16 files changed

+663
-26
lines changed

packages/jsx/jsx-runtime.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { jsx, jsxDEV } from './dist/index.mjs';
1+
export * from './dist/index.mjs';

packages/jsx/jsx-runtime.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { jsx, jsxDEV } from './dist/index.mjs';
1+
export * from './dist/index.mjs';

packages/jsx/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
},
5858
"devDependencies": {
5959
"vitest": "^3.1.1",
60+
"vitest-ansi-serializer": "^0.1.2",
6061
"@clack/test-utils": "workspace:*"
6162
}
6263
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { ConfirmOptions } from '@clack/prompts';
2+
import { confirm } from '@clack/prompts';
3+
4+
export type ConfirmProps = ConfirmOptions;
5+
6+
export function Confirm(props: ConfirmProps): ReturnType<typeof confirm> {
7+
return confirm(props);
8+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { NoteOptions } from '@clack/prompts';
2+
import { isCancel, note } from '@clack/prompts';
3+
import type { JSX } from '../types.js';
4+
import { resolveChildren } from '../utils.js';
5+
6+
export interface NoteProps extends NoteOptions {
7+
children?: JSX.Element[] | JSX.Element | string;
8+
message?: string;
9+
title?: string;
10+
}
11+
12+
export async function Note(props: NoteProps): Promise<void> {
13+
let message = '';
14+
15+
if (props.children) {
16+
const messages: string[] = [];
17+
const children = await resolveChildren(props.children);
18+
for (const child of children) {
19+
// TODO (43081j): handle cancelling of children
20+
if (isCancel(child)) {
21+
continue;
22+
}
23+
messages.push(String(child));
24+
}
25+
message = messages.join('\n');
26+
} else if (props.message) {
27+
message = props.message;
28+
}
29+
30+
note(message, props.title, props);
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { type Option, isCancel } from '@clack/prompts';
2+
import type { JSX } from '../types.js';
3+
import { resolveChildren } from '../utils.js';
4+
5+
export interface OptionProps {
6+
value: unknown;
7+
children?: JSX.Element | JSX.Element[] | string;
8+
}
9+
10+
export async function Option(props: OptionProps): Promise<Option<unknown>> {
11+
let label = '';
12+
if (props.children) {
13+
const children = await resolveChildren(props.children);
14+
const childStrings: string[] = [];
15+
16+
for (const child of children) {
17+
if (isCancel(child)) {
18+
continue;
19+
}
20+
childStrings.push(String(child));
21+
}
22+
23+
label = childStrings.join('\n');
24+
} else {
25+
label = String(props.value);
26+
}
27+
return {
28+
value: props.value,
29+
label,
30+
};
31+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { PasswordOptions } from '@clack/prompts';
2+
import { password } from '@clack/prompts';
3+
4+
export type PasswordProps = PasswordOptions;
5+
6+
export function Password(props: PasswordProps): ReturnType<typeof password> {
7+
return password(props);
8+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { Option, SelectOptions } from '@clack/prompts';
2+
import { select } from '@clack/prompts';
3+
import type { JSX } from '../types.js';
4+
import { resolveChildren } from '../utils.js';
5+
6+
export interface SelectProps extends Omit<SelectOptions<unknown>, 'options'> {
7+
children: JSX.Element[] | JSX.Element;
8+
}
9+
10+
const isOptionLike = (obj: unknown): obj is Option<unknown> => {
11+
return (
12+
obj !== null &&
13+
typeof obj === 'object' &&
14+
Object.hasOwnProperty.call(obj, 'label') &&
15+
Object.hasOwnProperty.call(obj, 'value') &&
16+
typeof (obj as { label: string }).label === 'string'
17+
);
18+
};
19+
20+
export async function Select(props: SelectProps): ReturnType<typeof select> {
21+
const { children, ...opts } = props;
22+
const options: Option<unknown>[] = [];
23+
const resolvedChildren = await resolveChildren(props.children);
24+
25+
for (const child of resolvedChildren) {
26+
if (isOptionLike(child)) {
27+
options.push(child);
28+
}
29+
}
30+
31+
return select({
32+
...opts,
33+
options,
34+
});
35+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { TextOptions } from '@clack/prompts';
2+
import { text } from '@clack/prompts';
3+
4+
export type TextProps = TextOptions;
5+
6+
export function Text(props: TextProps): ReturnType<typeof text> {
7+
return text(props);
8+
}

packages/jsx/src/index.ts

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,46 @@
1-
import type { ConfirmOptions } from '@clack/prompts';
2-
import { confirm } from '@clack/prompts';
3-
4-
namespace JSX {
5-
export interface IntrinsicElements {
6-
}
7-
8-
export type Element = Promise<unknown>;
9-
}
1+
import { Confirm, type ConfirmProps } from './components/confirm.js';
2+
import { Note, type NoteProps } from './components/note.js';
3+
import { Option, type OptionProps } from './components/option.js';
4+
import { Password, type PasswordProps } from './components/password.js';
5+
import { Select, type SelectProps } from './components/select.js';
6+
import { Text, type TextProps } from './components/text.js';
7+
import type { JSX } from './types.js';
108

119
export type { JSX };
10+
export {
11+
Confirm,
12+
type ConfirmProps,
13+
Note,
14+
type NoteProps,
15+
Text,
16+
type TextProps,
17+
Password,
18+
type PasswordProps,
19+
Option,
20+
type OptionProps,
21+
Select,
22+
type SelectProps,
23+
};
1224

13-
export function Confirm(props: ConfirmOptions): ReturnType<typeof confirm> {
14-
return confirm(props);
25+
export function Fragment(props: { children: JSX.Element | JSX.Element[] }): JSX.Element {
26+
return Promise.resolve(props.children);
1527
}
1628

1729
export type Component =
18-
| typeof Confirm;
30+
| typeof Confirm
31+
| typeof Note
32+
| typeof Text
33+
| typeof Password
34+
| typeof Option
35+
| typeof Select;
1936

2037
function jsx<T extends keyof JSX.IntrinsicElements>(
2138
tag: T,
2239
props: JSX.IntrinsicElements[T],
2340
_key?: string
2441
): JSX.Element;
25-
function jsx<T extends Component>(
26-
fn: T,
27-
props: Parameters<T>[0],
28-
_key?: string
29-
): JSX.Element;
30-
function jsx(
31-
tagOrFn: string | Component,
32-
props: unknown,
33-
_key?: string
34-
): JSX.Element {
42+
function jsx<T extends Component>(fn: T, props: Parameters<T>[0], _key?: string): JSX.Element;
43+
function jsx(tagOrFn: string | Component, props: unknown, _key?: string): JSX.Element {
3544
if (typeof tagOrFn === 'function') {
3645
return (tagOrFn as (props: unknown) => JSX.Element)(props);
3746
}

0 commit comments

Comments
 (0)