Skip to content

Commit bd2f8e0

Browse files
committed
chore: format main
1 parent 400874b commit bd2f8e0

12 files changed

Lines changed: 52 additions & 47 deletions

File tree

docs/store-conventions.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ built on `@xstate/store`, with thin React adapters on top. This note records
66
when to reach for a store, where store code lives, and how it is tested.
77

88
Rule of thumb: **transition logic moves into store events; IO stays at the
9-
boundary.** An effect that only *repairs state after render* is a store
9+
boundary.** An effect that only _repairs state after render_ is a store
1010
transition in disguise. An effect that talks to a renderer, timer, stream, or
1111
process is doing its job.
1212

1313
## When to use what
1414

15-
| Situation | Use |
16-
|---|---|
17-
| Synchronous state updated by named events; cross-component; needs subscription/selectors (registry, surface stack, overlay stack, nav/search, sequence display) | `@xstate/store` |
18-
| Async lifecycles with real states and cancellable work (content loader) | `@xstate/store` + request-ids first; full `xstate` only if a written justification shows the statechart pays for itself |
19-
| Component-local input state that never crosses a component boundary (a filter query local to one overlay, a focus flag) | React `useState` |
20-
| Purely derived render data | `useMemo`/selectors — never an effect, never a store |
21-
| Imperative OpenTUI ref sync, subscriptions, timers, async IO | effects (or store-adjacent wrappers) — these are legitimate external synchronization and stay effects |
15+
| Situation | Use |
16+
| --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
17+
| Synchronous state updated by named events; cross-component; needs subscription/selectors (registry, surface stack, overlay stack, nav/search, sequence display) | `@xstate/store` |
18+
| Async lifecycles with real states and cancellable work (content loader) | `@xstate/store` + request-ids first; full `xstate` only if a written justification shows the statechart pays for itself |
19+
| Component-local input state that never crosses a component boundary (a filter query local to one overlay, a focus flag) | React `useState` |
20+
| Purely derived render data | `useMemo`/selectors — never an effect, never a store |
21+
| Imperative OpenTUI ref sync, subscriptions, timers, async IO | effects (or store-adjacent wrappers) — these are legitimate external synchronization and stay effects |
2222

2323
## File layout
2424

examples/mouse-choose.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,18 @@
2020
import { launch, createStaticProvider, type ChooseItem } from "@tooee/choose"
2121

