@kud/ink-ui 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -94,6 +94,25 @@ type TextInputProps = {
94
94
  };
95
95
  declare const TextInput: ({ placeholder, defaultValue, onChange, onSubmit, isDisabled, }: TextInputProps) => React.JSX.Element;
96
96
 
97
+ type EmailInputProps = {
98
+ placeholder?: string;
99
+ defaultValue?: string;
100
+ domains?: string[];
101
+ onChange?: (value: string) => void;
102
+ onSubmit?: (value: string) => void;
103
+ isDisabled?: boolean;
104
+ };
105
+ declare const EmailInput: ({ placeholder, defaultValue, domains, onChange, onSubmit, isDisabled, }: EmailInputProps) => React.JSX.Element;
106
+
107
+ type PasswordInputProps = {
108
+ placeholder?: string;
109
+ mask?: string;
110
+ onChange?: (value: string) => void;
111
+ onSubmit?: (value: string) => void;
112
+ isDisabled?: boolean;
113
+ };
114
+ declare const PasswordInput: ({ placeholder, mask, onChange, onSubmit, isDisabled, }: PasswordInputProps) => React.JSX.Element;
115
+
97
116
  type ConfirmInputProps = {
98
117
  defaultChoice?: "confirm" | "cancel";
99
118
  onConfirm?: () => void;
@@ -102,6 +121,27 @@ type ConfirmInputProps = {
102
121
  };
103
122
  declare const ConfirmInput: ({ defaultChoice, onConfirm, onCancel, isDisabled, }: ConfirmInputProps) => React.JSX.Element;
104
123
 
124
+ type ItemProps$1 = {
125
+ children: React.ReactNode;
126
+ };
127
+ type UnorderedListProps = {
128
+ children: React.ReactNode;
129
+ };
130
+ declare const UnorderedList: (({ children }: UnorderedListProps) => React.JSX.Element) & {
131
+ Item: ({ children }: ItemProps$1) => React.JSX.Element;
132
+ };
133
+
134
+ type ItemProps = {
135
+ children: React.ReactNode;
136
+ _index?: number;
137
+ };
138
+ type OrderedListProps = {
139
+ children: React.ReactNode;
140
+ };
141
+ declare const OrderedList: (({ children }: OrderedListProps) => React.JSX.Element) & {
142
+ Item: ({ children, _index }: ItemProps) => React.JSX.Element;
143
+ };
144
+
105
145
  type Span = {
106
146
  text: string;
107
147
  color?: string;
@@ -119,8 +159,9 @@ type StyledLine = {
119
159
  type ScrollViewProps = {
120
160
  lines: StyledLine[];
121
161
  showIndicator?: boolean;
162
+ initialStart?: number;
122
163
  };
123
- declare const ScrollView: ({ lines, showIndicator, }: ScrollViewProps) => React.JSX.Element;
164
+ declare const ScrollView: ({ lines, showIndicator, initialStart, }: ScrollViewProps) => React.JSX.Element;
124
165
 
125
166
  type TabItem<T extends string = string> = {
126
167
  value: T;
@@ -206,4 +247,4 @@ declare const spacing: {
206
247
  };
207
248
  type Spacing = (typeof spacing)[keyof typeof spacing];
208
249
 
209
- export { Alert, Badge, type BadgeVariant, Banner, type Color, type Column, ConfirmInput, FooterHints, Header, type Hint, type IconMode, KeyValue, LoadingScreen, MultiSelect, type NotifyOptions, ProgressBar, ScrollView, Select, type SelectOption, SelectableRow, type Spacing, type Span, Spinner, StatusMessage, type StatusVariant, type StyledLine, Switch, type SwitchValue, type TabItem, Table, Tabs, TextInput, Toast, Toggle, colors, getIconMode, notify, setIconMode, spacing };
250
+ export { Alert, Badge, type BadgeVariant, Banner, type Color, type Column, ConfirmInput, EmailInput, FooterHints, Header, type Hint, type IconMode, KeyValue, LoadingScreen, MultiSelect, type NotifyOptions, OrderedList, PasswordInput, ProgressBar, ScrollView, Select, type SelectOption, SelectableRow, type Spacing, type Span, Spinner, StatusMessage, type StatusVariant, type StyledLine, Switch, type SwitchValue, type TabItem, Table, Tabs, TextInput, Toast, Toggle, UnorderedList, colors, getIconMode, notify, setIconMode, spacing };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Box, Text, useInput, measureElement } from 'ink';
2
- import { jsxs, jsx } from 'react/jsx-runtime';
3
- import { useState, useEffect, useRef, useLayoutEffect } from 'react';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import React8, { createContext, useContext, useState, useEffect, useRef, useLayoutEffect } from 'react';
4
4
  import cliSpinners from 'cli-spinners';
5
5
  import { glyphs } from '@kud/glyphs';
6
6
  import { spawn } from 'child_process';
@@ -223,6 +223,148 @@ var TextInput = ({
223
223
  after
224
224
  ] });
225
225
  };
226
+ var defaultDomains = [
227
+ "gmail.com",
228
+ "outlook.com",
229
+ "hotmail.com",
230
+ "yahoo.com",
231
+ "icloud.com",
232
+ "proton.me"
233
+ ];
234
+ var EmailInput = ({
235
+ placeholder = "",
236
+ defaultValue = "",
237
+ domains = defaultDomains,
238
+ onChange,
239
+ onSubmit,
240
+ isDisabled = false
241
+ }) => {
242
+ const [value, setValue] = useState(defaultValue);
243
+ const [cursor, setCursor] = useState(defaultValue.length);
244
+ const at = value.indexOf("@");
245
+ const domainFragment = at === -1 ? "" : value.slice(at + 1);
246
+ const match = at !== -1 && domainFragment.length > 0 ? domains.find(
247
+ (d) => d.startsWith(domainFragment) && d !== domainFragment
248
+ ) : void 0;
249
+ const suggestion = match ? match.slice(domainFragment.length) : "";
250
+ const showSuggestion = suggestion.length > 0 && cursor === value.length;
251
+ const update = (nextValue, nextCursor) => {
252
+ setValue(nextValue);
253
+ setCursor(nextCursor);
254
+ onChange?.(nextValue);
255
+ };
256
+ useInput(
257
+ (input, key) => {
258
+ if (key.return) {
259
+ onSubmit?.(value);
260
+ return;
261
+ }
262
+ if (key.tab && showSuggestion) {
263
+ update(value + suggestion, value.length + suggestion.length);
264
+ return;
265
+ }
266
+ if (key.leftArrow) {
267
+ setCursor((c) => Math.max(0, c - 1));
268
+ return;
269
+ }
270
+ if (key.rightArrow) {
271
+ setCursor((c) => Math.min(value.length, c + 1));
272
+ return;
273
+ }
274
+ if (key.backspace || key.delete) {
275
+ if (cursor === 0) return;
276
+ update(value.slice(0, cursor - 1) + value.slice(cursor), cursor - 1);
277
+ return;
278
+ }
279
+ if (input && !key.ctrl && !key.meta && !key.tab) {
280
+ update(
281
+ value.slice(0, cursor) + input + value.slice(cursor),
282
+ cursor + input.length
283
+ );
284
+ }
285
+ },
286
+ { isActive: !isDisabled }
287
+ );
288
+ if (value.length === 0) {
289
+ return /* @__PURE__ */ jsxs(Text, { children: [
290
+ /* @__PURE__ */ jsx(Text, { inverse: true, children: " " }),
291
+ placeholder ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: placeholder }) : null
292
+ ] });
293
+ }
294
+ if (showSuggestion) {
295
+ return /* @__PURE__ */ jsxs(Text, { children: [
296
+ value,
297
+ /* @__PURE__ */ jsx(Text, { inverse: true, children: suggestion.slice(0, 1) }),
298
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: suggestion.slice(1) })
299
+ ] });
300
+ }
301
+ const before = value.slice(0, cursor);
302
+ const atChar = value.slice(cursor, cursor + 1) || " ";
303
+ const after = value.slice(cursor + 1);
304
+ return /* @__PURE__ */ jsxs(Text, { children: [
305
+ before,
306
+ /* @__PURE__ */ jsx(Text, { inverse: true, children: atChar }),
307
+ after
308
+ ] });
309
+ };
310
+ var PasswordInput = ({
311
+ placeholder = "",
312
+ mask = "*",
313
+ onChange,
314
+ onSubmit,
315
+ isDisabled = false
316
+ }) => {
317
+ const [value, setValue] = useState("");
318
+ const [cursor, setCursor] = useState(0);
319
+ const update = (nextValue, nextCursor) => {
320
+ setValue(nextValue);
321
+ setCursor(nextCursor);
322
+ onChange?.(nextValue);
323
+ };
324
+ useInput(
325
+ (input, key) => {
326
+ if (key.return) {
327
+ onSubmit?.(value);
328
+ return;
329
+ }
330
+ if (key.leftArrow) {
331
+ setCursor((c) => Math.max(0, c - 1));
332
+ return;
333
+ }
334
+ if (key.rightArrow) {
335
+ setCursor((c) => Math.min(value.length, c + 1));
336
+ return;
337
+ }
338
+ if (key.backspace || key.delete) {
339
+ if (cursor === 0) return;
340
+ update(value.slice(0, cursor - 1) + value.slice(cursor), cursor - 1);
341
+ return;
342
+ }
343
+ if (input && !key.ctrl && !key.meta && !key.tab) {
344
+ update(
345
+ value.slice(0, cursor) + input + value.slice(cursor),
346
+ cursor + input.length
347
+ );
348
+ }
349
+ },
350
+ { isActive: !isDisabled }
351
+ );
352
+ if (value.length === 0) {
353
+ return /* @__PURE__ */ jsxs(Text, { children: [
354
+ /* @__PURE__ */ jsx(Text, { inverse: true, children: " " }),
355
+ placeholder ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: placeholder }) : null
356
+ ] });
357
+ }
358
+ const masked = mask.repeat(value.length);
359
+ const before = masked.slice(0, cursor);
360
+ const at = masked.slice(cursor, cursor + 1) || " ";
361
+ const after = masked.slice(cursor + 1);
362
+ return /* @__PURE__ */ jsxs(Text, { children: [
363
+ before,
364
+ /* @__PURE__ */ jsx(Text, { inverse: true, children: at }),
365
+ after
366
+ ] });
367
+ };
226
368
  var ConfirmInput = ({
227
369
  defaultChoice = "confirm",
228
370
  onConfirm,
@@ -249,13 +391,58 @@ var ConfirmInput = ({
249
391
  const hint = defaultChoice === "confirm" ? "(Y/n)" : "(y/N)";
250
392
  return /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint });
251
393
  };
394
+ var markers = ["\u25CF", "\u25CB", "\u25AA", "\u25AB"];
395
+ var DepthContext = createContext(0);
396
+ var UnorderedListItem = ({ children }) => {
397
+ const depth = useContext(DepthContext);
398
+ const marker = markers[Math.max(0, depth - 1) % markers.length];
399
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
400
+ /* @__PURE__ */ jsxs(Text, { children: [
401
+ marker,
402
+ " "
403
+ ] }),
404
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", children })
405
+ ] });
406
+ };
407
+ var UnorderedListRoot = ({ children }) => {
408
+ const depth = useContext(DepthContext);
409
+ return /* @__PURE__ */ jsx(DepthContext.Provider, { value: depth + 1, children: /* @__PURE__ */ jsx(Box, { flexDirection: "column", children }) });
410
+ };
411
+ var UnorderedList = Object.assign(UnorderedListRoot, {
412
+ Item: UnorderedListItem
413
+ });
414
+ var OrderedListItem = ({ children, _index = 1 }) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
415
+ /* @__PURE__ */ jsxs(Text, { children: [
416
+ _index,
417
+ ". "
418
+ ] }),
419
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", children })
420
+ ] });
421
+ var OrderedListRoot = ({ children }) => {
422
+ let n = 0;
423
+ const numbered = React8.Children.map(children, (child) => {
424
+ if (React8.isValidElement(child) && child.type === OrderedListItem) {
425
+ n += 1;
426
+ return React8.cloneElement(child, {
427
+ _index: n
428
+ });
429
+ }
430
+ return child;
431
+ });
432
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: numbered });
433
+ };
434
+ var OrderedList = Object.assign(OrderedListRoot, {
435
+ Item: OrderedListItem
436
+ });
252
437
  var ScrollView = ({
253
438
  lines,
254
- showIndicator = true
439
+ showIndicator = true,
440
+ initialStart = 0
255
441
  }) => {
256
442
  const ref = useRef(null);
257
443
  const [height, setHeight] = useState(1);
258
- const [start, setStart] = useState(0);
444
+ const [start, setStart] = useState(initialStart);
445
+ useEffect(() => setStart(initialStart), [initialStart]);
259
446
  useLayoutEffect(() => {
260
447
  if (!ref.current) return;
261
448
  const { height: h } = measureElement(ref.current);
@@ -473,4 +660,4 @@ var notify = (message, options = {}) => {
473
660
  child.unref();
474
661
  };
475
662
 
476
- export { Alert, Badge, Banner, ConfirmInput, FooterHints, Header, KeyValue, LoadingScreen, MultiSelect, ProgressBar, ScrollView, Select, SelectableRow, Spinner, StatusMessage, Switch, Table, Tabs, TextInput, Toast, Toggle, colors, getIconMode, notify, setIconMode, spacing };
663
+ export { Alert, Badge, Banner, ConfirmInput, EmailInput, FooterHints, Header, KeyValue, LoadingScreen, MultiSelect, OrderedList, PasswordInput, ProgressBar, ScrollView, Select, SelectableRow, Spinner, StatusMessage, Switch, Table, Tabs, TextInput, Toast, Toggle, UnorderedList, colors, getIconMode, notify, setIconMode, spacing };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kud/ink-ui",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "React component library for Ink CLIs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",