giggles 0.3.11 → 0.3.12

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.
@@ -0,0 +1,56 @@
1
+ // src/terminal/hooks/useTerminalFocus.ts
2
+ import { useEffect, useRef } from "react";
3
+ function useTerminalFocus(callback) {
4
+ const callbackRef = useRef(callback);
5
+ callbackRef.current = callback;
6
+ useEffect(() => {
7
+ const handler = (data) => {
8
+ const str = data.toString();
9
+ if (str.includes("\x1B[I")) callbackRef.current(true);
10
+ if (str.includes("\x1B[O")) callbackRef.current(false);
11
+ };
12
+ process.stdin.on("data", handler);
13
+ const timer = setTimeout(() => {
14
+ process.stdout.write("\x1B[?1004h");
15
+ }, 0);
16
+ return () => {
17
+ clearTimeout(timer);
18
+ process.stdout.write("\x1B[?1004l");
19
+ process.stdin.off("data", handler);
20
+ };
21
+ }, []);
22
+ }
23
+
24
+ // src/terminal/hooks/useShellout.ts
25
+ import { execa } from "execa";
26
+ import { useCallback, useState } from "react";
27
+ import { useStdin } from "ink";
28
+ function useShellOut() {
29
+ const [, setRedrawCount] = useState(0);
30
+ const { setRawMode } = useStdin();
31
+ const run = useCallback(
32
+ async (command) => {
33
+ process.stdout.write("\x1B[?1049l");
34
+ setRawMode(false);
35
+ try {
36
+ const result = await execa(command, { stdio: "inherit", shell: true, reject: false });
37
+ return { exitCode: result.exitCode ?? 0 };
38
+ } finally {
39
+ setRawMode(true);
40
+ process.stdout.write("\x1B[?1049h");
41
+ process.stdout.write("\x1B[2J");
42
+ process.stdout.write("\x1B[H");
43
+ setRedrawCount((c) => c + 1);
44
+ }
45
+ },
46
+ [setRawMode]
47
+ );
48
+ return {
49
+ run
50
+ };
51
+ }
52
+
53
+ export {
54
+ useTerminalFocus,
55
+ useShellOut
56
+ };
@@ -0,0 +1,49 @@
1
+ // src/terminal/hooks/useTerminalSize.ts
2
+ import { useEffect, useState } from "react";
3
+ function useTerminalSize() {
4
+ const [size, setSize] = useState({
5
+ rows: process.stdout.rows,
6
+ columns: process.stdout.columns
7
+ });
8
+ useEffect(() => {
9
+ const handleResize = () => {
10
+ setSize({
11
+ rows: process.stdout.rows,
12
+ columns: process.stdout.columns
13
+ });
14
+ };
15
+ process.stdout.on("resize", handleResize);
16
+ return () => {
17
+ process.stdout.off("resize", handleResize);
18
+ };
19
+ }, []);
20
+ return size;
21
+ }
22
+
23
+ // src/terminal/components/AlternateScreen.tsx
24
+ import { useEffect as useEffect2, useState as useState2 } from "react";
25
+ import { Box } from "ink";
26
+ import { Fragment, jsx } from "react/jsx-runtime";
27
+ var _a;
28
+ var isTTY = typeof process !== "undefined" && ((_a = process.stdout) == null ? void 0 : _a.write);
29
+ function AlternateScreen({ children, fullScreen = true }) {
30
+ const [ready, setReady] = useState2(!isTTY);
31
+ const { rows, columns } = useTerminalSize();
32
+ useEffect2(() => {
33
+ if (!isTTY) return;
34
+ process.stdout.write("\x1B[?1049h");
35
+ process.stdout.write("\x1B[2J");
36
+ process.stdout.write("\x1B[H");
37
+ setReady(true);
38
+ return () => {
39
+ process.stdout.write("\x1B[?1049l");
40
+ };
41
+ }, []);
42
+ if (!ready) return null;
43
+ return fullScreen ? /* @__PURE__ */ jsx(Box, { height: rows, width: columns, children }) : /* @__PURE__ */ jsx(Fragment, { children });
44
+ }
45
+
46
+ export {
47
+ useTerminalSize,
48
+ AlternateScreen
49
+ };
@@ -3,8 +3,8 @@ import {
3
3
  } from "./chunk-EVD6YPS3.js";