2222
const frameworks: ChooseItem[] = [
23-
{ text: "OpenTUI", value: "opentui", icon: "\u{1F5A5}", description: "Zig-native terminal renderer" },
24-
{ text: "React", value: "react", icon: "\u{269B}", description: "Declarative UI via the reconciler" },
23+
{
24+
text: "OpenTUI",
25+
value: "opentui",
26+
icon: "\u{1F5A5}",
27+
description: "Zig-native terminal renderer",
28+
},
29+
{
30+
text: "React",
31+
value: "react",
32+
icon: "\u{269B}",
33+
description: "Declarative UI via the reconciler",
34+
},
2535
{ text: "Solid", value: "solid", icon: "\u{1F9F1}", description: "Fine-grained reactivity" },
2636
{ text: "Bun", value: "bun", icon: "\u{1F35E}", description: "Fast all-in-one runtime" },
2737
{ text: "TypeScript", value: "typescript", icon: "\u{1F4D8}", description: "Typed JavaScript" },

packages/choose/test/ChooseOverlay.mouse.test.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,7 @@ function lineOf(frame: string, text: string): { x: number; y: number } {
3434
return { x: -1, y: -1 }
3535
}
3636

37-
async function setup(opts: {
38-
onSelect?: (item: ChooseItem) => void
39-
onCancel?: () => void
40-
}) {
37+
async function setup(opts: { onSelect?: (item: ChooseItem) => void; onCancel?: () => void }) {
4138
const s = await testRender(
4239
<TooeeProvider initialMode="insert">
4340
<ChooseOverlay

packages/commands/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
"scripts": {
3636
"typecheck": "tsc --noEmit"
3737
},
38+
"dependencies": {
39+
"@xstate/store": "^4",
40+
"@xstate/store-react": "^2"
41+
},
3842
"devDependencies": {
3943
"@opentui/core": "^0.2.15",
4044
"@opentui/react": "^0.2.15",
@@ -46,9 +50,5 @@
4650
"@opentui/core": "^0.2.15",
4751
"@opentui/react": "^0.2.15",
4852
"react": "^18.0.0 || ^19.0.0"
49-
},
50-
"dependencies": {
51-
"@xstate/store": "^4",
52-
"@xstate/store-react": "^2"
5353
}
5454
}

packages/commands/src/context.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,7 @@ export function CommandSurfaceProvider({
254254

255255
// Surface-local mode changes are transitions too (F-08): a mid-chord mode
256256
// switch on a modal surface resets the pending sequence.
257-
const handleModeChange = useCallback(
258-
() => commandStore.modeChanged(id),
259-
[commandStore, id],
260-
)
257+
const handleModeChange = useCallback(() => commandStore.modeChanged(id), [commandStore, id])
261258

262259
return (
263260
<ModeProvider initialMode={initialMode} onModeChange={handleModeChange}>

packages/commands/src/parse.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ export function parseHotkey(hotkey: string, leaderKey?: string): ParsedHotkey {
6969
if (!leaderKey) {
7070
// No leader configured: the hotkey must not spring to life on some
7171
// invented default. Zero steps = unmatchable; the dispatcher skips it.
72-
warnOnce(`[tooee/commands] Hotkey "${trimmed}" uses <leader> but no leader key is configured; the hotkey is disabled.`)
72+
warnOnce(
73+
`[tooee/commands] Hotkey "${trimmed}" uses <leader> but no leader key is configured; the hotkey is disabled.`,
74+
)
7375
return { steps: [] }
7476
}
7577
const leaderStep = parseStep(leaderKey)

packages/commands/test/command-store.test.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,8 @@ describe("command store — registration", () => {
156156
const registry = cs.registryFor(surface)
157157
const seen: Mode[] = []
158158
let blocked = 0
159-
registry.register(
160-
command("go", "g", { handler: (ctx) => seen.push(ctx.mode) }),
161-
)
162-
registry.register(
163-
command("no", "n", { when: () => false, handler: () => blocked++ }),
164-
)
159+
registry.register(command("go", "g", { handler: (ctx) => seen.push(ctx.mode) }))
160+
registry.register(command("no", "n", { when: () => false, handler: () => blocked++ }))
165161

166162
registry.invoke("go")
167163
registry.invoke("no")

packages/commands/test/registry.test.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
import { testRender } from "../../../test/support/test-render.ts"
22
import { test, expect, afterEach, describe } from "bun:test"
33
import { act, useState } from "react"
4-
import {
5-
CommandProvider,
6-
useCommand,
7-
useCommandGroup,
8-
useCommandRegistry,
9-
} from "../src/index.js"
4+
import { CommandProvider, useCommand, useCommandGroup, useCommandRegistry } from "../src/index.js"
105
import type { RegisteredCommandGroup } from "../src/index.js"
116

127
type TestSession = Awaited<ReturnType<typeof testRender>>

packages/commands/test/store-integration.test.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,12 @@ describe("F-13: surface command metadata", () => {
238238
test("useActiveCommandSurface().commands lists the modal surface's commands reactively", async () => {
239239
function ActiveProbe() {
240240
const active = useActiveCommandSurface()
241-
const ids = active ? active.commands.map((c) => c.id).sort().join(",") : "none"
241+
const ids = active
242+
? active.commands
243+
.map((c) => c.id)
244+
.sort()
245+
.join(",")
246+
: "none"
242247
return <text content={`active-commands:[${ids}]`} />
243248
}
244249

@@ -279,7 +284,10 @@ describe("F-13: surface command metadata", () => {
279284
test("useSurfaceCommands defaults to the active surface and falls back to root", async () => {
280285
function SurfaceCommandsProbe() {
281286
const commands = useSurfaceCommands()
282-
const ids = commands.map((c) => c.id).sort().join(",")
287+
const ids = commands
288+
.map((c) => c.id)
289+
.sort()
290+
.join(",")
283291
return <text content={`surface-commands:[${ids}]`} />
284292
}
285293

packages/commands/test/surface.test.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,12 @@ describe("command surface arbitration", () => {
228228
const [surfaceAction, setSurfaceAction] = useState(0)
229229
const active = useActiveCommandSurface()
230230

231-
useCommand({ id: "root.open", title: "Open", hotkey: "o", handler: () => setShowSurface(true) })
231+
useCommand({
232+
id: "root.open",
233+
title: "Open",
234+
hotkey: "o",
235+
handler: () => setShowSurface(true),
236+
})
232237

233238
useKeyboard((key) => {
234239
if (key.name === "z") setUnguarded((n) => n + 1)

0 commit comments

Comments
 (0)