Skip to content

Commit

Permalink
release @reliverse/relinka 1.0.0 & improve prompts
Browse files Browse the repository at this point in the history
  • Loading branch information
blefnk committed Nov 19, 2024
1 parent 1d73760 commit 82478c5
Show file tree
Hide file tree
Showing 47 changed files with 680 additions and 240 deletions.
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Reliverse Prompts
# @reliverse/relinka

[**Docs**](https://docs.reliverse.org/prompts) | [**npmjs.com**](https://npmjs.com/package/@reliverse/relinka) | [**GitHub**](https://github.com/reliverse/prompts)
[**Docs**](https://docs.reliverse.org/relinka) | [**npmjs.com**](https://npmjs.com/package/@reliverse/relinka) | [**GitHub**](https://github.com/reliverse/relinka)

[![Separator](./public/split.png)](https://docs.reliverse.org/prompts)
[![Separator](./public/split.png)](https://docs.reliverse.org/relinka)

@reliverse/relinka is a powerful library that enables seamless, type-safe, and resilient prompts for command-line applications. Crafted with simplicity and elegance, it provides developers with an intuitive and robust way to build interactive CLIs.

[![CLI Example](./public/example.png)](https://docs.reliverse.org/prompts)
[![CLI Example](./public/example.png)](https://docs.reliverse.org/relinka)

## Installation

Expand All @@ -23,7 +23,7 @@ bun add @reliverse/relinka # Replace 'bun' with npm, pnpm, or yarn if desired (d
- **Flexible Prompt Types**: Supports a range of prompt types, including text, password, number, select, and multiselect.
- **Crash Resilience**: Designed to handle cancellations and errors gracefully, ensuring stability.

[![Confirm Prompt](./public/confirm.gif)](https://docs.reliverse.org/prompts)
[![Confirm Prompt](./public/confirm.gif)](https://docs.reliverse.org/relinka)

## Prompt Types

Expand All @@ -36,13 +36,13 @@ Each type has its own validation and display logic. More types are planned for f
- **Select**: Dropdown selection for multiple choices.
- **Multiselect**: Allows users to select multiple items from a list.

[![Multiselect Prompt](./public/list.gif)](https://docs.reliverse.org/prompts)
[![Multiselect Prompt](./public/list.gif)](https://docs.reliverse.org/relinka)

## Input Validation

All prompts support custom validation logic, providing immediate feedback to users.

[![Number Prompt with Validation](./public/validate.gif)](https://docs.reliverse.org/prompts)
[![Number Prompt with Validation](./public/validate.gif)](https://docs.reliverse.org/relinka)

## Contributing

Expand All @@ -51,8 +51,8 @@ All prompts support custom validation logic, providing immediate feedback to use
Here is how to install the library for development:

```sh
git clone https://github.com/reliverse/prompts.git
cd prompts
git clone https://github.com/reliverse/relinka.git
cd relinka
bun i
```

Expand Down Expand Up @@ -114,7 +114,7 @@ This project wouldn’t exist without the amazing work of the following projects

## Wrap-Up

@reliverse/relinka is a versatile library designed to accelerate CLI development by providing customizable prompt components. Integrated into the [Reliverse CLI](https://github.com/blefnk/reliverse#readme), @reliverse/relinka enables you to create a unique design aligned with your CLI app’s aesthetics, similar to how @shadcn/ui supports customizable web UI components. Quickly get started by copying configurations from the [Reliverse Docs](https://docs.reliverse.org/prompts) and using components that fit your project, making it faster to bring your CLI app to life. You’re free to customize each component as desired, with default designs provided to ensure an attractive interface from the start.
@reliverse/relinka is a versatile library designed to accelerate CLI development by providing customizable prompt components. Integrated into the [Reliverse CLI](https://github.com/blefnk/reliverse#readme), @reliverse/relinka enables you to create a unique design aligned with your CLI app’s aesthetics, similar to how @shadcn/ui supports customizable web UI components. Quickly get started by copying configurations from the [Reliverse Docs](https://docs.reliverse.org/relinka) and using components that fit your project, making it faster to bring your CLI app to life. You’re free to customize each component as desired, with default designs provided to ensure an attractive interface from the start.

**Example Configuration:**

Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"outro",
"pagedown",
"pageup",
"picocolors",
"printj",
"redrun",
"relinka",
Expand Down
34 changes: 13 additions & 21 deletions examples/1-main-example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,59 +6,51 @@ import {
doSomeFunStuff,
showAnimatedText,
showAnyKeyPrompt,
showConfirmPrompt,
// showConfirmPrompt,
showDatePrompt,
showEndPrompt,
// showMultiSelectPrompt,
showNumMultiSelectPrompt,
showNextStepsPrompt,
showNumberPrompt,
showNumSelectPrompt,
showPasswordPrompt,
showResults,
showStartPrompt,
showTextPrompt,
showSelectPrompt,
showMultiSelectPrompt,
} from "@/reliverse/main-prompts";
import { type UserInput } from "@/reliverse/main-schema";

import { multiSelectPrompt } from "~/components/multi-select";
import { selectPrompt } from "~/components/select";
import { errorHandler } from "~/utils/errors";

export async function detailedExample() {
await showStartPrompt();
await showAnyKeyPrompt("privacy");

const selectOptions = ["Option 1", "Option 2", "Option 3", "Option 4"];
const multiSelectOptions = ["Option 1", "Option 2", "Option 3", "Option 4"];

const selectedOption = await selectPrompt(selectOptions);
console.log(`You selected: ${selectedOption}`);

const selectedOptions = await multiSelectPrompt(multiSelectOptions);
console.log("You selected:");
selectedOptions.forEach((option) => console.log(option));

const username = await showTextPrompt();
const dir = await askDir(username);
const age = await showNumberPrompt();
const lang = await showSelectPrompt();
const color = await showNumSelectPrompt();
const password = await showPasswordPrompt();
const birthday = await showDatePrompt();
// const features = await showMultiSelectPrompt();
const features = ["Feature 1", "Feature 2", "Feature 3"];
const deps = await showConfirmPrompt(username);
const langs = await showMultiSelectPrompt();
const features = await showNumMultiSelectPrompt();
// const deps = await showConfirmPrompt(username);
const userInput = {
username,
dir,
age,
lang,
color,
password,
birthday,
langs,
features,
deps,
// deps,
} satisfies UserInput;
await showResults(userInput);
await doSomeFunStuff(userInput);
// await showResults(userInput);
// await doSomeFunStuff(userInput);
await showNextStepsPrompt();
await showAnimatedText();
await showEndPrompt();
Expand Down
6 changes: 3 additions & 3 deletions examples/4-experimental.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { TreeItem } from "~/utils/helpers/utils/tree";
import type { TreeItem } from "~/components/modules/helpers/tree";

import { relinka, createRelinka } from "~/components/modules";
import { formatTree } from "~/components/modules/helpers/tree";
import { errorHandler } from "~/utils/errors";
import { relinka, createRelinka } from "~/utils/helpers";
import { formatTree } from "~/utils/helpers/utils/tree";

import { reporterDemo } from "./reliverse/experiments/utils";

Expand Down
2 changes: 1 addition & 1 deletion examples/reliverse/experiments/state/main-with-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { nextStepsPrompt } from "~/components/next-steps";
// import { multiSelectPrompt } from "~/components/num-multi-select";
import { numberPrompt } from "~/components/number";
import { passwordPrompt } from "~/components/password";
import { selectPrompt } from "~/components/select";
import { selectPrompt } from "~/components/select-2";

import type { PromptOptionsWithState } from "./types-wth-state";

Expand Down
4 changes: 2 additions & 2 deletions examples/reliverse/experiments/tests/relinka.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { describe, test, expect } from "vitest";

import type { RelinkaReporter, LogObject } from "~/utils/helpers";
import type { RelinkaReporter, LogObject } from "~/components/modules";

import { LogLevels, createRelinka } from "~/utils/helpers";
import { LogLevels, createRelinka } from "~/components/modules";

describe("relinka", () => {
test("can set level", () => {
Expand Down
4 changes: 2 additions & 2 deletions examples/reliverse/experiments/tmp/main-2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export async function prompts<T extends TSchema>(
value = await selectPrompt(options);
break;
case "multiselect":
value = await multisSlectPrompt(options);
value = await multiSelectPrompt(options);
break;
case "password":
value = await passwordPrompt(options);
Expand Down Expand Up @@ -259,7 +259,7 @@ async function selectPrompt<T extends TSchema>(
}
}

async function multisSlectPrompt<T extends TSchema>(
async function multiSelectPrompt<T extends TSchema>(
options: PromptOptions<T>,
): Promise<Static<T>> {
const { title, choices, schema } = options;
Expand Down
6 changes: 3 additions & 3 deletions examples/reliverse/experiments/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { RelinkaOptions } from "~/utils/helpers";
import type { RelinkaOptions } from "~/components/modules";

import { createRelinka } from "~/utils/helpers";
import { createRelinka } from "~/components/modules";

import { randomSentence } from "./sentence";

Expand All @@ -22,7 +22,7 @@ export function reporterDemo(

relinka.error(new Error(randomSentence()));

const tagged = relinka.withTag("unjs").withTag("router");
const tagged = relinka.withTag("reliverse").withTag("relinka");

for (const type of Object.keys(relinka.options.types).sort()) {
tagged[type](randomSentence());
Expand Down
96 changes: 72 additions & 24 deletions examples/reliverse/main-prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { emojify } from "node-emoji";
import { bold } from "picocolors";

import { pressAnyKeyPrompt } from "~/components/any-key";
import { relinka } from "~/components/modules";
import { numSelectPrompt } from "~/components/num-select";
import { promptsDisplayResults } from "~/components/results";
import {
Expand All @@ -12,11 +13,11 @@ import {
datePrompt,
endPrompt,
msg,
multiSelectPrompt,
numMultiSelectPrompt,
nextStepsPrompt,
numberPrompt,
passwordPrompt,
selectPrompt,
// selectPrompt,
spinnerPrompts,
startPrompt,
textPrompt,
Expand All @@ -39,7 +40,7 @@ const IDs = {
deps: "deps",
password: "password",
age: "age",
language: "language",
lang: "lang",
color: "color",
birthday: "birthday",
features: "features",
Expand Down Expand Up @@ -109,22 +110,23 @@ export async function showNumberPrompt(): Promise<UserInput["age"]> {
return age ?? 34;
}

// TODO: fix, currently works only if it's the first prompt
// export async function showSelectPrompt(): Promise<string> {
// const language = await selectPrompt({
// id: IDs.language,
// title: "Choose your language",
// choices: [
// {
// title: "English",
// id: "en",
// },
// { title: "Other", id: "other" },
// ],
// });
export async function showSelectPrompt(): Promise<string> {
const lang = await relinka.prompt("Choose your language", {
type: "select",
options: [
{ label: "English", value: "English" },
{ label: "Ukrainian", value: "Ukrainian" },
{ label: "Other", value: "Other" },
],
initial: "English",
});

if (typeof lang !== "string") {
process.exit(0);
}

// return language ?? "";
// }
return lang.toString();
}

export async function showNumSelectPrompt(): Promise<UserInput["color"]> {
const choices = createColorChoices();
Expand Down Expand Up @@ -188,8 +190,53 @@ export async function showDatePrompt(): Promise<UserInput["birthday"]> {
return birthdayDate ?? "16.11.1988";
}

/* export async function showMultiSelectPrompt(): Promise<UserInput["features"]> {
const features = await multiSelectPrompt({
export async function showMultiSelectPrompt(): Promise<string[]> {
const features = await relinka.prompt(
"Select your programming language(s) | Use <space> to select/deselect",
{
type: "multiselect",
options: [
{
label: "TypeScript",
value: "typescript",
hint: emojify(":blue_heart:"),
},
{
label: "JavaScript",
value: "javascript",
hint: emojify(":yellow_heart:"),
},
{
label: "CoffeeScript",
value: "coffeescript",
hint: emojify(":coffee:"),
},
{
label: "Python",
value: "python",
hint: emojify(":snake:"),
},
{ label: "Java", value: "java", hint: emojify(":coffee:") },
{ label: "C#", value: "csharp", hint: emojify(":hash:") },
{ label: "Go", value: "go", hint: emojify(":dolphin:") },
{ label: "Rust", value: "rust", hint: emojify(":crab:") },
{ label: "Swift", value: "swift", hint: emojify(":apple:") },
],
initial: ["javascript", "typescript"],
},
);

if (!Array.isArray(features)) {
process.exit(0);
}

return features.toString().split(",");
}

export async function showNumMultiSelectPrompt(): Promise<
UserInput["features"]
> {
const features = await numMultiSelectPrompt({
id: IDs.features,
title: "What features do you want to use?",
defaultValue: ["react", "typescript"],
Expand All @@ -215,9 +262,10 @@ export async function showDatePrompt(): Promise<UserInput["birthday"]> {
schema: schema.properties.features,
});
return features ?? ["react", "typescript"];
} */
}

export async function showConfirmPrompt(
// TODO: fix bun crash
/* export async function showConfirmPrompt(
username: string,
): Promise<UserInput["deps"]> {
await showAnyKeyPrompt("pm", username);
Expand All @@ -240,7 +288,7 @@ export async function showConfirmPrompt(
});
// A return value is unnecessary for prompts when the result is not needed later.
return deps ?? false;
}
} */

// Prompt ID is not required for the following
// components, as they don't return any values.
Expand Down Expand Up @@ -301,7 +349,7 @@ export async function showEndPrompt() {
await endPrompt({
id: "end",
title: emojify(
"ℹ :books: Learn the docs here: https://docs.reliverse.org/prompts",
"ℹ :books: Learn the docs here: https://docs.reliverse.org/relinka",
),
titleAnimation: "glitch",
...basicConfig,
Expand Down
6 changes: 4 additions & 2 deletions examples/reliverse/main-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { colorMap } from "~/utils/mapping";
const colorKeys = Object.keys(colorMap) as [keyof typeof colorMap];

// You can find the schema templates like this
// one at https://docs.reliverse.org/prompts
// one at https://docs.reliverse.org/relinka
const colorSchema = Type.Enum(
Object.keys(colorMap).reduce(
(acc, key) => {
Expand All @@ -25,11 +25,13 @@ export const schema = Type.Object({
pattern: "^[a-zA-Z0-9\u0400-\u04FF]+$",
}),
dir: Type.String({ minLength: 1 }),
deps: Type.Boolean(),
// deps: Type.Boolean(),
password: Type.String({ minLength: 4 }),
age: Type.Number({ minimum: 18, maximum: 99 }),
lang: Type.String(),
color: colorSchema,
birthday: Type.String({ minLength: 10, maxLength: 10 }),
langs: Type.Array(Type.String()),
features: Type.Array(Type.String()),
});

Expand Down
Loading

0 comments on commit 82478c5

Please sign in to comment.