4
4
 
5
5
  // src/ui/CodeBlock.tsx
6
- import Prism from "prismjs";
7
6
  import { Box, Text } from "ink";
7
+ import Prism from "prismjs";
8
8
  import { jsx } from "react/jsx-runtime";
9
9
  var defaultTokenColors = {
10
10
  keyword: "#C678DD",
@@ -22,15 +22,12 @@ var defaultTokenColors = {
22
22
  inserted: "#98C379",
23
23
  deleted: "#E06C75"
24
24
  };
25
- function CodeBlock({ children, language, showBorder = true, tokenColors }) {
25
+ function CodeBlock({ children, language, tokenColors, ...boxProps }) {
26
26
  const theme = useTheme();
27
27
  const colors = { ...defaultTokenColors, ...tokenColors };
28
28
  const grammar = language ? Prism.languages[language] : void 0;
29
29
  const content = grammar ? renderTokens(Prism.tokenize(children, grammar), colors) : /* @__PURE__ */ jsx(Text, { children });
30
- if (!showBorder) {
31
- return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: content }) });
32
- }
33
- return /* @__PURE__ */ jsx(Box, { paddingX: 1, borderStyle: "single", borderColor: theme.borderColor, children: /* @__PURE__ */ jsx(Text, { children: content }) });
30
+ return /* @__PURE__ */ jsx(Box, { paddingX: 1, borderStyle: "round", borderColor: theme.borderColor, ...boxProps, children: /* @__PURE__ */ jsx(Text, { children: content }) });
34
31
  }
