giggles 0.6.1 → 0.6.2

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/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # giggles
6
6
 
7
- ![giggles](https://github.com/user-attachments/assets/c5c7ef05-232f-4180-8b85-0160fb0f083a)
7
+ <img src="https://github.com/user-attachments/assets/c5c7ef05-232f-4180-8b85-0160fb0f083a" width="700" alt="giggles">
8
8
 
9
9
  giggles is a batteries-included react framework for building terminal apps. built on ink, it handles focus, input routing, screen navigation, and theming out of the box so you can skip the plumbing and build.
10
10
 
@@ -30,3 +30,83 @@ npx create-giggles-app
30
30
  ```
31
31
 
32
32
  see [giggles.zzzzion.com](https://giggles.zzzzion.com) for API documentation and live demos.
33
+
34
+ ## giggles/ui
35
+
36
+ ### [select](https://giggles.zzzzion.com/ui/select)
37
+
38
+ <img src="https://github.com/user-attachments/assets/8ce13f75-7a7b-4123-a973-f2992193bf84" width="500" alt="select">
39
+
40
+ ### [multi select](https://giggles.zzzzion.com/ui/multi-select)
41
+
42
+ <img src="https://github.com/user-attachments/assets/24f5d625-6e46-4cb1-8d22-42d40eb48f56" width="500" alt="multi-select">
43
+
44
+ ### [markdown](https://giggles.zzzzion.com/ui/markdown)
45
+
46
+ <img src="https://github.com/user-attachments/assets/1cdb6e84-c714-470a-8cf0-b6abf68b78a9" width="500" alt="markdown">
47
+
48
+ ### [text input](https://giggles.zzzzion.com/ui/text-input)
49
+
50
+ <img src="https://github.com/user-attachments/assets/b56056ca-97e2-4dc2-a1eb-2ee3f4d559e7" width="500" alt="text-input">
51
+
52
+ ### [viewport](https://giggles.zzzzion.com/ui/viewport)
53
+
54
+ <img src="https://github.com/user-attachments/assets/56c6cb6b-b2a7-4803-bed4-c6c6c34042c3" width="500" alt="viewport">
55
+
56
+ ### [code block](https://giggles.zzzzion.com/ui/codeblock)
57
+
58
+ <img src="https://github.com/user-attachments/assets/283dbd7e-326c-4acb-b8c0-d3608722952b" width="500" alt="codeblock">
59
+
60
+ ### [confirm](https://giggles.zzzzion.com/ui/confirm)
61
+
62
+ <img src="https://github.com/user-attachments/assets/b887da72-bf02-4084-b846-8b90cc3c3487" width="500" alt="confirm">
63
+
64
+ ### [spinner](https://giggles.zzzzion.com/ui/spinner)
65
+
66
+ <img src="https://github.com/user-attachments/assets/71aef7f8-e53b-4876-864f-b9b1a5100c5d" width="500" alt="spinner">
67
+
68
+ ### [modal](https://giggles.zzzzion.com/ui/modal)
69
+
70
+ <img src="https://github.com/user-attachments/assets/7415c554-927e-4b5c-91d7-7e3b1f4ea0ca" width="500" alt="modal">
71
+
72
+ ### [paginator](https://giggles.zzzzion.com/ui/paginator)
73
+
74
+ <img src="https://github.com/user-attachments/assets/b0780f46-848e-4881-822a-86d7db02d212" width="500" alt="paginator">
75
+
76
+ ### [autocomplete](https://giggles.zzzzion.com/ui/autocomplete)
77
+
78
+ <img src="https://github.com/user-attachments/assets/aa76dd7a-5357-4969-a979-95975b5ec578" width="500" alt="autocomplete">
79
+
80
+ ### [command palette](https://giggles.zzzzion.com/ui/command-palette)
81
+
82
+ <img src="https://github.com/user-attachments/assets/30886cb5-986f-4477-85c1-61cba4b499aa" width="500" alt="command-palette">
83
+
84
+ ### [virtual list](https://giggles.zzzzion.com/ui/virtual-list)
85
+
86
+ <img src="https://github.com/user-attachments/assets/d3ef1d92-813c-4546-8d60-2c38745ddbbc" width="500" alt="virtual-list">
87
+
88
+ ### [badge](https://giggles.zzzzion.com/ui/badge)
89
+
90
+ <img src="https://github.com/user-attachments/assets/b144c3f5-8b3b-4236-abf2-fc239d23f0c6" width="500" alt="badge">
91
+
92
+ ### [panel](https://giggles.zzzzion.com/ui/panel)
93
+
94
+ <img src="https://github.com/user-attachments/assets/9831d73a-baa9-410a-b933-e0dfd9433604" width="500" alt="panel">
95
+
96
+ ## giggles/terminal
97
+
98
+ ### [useShellOut](https://giggles.zzzzion.com/terminal#useshellout)
99
+
100
+ suspend the UI, hand off the terminal to an external program like `vim` or `less`, and resume cleanly when it exits
101
+
102
+ ### [useSpawn](https://giggles.zzzzion.com/terminal#usespawn)
103
+
104
+ spawn a child process and stream its stdout/stderr output into your UI — with support for colored output via a pty
105
+
106
+ ### [useTerminalSize](https://giggles.zzzzion.com/terminal#useterminalsize)
107
+
108
+ reactively track the terminal's current dimensions (rows and columns), updating on resize
109
+
110
+ ### [useTerminalFocus](https://giggles.zzzzion.com/terminal#useterminalfocus)
111
+
112
+ detect when the terminal window gains or loses focus
@@ -150,12 +150,25 @@ function useFocusScope(options) {
150
150
  store.unregisterKeybindings(id, keybindingRegistrationId);
151
151
  };
152
152
  }, [id, keybindingRegistrationId, store]);
153
- return { id, hasFocus, isPassive };
153
+ useEffect4(() => {
154
+ if (!store.hasFocusScopeComponent(id)) {
155
+ throw new GigglesError(
156
+ "useFocusScope() was called but no <FocusScope handle={scope}> was rendered. Every useFocusScope() call requires a corresponding <FocusScope> in the render output \u2014 without it, child components register under the wrong parent scope and keyboard navigation silently breaks."
157
+ );
158
+ }
159
+ }, [id, store]);
160
+ return { id, hasFocus, isPassive, next, prev, nextShallow, prevShallow, escape, drillIn };
154
161
  }
155
162
 
156
163
  // src/core/focus/FocusScope.tsx
164
+ import { useEffect as useEffect5 } from "react";
157
165
  import { jsx as jsx3 } from "react/jsx-runtime";
158
166
  function FocusScope({ handle, children }) {
167
+ const store = useStore();
168
+ useEffect5(() => {
169
+ store.registerFocusScopeComponent(handle.id);
170
+ return () => store.unregisterFocusScopeComponent(handle.id);
171
+ }, [handle.id, store]);
159
172
  return /* @__PURE__ */ jsx3(ScopeIdContext.Provider, { value: handle.id, children });
160
173
  }
161
174
 
@@ -191,6 +204,7 @@ var FocusStore = class {
191
204
  passiveSet = /* @__PURE__ */ new Set();
192
205
  pendingFocusFirstChild = /* @__PURE__ */ new Set();
193
206
  trapNodeId = null;
207
+ renderedScopes = /* @__PURE__ */ new Set();
194
208
  listeners = /* @__PURE__ */ new Set();
195
209
  version = 0;
196
210
  // nodeId → registrationId → BindingRegistration
@@ -396,6 +410,15 @@ var FocusStore = class {
396
410
  // ---------------------------------------------------------------------------
397
411
  // Trap
398
412
  // ---------------------------------------------------------------------------
413
+ registerFocusScopeComponent(id) {
414
+ this.renderedScopes.add(id);
415
+ }
416
+ unregisterFocusScopeComponent(id) {
417
+ this.renderedScopes.delete(id);
418
+ }
419
+ hasFocusScopeComponent(id) {
420
+ return this.renderedScopes.has(id);
421
+ }
399
422
  setTrap(nodeId) {
400
423
  this.trapNodeId = nodeId;
401
424
  }
package/dist/index.d.ts CHANGED
@@ -41,8 +41,6 @@ type FocusScopeHandle = {
41
41
  id: string;
42
42
  hasFocus: boolean;
43
43
  isPassive: boolean;
44
- };
45
- type FocusScopeHelpers = {
46
44
  next: () => void;
47
45
  prev: () => void;
48
46
  nextShallow: () => void;
@@ -50,6 +48,7 @@ type FocusScopeHelpers = {
50
48
  escape: () => void;
51
49
  drillIn: () => void;
52
50
  };
51
+ type FocusScopeHelpers = Pick<FocusScopeHandle, 'next' | 'prev' | 'nextShallow' | 'prevShallow' | 'escape' | 'drillIn'>;
53
52
  type FocusScopeOptions = {
54
53
  parent?: FocusScopeHandle;
55
54
  keybindings?: Keybindings | ((helpers: FocusScopeHelpers) => Keybindings);
package/dist/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ import {
2
+ useTerminalSize
3
+ } from "./chunk-WNGBTD67.js";
1
4
  import {
2
5
  FocusScope,
3
6
  FocusStore,
@@ -11,14 +14,11 @@ import {
11
14
  useKeybindingRegistry,
12
15
  useKeybindings,
13
16
  useStore
14
- } from "./chunk-A7BRQXWE.js";
17
+ } from "./chunk-TWXBZE5C.js";
15
18
  import {
16
19
  ThemeProvider,
17
20
  useTheme
18
21
  } from "./chunk-C77VBSPK.js";
19
- import {
20
- useTerminalSize
21
- } from "./chunk-WNGBTD67.js";
22
22
 
23
23
  // src/core/GigglesProvider.tsx
24
24
  import { useRef } from "react";
@@ -4,6 +4,11 @@ type TerminalSize = {
4
4
  rows: number;
5
5
  columns: number;
6
6
  };
7
+ type ShellOutHandle = {
8
+ run: (command: string) => Promise<{
9
+ exitCode: number;
10
+ }>;
11
+ };
7
12
  type SpawnOptions = SpawnOptionsWithoutStdio & {
8
13
  /**
9
14
  * Inject FORCE_COLOR=1 and TERM=xterm-256color into the child process
@@ -28,12 +33,8 @@ declare function useTerminalSize(): TerminalSize;
28
33
 
29
34
  declare function useTerminalFocus(callback: (focused: boolean) => void): void;
30
35
 
31
- declare function useShellOut(): {
32
- run: (command: string) => Promise<{
33
- exitCode: number;
34
- }>;
35
- };
36
+ declare function useShellOut(): ShellOutHandle;
36
37
 
37
38
  declare function useSpawn(): SpawnHandle;
38
39
 
39
- export { type SpawnHandle, type SpawnOptions, type SpawnOutputLine, type TerminalSize, useShellOut, useSpawn, useTerminalFocus, useTerminalSize };
40
+ export { type ShellOutHandle, type SpawnHandle, type SpawnOptions, type SpawnOutputLine, type TerminalSize, useShellOut, useSpawn, useTerminalFocus, useTerminalSize };
package/dist/ui/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  useFocusNode,
5
5
  useKeybindingRegistry,
6
6
  useKeybindings
7
- } from "../chunk-A7BRQXWE.js";
7
+ } from "../chunk-TWXBZE5C.js";
8
8
  import {
9
9
  CodeBlock
10
10
  } from "../chunk-SKSDNDQF.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "giggles",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,8 +40,8 @@
40
40
  "scripts": {
41
41
  "build": "tsup",
42
42
  "build:watch": "nodemon --watch src --ext ts,tsx --exec tsup",
43
- "play": "tsx --watch",
44
- "record": "vhs",
43
+ "play": "f() { tsx --watch playground/examples/$1.tsx; }; f",
44
+ "record": "f() { vhs playground/tapes/$1.tape; }; f",
45
45
  "dev:docs": "pnpm build && concurrently --kill-others \"pnpm build:watch\" \"pnpm --filter documentation dev\"",
46
46
  "lint": "prettier --write . && eslint . --fix"
47
47
  },