35
32
  function renderTokens(tokens, colors) {
36
33
  return tokens.map((token, idx) => {
package/dist/index.d.ts CHANGED
@@ -30,9 +30,10 @@ declare function useTheme(): GigglesTheme;
30
30
 
31
31
  type GigglesProviderProps = {
32
32
  theme?: Partial<GigglesTheme>;
33
+ fullScreen?: boolean;
33
34
  children: React__default.ReactNode;
34
35
  };
35
- declare function GigglesProvider({ theme, children }: GigglesProviderProps): react_jsx_runtime.JSX.Element;
36
+ declare function GigglesProvider({ theme, fullScreen, children }: GigglesProviderProps): react_jsx_runtime.JSX.Element;
36
37
 
37
38
  declare function useKeybindings(focus: FocusHandle, bindings: Keybindings, options?: KeybindingOptions): void;
38
39
 
package/dist/index.js CHANGED
@@ -1,6 +1,3 @@
1
- import {
2
- AlternateScreen
3
- } from "./chunk-7PDVDYFB.js";
4
1
  import {
5
2
  FocusGroup,
6
3
  FocusNodeContext,
@@ -19,11 +16,14 @@ import {
19
16
  ThemeProvider,
20
17
  useTheme
21
18
  } from "./chunk-EVD6YPS3.js";
19
+ import {
20
+ AlternateScreen
21
+ } from "./chunk-5BONVNP7.js";
22
22
 
23
23
  // src/core/GigglesProvider.tsx
24
24
  import { jsx } from "react/jsx-runtime";
25
- function GigglesProvider({ theme, children }) {
26
- return /* @__PURE__ */ jsx(AlternateScreen, { children: /* @__PURE__ */ jsx(ThemeProvider, { theme, children: /* @__PURE__ */ jsx(FocusProvider, { children: /* @__PURE__ */ jsx(InputProvider, { children: /* @__PURE__ */ jsx(InputRouter, { children }) }) }) }) });
25
+ function GigglesProvider({ theme, fullScreen, children }) {
26
+ return /* @__PURE__ */ jsx(AlternateScreen, { fullScreen, children: /* @__PURE__ */ jsx(ThemeProvider, { theme, children: /* @__PURE__ */ jsx(FocusProvider, { children: /* @__PURE__ */ jsx(InputProvider, { children: /* @__PURE__ */ jsx(InputRouter, { children }) }) }) }) });
27
27
  }
28
28
 
29
29
  // src/core/router/Router.tsx
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CodeBlock
3
- } from "../chunk-WJRBHS5J.js";
3
+ } from "../chunk-JTJH45JR.js";
4
4
  import {
5
5
  useTheme
6
6
  } from "../chunk-EVD6YPS3.js";
@@ -10,9 +10,11 @@ declare function useTerminalSize(): TerminalSize;
10
10
 
11
11
  declare function useTerminalFocus(callback: (focused: boolean) => void): void;
12
12
 
13
- declare function AlternateScreen({ children }: {
13
+ type AlternateScreenProps = {
14
14
  children: ReactNode;
15
- }): react_jsx_runtime.JSX.Element | null;
15
+ fullScreen?: boolean;
16
+ };
17
+ declare function AlternateScreen({ children, fullScreen }: AlternateScreenProps): react_jsx_runtime.JSX.Element | null;
16
18
 
17
19
  declare function useShellOut(): {
18
20
  run: (command: string) => Promise<{
@@ -1,80 +1,11 @@
1
1
  import {
2
- AlternateScreen
3
- } from "../chunk-7PDVDYFB.js";
4
-
5
- // src/terminal/hooks/useTerminalSize.ts
6
- import { useEffect, useState } from "react";
7
- function useTerminalSize() {
8
- const [size, setSize] = useState({
9
- rows: process.stdout.rows,
10
- columns: process.stdout.columns
11
- });
12
- useEffect(() => {
13
- const handleResize = () => {
14
- setSize({
15
- rows: process.stdout.rows,
16
- columns: process.stdout.columns
17
- });
18
- };
19
- process.stdout.on("resize", handleResize);
20
- return () => {
21
- process.stdout.off("resize", handleResize);
22
- };
23
- }, []);
24
- return size;
25
- }
26
-
27
- // src/terminal/hooks/useTerminalFocus.ts
28
- import { useEffect as useEffect2, useRef } from "react";
29
- function useTerminalFocus(callback) {
30
- const callbackRef = useRef(callback);
31
- callbackRef.current = callback;
32
- useEffect2(() => {
33
- const handler = (data) => {
34
- const str = data.toString();
35
- if (str.includes("\x1B[I")) callbackRef.current(true);
36
- if (str.includes("\x1B[O")) callbackRef.current(false);
37
- };
38
- process.stdin.on("data", handler);
39
- const timer = setTimeout(() => {
40
- process.stdout.write("\x1B[?1004h");
41
- }, 0);
42
- return () => {
43
- clearTimeout(timer);
44
- process.stdout.write("\x1B[?1004l");
45
- process.stdin.off("data", handler);
46
- };
47
- }, []);
48
- }
49
-
50
- // src/terminal/hooks/useShellout.ts
51
- import { execa } from "execa";
52
- import { useCallback, useState as useState2 } from "react";
53
- import { useStdin } from "ink";
54
- function useShellOut() {
55
- const [, setRedrawCount] = useState2(0);
56
- const { setRawMode } = useStdin();
57
- const run = useCallback(
58
- async (command) => {
59
- process.stdout.write("\x1B[?1049l");
60
- setRawMode(false);
61
- try {
62
- const result = await execa(command, { stdio: "inherit", shell: true, reject: false });
63
- return { exitCode: result.exitCode ?? 0 };
64
- } finally {
65
- setRawMode(true);
66
- process.stdout.write("\x1B[?1049h");
67
- process.stdout.write("\x1B[2J");
68
- process.stdout.write("\x1B[H");
69
- setRedrawCount((c) => c + 1);
70
- }
71
- },
72
- [setRawMode]
73
- );
74
- return {
75
- run
76
- };
77
- }
2
+ useShellOut,
3
+ useTerminalFocus
4
+ } from "../chunk-4LEJFY5C.js";
5
+ import {
6
+ AlternateScreen,
7
+ useTerminalSize
8
+ } from "../chunk-5BONVNP7.js";
78
9
  export {
79
10
  AlternateScreen,
80
11
  useShellOut,
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { R as RegisteredKeybinding } from '../types-Dmw9TKt4.js';
3
3
  import React__default from 'react';
4
- import 'ink';
4
+ import { BoxProps } from 'ink';
5
5
 
6
6
  type CommandPaletteRenderProps = {
7
7
  query: string;
@@ -162,14 +162,12 @@ type ViewportProps = {
162
162
  };
163
163
  declare const Viewport: React__default.ForwardRefExoticComponent<ViewportProps & React__default.RefAttributes<ViewportRef>>;
164
164
 
165
- type BorderStyle = 'single' | 'double' | 'round' | 'bold' | 'singleDouble' | 'doubleSingle' | 'classic' | 'arrow';
166
- type ModalProps = {
165
+ type ModalProps = Omit<BoxProps, 'children'> & {
167
166
  children: React__default.ReactNode;
168
167
  onClose: () => void;
169
168
  title?: string;
170
- borderStyle?: BorderStyle;
171
169
  };
172
- declare function Modal({ children, onClose, title, borderStyle }: ModalProps): react_jsx_runtime.JSX.Element;
170
+ declare function Modal({ children, onClose, title, ...boxProps }: ModalProps): react_jsx_runtime.JSX.Element;
173
171
 
174
172
  type BadgeVariant = 'round' | 'arrow' | 'plain';
175
173
  type BadgeProps = {
@@ -180,14 +178,12 @@ type BadgeProps = {
180
178
  };
181
179
  declare function Badge({ children, color, background, variant }: BadgeProps): react_jsx_runtime.JSX.Element;
182
180
 
183
- type PanelProps = {
181
+ type PanelProps = Omit<BoxProps, 'children'> & {
184
182
  children: React__default.ReactNode;
185
183
  title?: string;
186
- width?: number;
187
- borderColor?: string;
188
184
  footer?: React__default.ReactNode;
189
185
  };
190
- declare function Panel({ children, title, width, borderColor, footer }: PanelProps): react_jsx_runtime.JSX.Element;
186
+ declare function Panel({ children, title, width, borderColor, footer, ...boxProps }: PanelProps): react_jsx_runtime.JSX.Element;
191
187
 
192
188
  type TokenColors = {
193
189
  keyword: string;
@@ -205,13 +201,12 @@ type TokenColors = {
205
201
  inserted: string;
206
202
  deleted: string;
207
203
  };
208
- type CodeBlockProps = {
204
+ type CodeBlockProps = Omit<BoxProps, 'children'> & {
209
205
  children: string;
210
206
  language?: string;
211
- showBorder?: boolean;
212
207
  tokenColors?: Partial<TokenColors>;
213
208
  };
214
- declare function CodeBlock({ children, language, showBorder, tokenColors }: CodeBlockProps): react_jsx_runtime.JSX.Element;
209
+ declare function CodeBlock({ children, language, tokenColors, ...boxProps }: CodeBlockProps): react_jsx_runtime.JSX.Element;
215
210
 
216
211
  type SpinnerDef = {
217
212
  frames: string[];
package/dist/ui/index.js CHANGED
@@ -7,10 +7,14 @@ import {
7
7
  } from "../chunk-CKA5JJ4B.js";
8
8
  import {
9
9
  CodeBlock
10
- } from "../chunk-WJRBHS5J.js";
10
+ } from "../chunk-JTJH45JR.js";
11
11
  import {
12
12
  useTheme
13
13
  } from "../chunk-EVD6YPS3.js";
14
+ import "../chunk-4LEJFY5C.js";
15
+ import {
16
+ useTerminalSize
17
+ } from "../chunk-5BONVNP7.js";
14
18
 
15
19
  // src/ui/CommandPalette.tsx
16
20
  import { useState } from "react";
@@ -821,7 +825,7 @@ var Viewport = forwardRef(function Viewport2({ children, height, keybindings: en
821
825
  // src/ui/Modal.tsx
822
826
  import { Box as Box8, Text as Text8 } from "ink";
823
827
  import { jsx as jsx9, jsxs as jsxs10 } from "react/jsx-runtime";
824
- function ModalInner({ children, onClose, title, borderStyle = "round" }) {
828
+ function ModalInner({ children, onClose, title, ...boxProps }) {
825
829
  const focus = useFocus();
826
830
  const theme = useTheme();
827
831
  useKeybindings(focus, {
@@ -832,9 +836,10 @@ function ModalInner({ children, onClose, title, borderStyle = "round" }) {
832
836
  {
833
837
  flexDirection: "column",
834
838
  alignSelf: "flex-start",
835
- borderStyle,
839
+ borderStyle: "round",
836
840
  borderColor: theme.borderColor,
837
841
  paddingX: 1,
842
+ ...boxProps,
838
843
  children: [
839
844
  title != null && /* @__PURE__ */ jsx9(Text8, { bold: true, children: title }),
840
845
  children
@@ -842,8 +847,8 @@ function ModalInner({ children, onClose, title, borderStyle = "round" }) {
842
847
  }
843
848
  );
844
849
  }
845
- function Modal({ children, onClose, title, borderStyle }) {
846
- return /* @__PURE__ */ jsx9(FocusTrap, { children: /* @__PURE__ */ jsx9(ModalInner, { onClose, title, borderStyle, children }) });
850
+ function Modal({ children, onClose, title, ...boxProps }) {
851
+ return /* @__PURE__ */ jsx9(FocusTrap, { children: /* @__PURE__ */ jsx9(ModalInner, { onClose, title, ...boxProps, children }) });
847
852
  }
848
853
 
849
854
  // src/ui/Badge.tsx
@@ -871,11 +876,17 @@ function Badge({ children, color, background, variant = "round" }) {
871
876
  import { useState as useState7 } from "react";
872
877
  import { Box as Box9, Text as Text10, measureElement as measureElement2 } from "ink";
873
878
  import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs12 } from "react/jsx-runtime";
874
- function Panel({ children, title, width, borderColor, footer }) {
879
+ function parsePercentage(value, total) {
880
+ const pct = parseFloat(value);
881
+ return isNaN(pct) ? 0 : Math.floor(pct / 100 * total);
882
+ }
883
+ function Panel({ children, title, width, borderColor, footer, ...boxProps }) {
875
884
  const theme = useTheme();
885
+ const { columns } = useTerminalSize();
876
886
  const color = borderColor ?? theme.borderColor;
877
- const [measuredWidth, setMeasuredWidth] = useState7(width ?? 0);
878
- const effectiveWidth = width ?? measuredWidth;
887
+ const initialWidth = typeof width === "number" ? width : typeof width === "string" && width.endsWith("%") ? parsePercentage(width, columns) : 0;
888
+ const [measuredWidth, setMeasuredWidth] = useState7(initialWidth);
889
+ const effectiveWidth = typeof width === "number" ? width : measuredWidth;
879
890
  const renderTopBorder = () => {
880
891
  if (effectiveWidth === 0) return null;
881
892
  if (title == null) {
@@ -908,9 +919,10 @@ function Panel({ children, title, width, borderColor, footer }) {
908
919
  ref: (node) => {
909
920
  if (node) {
910
921
  const { width: w } = measureElement2(node);
911
- if (w !== measuredWidth) setMeasuredWidth(w);
922
+ if (w > 0 && w !== measuredWidth) setMeasuredWidth(w);
912
923
  }
913
924
  },
925
+ ...boxProps,
914
926
  children: [
915
927
  renderTopBorder(),
916
928
  /* @__PURE__ */ jsx11(Box9, { flexDirection: "column", flexGrow: 1, borderStyle: "round", borderTop: false, borderColor: color, paddingX: 1, children: footer ? /* @__PURE__ */ jsxs12(Fragment3, { children: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "giggles",
3
- "version": "0.3.11",
3
+ "version": "0.3.12",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,23 +0,0 @@
1
- // src/terminal/components/AlternateScreen.tsx
2
- import { useEffect, useState } from "react";
3
- import { Fragment, jsx } from "react/jsx-runtime";
4
- var _a;
5
- var isTTY = typeof process !== "undefined" && ((_a = process.stdout) == null ? void 0 : _a.write);
6
- function AlternateScreen({ children }) {
7
- const [ready, setReady] = useState(!isTTY);
8
- useEffect(() => {
9
- if (!isTTY) return;
10
- process.stdout.write("\x1B[?1049h");
11
- process.stdout.write("\x1B[2J");
12
- process.stdout.write("\x1B[H");
13
- setReady(true);
14
- return () => {
15
- process.stdout.write("\x1B[?1049l");
16
- };
17
- }, []);
18
- return ready ? /* @__PURE__ */ jsx(Fragment, { children }) : null;
19
- }
20
-
21
- export {
22
- AlternateScreen
23
- };