Skip to content

Commit 3f01b49

Browse files
committed
update app API for 3 different atom types
1 parent 964ccec commit 3f01b49

5 files changed

Lines changed: 119 additions & 99 deletions

File tree

tsunami/app/defaultclient.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"io/fs"
99
"net/http"
1010

11+
"github.com/wavetermdev/waveterm/tsunami/util"
1112
"github.com/wavetermdev/waveterm/tsunami/vdom"
1213
)
1314

@@ -41,16 +42,31 @@ func SendAsyncInitiation() error {
4142
return defaultClient.SendAsyncInitiation()
4243
}
4344

44-
func SetAtomVals(m map[string]any) {
45-
defaultClient.SetAtomVals(m)
45+
func GetSharedAtom[T any](name string) T {
46+
rawVal := defaultClient.GetAtomVal("$shared." + name)
47+
return util.GetTypedAtomValue[T](rawVal, "$shared."+name)
4648
}
4749

48-
func SetAtomVal(name string, val any) {
49-
defaultClient.SetAtomVal(name, val)
50+
func SetSharedAtom[T any](name string, val T) {
51+
defaultClient.SetAtomVal("$shared."+name, val)
5052
}
5153

52-
func GetAtomVal(name string) any {
53-
return defaultClient.GetAtomVal(name)
54+
func GetConfig[T any](name string) T {
55+
rawVal := defaultClient.GetAtomVal("$config." + name)
56+
return util.GetTypedAtomValue[T](rawVal, "$config."+name)
57+
}
58+
59+
func SetConfig[T any](name string, val T) {
60+
defaultClient.SetAtomVal("$config."+name, val)
61+
}
62+
63+
func GetData[T any](name string) T {
64+
rawVal := defaultClient.GetAtomVal("$data." + name)
65+
return util.GetTypedAtomValue[T](rawVal, "$data."+name)
66+
}
67+
68+
func SetData[T any](name string, val T) {
69+
defaultClient.SetAtomVal("$data."+name, val)
5470
}
5571

5672
// HandleDynFunc registers a dynamic HTTP handler function with the internal http.ServeMux.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Global Keyboard Handling
2+
3+
The Tsunami framework provides two approaches for handling keyboard events:
4+
5+
1. Standard DOM event handling on elements:
6+
7+
```go
8+
vdom.H("div", map[string]any{
9+
"onKeyDown": func(e vdom.VDomEvent) {
10+
// Handle key event
11+
},
12+
})
13+
```
14+
15+
2. Global keyboard event handling:
16+
17+
```go
18+
// Global keyboard events are automatically enabled when you set a global event handler
19+
func init() {
20+
app.SetGlobalEventHandler(func(event vdom.VDomEvent) {
21+
if event.EventType != "onKeyDown" || event.KeyData == nil {
22+
return
23+
}
24+
25+
switch event.KeyData.Key {
26+
case "ArrowUp":
27+
// Handle up arrow
28+
case "ArrowDown":
29+
// Handle down arrow
30+
}
31+
})
32+
```
33+
34+
The global handler approach is particularly useful when:
35+
36+
- You need to handle keyboard events regardless of focus state
37+
- Building terminal-like applications that need consistent keyboard control
38+
- Implementing application-wide keyboard shortcuts
39+
- Managing navigation in full-screen applications
40+
41+
Key differences:
42+
43+
- Standard DOM events require the element to have focus
44+
- Global events work regardless of focus state
45+
- Global events can be used alongside regular DOM event handlers
46+
- Global handler receives all keyboard events for the application
47+
48+
The event handler receives a VDomEvent with KeyData for keyboard events:
49+
50+
```go
51+
type VDomEvent struct {
52+
EventType string // e.g., "onKeyDown"
53+
KeyData *WaveKeyboardEvent `json:"keydata,omitempty"`
54+
// ... other fields
55+
}
56+
57+
type WaveKeyboardEvent struct {
58+
Type string // "keydown", "keyup", "keypress"
59+
Key string // The key value (e.g., "ArrowUp")
60+
Code string // Physical key code
61+
Shift bool // Modifier states
62+
Control bool
63+
Alt bool
64+
Meta bool
65+
Cmd bool // Meta on Mac, Alt on Windows/Linux
66+
Option bool // Alt on Mac, Meta on Windows/Linux
67+
}
68+
```
69+
70+
When using global keyboard events:
71+
72+
Global keyboard events are automatically enabled when you set a global event handler. Set up the handler in a place where you have access to necessary state updates.

tsunami/prompts/system.md

Lines changed: 3 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ var App = app.DefineComponent("App",
6969

7070
Key Points:
7171

72-
- Must use package main.
72+
- Must use `package main`.
7373
- The `App` component is required. It serves as the entry point to your application.
7474
- Do NOT add a `main()` function, that is provided by the framework when building.
7575
- Uses Tailwind v4 for styling - you can use any Tailwind classes in your components.
@@ -98,7 +98,7 @@ vdom.H("div", map[string]any{
9898
vdom.H("div", map[string]any{
9999
"style": map[string]any{
100100
"marginTop": 10, // Numbers automatically convert to px (like React)
101-
"zIndex": 1000,
101+
"zIndex": 1000, // use React style names
102102
"transform": "rotate(45deg)",
103103
},
104104
})
@@ -671,76 +671,7 @@ Key points for state management:
671671

672672
## Global Keyboard Handling
673673

674-
The Tsunami framework provides two approaches for handling keyboard events:
675-
676-
1. Standard DOM event handling on elements:
677-
678-
```go
679-
vdom.H("div", map[string]any{
680-
"onKeyDown": func(e vdom.VDomEvent) {
681-
// Handle key event
682-
},
683-
})
684-
```
685-
686-
2. Global keyboard event handling:
687-
688-
```go
689-
// Global keyboard events are automatically enabled when you set a global event handler
690-
func init() {
691-
app.SetGlobalEventHandler(func(event vdom.VDomEvent) {
692-
if event.EventType != "onKeyDown" || event.KeyData == nil {
693-
return
694-
}
695-
696-
switch event.KeyData.Key {
697-
case "ArrowUp":
698-
// Handle up arrow
699-
case "ArrowDown":
700-
// Handle down arrow
701-
}
702-
})
703-
```
704-
705-
The global handler approach is particularly useful when:
706-
707-
- You need to handle keyboard events regardless of focus state
708-
- Building terminal-like applications that need consistent keyboard control
709-
- Implementing application-wide keyboard shortcuts
710-
- Managing navigation in full-screen applications
711-
712-
Key differences:
713-
714-
- Standard DOM events require the element to have focus
715-
- Global events work regardless of focus state
716-
- Global events can be used alongside regular DOM event handlers
717-
- Global handler receives all keyboard events for the application
718-
719-
The event handler receives a VDomEvent with KeyData for keyboard events:
720-
721-
```go
722-
type VDomEvent struct {
723-
EventType string // e.g., "onKeyDown"
724-
KeyData *WaveKeyboardEvent `json:"keydata,omitempty"`
725-
// ... other fields
726-
}
727-
728-
type WaveKeyboardEvent struct {
729-
Type string // "keydown", "keyup", "keypress"
730-
Key string // The key value (e.g., "ArrowUp")
731-
Code string // Physical key code
732-
Shift bool // Modifier states
733-
Control bool
734-
Alt bool
735-
Meta bool
736-
Cmd bool // Meta on Mac, Alt on Windows/Linux
737-
Option bool // Alt on Mac, Meta on Windows/Linux
738-
}
739-
```
740-
741-
When using global keyboard events:
742-
743-
Global keyboard events are automatically enabled when you set a global event handler. Set up the handler in a place where you have access to necessary state updates.
674+
For some applications, getting access to each key press regardless of focus state is essential. To enable global keyboard handling that captures all keyboard events across your application, see the global-keyboard-handling.md document.
744675

745676
## File Handling
746677

tsunami/util/util.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,23 @@ func OpenBrowser(url string, delay time.Duration) {
9090

9191
exec.Command(cmd, args...).Start()
9292
}
93+
94+
func GetTypedAtomValue[T any](rawVal any, atomName string) T {
95+
var result T
96+
if rawVal == nil {
97+
return *new(T)
98+
}
99+
100+
var ok bool
101+
result, ok = rawVal.(T)
102+
if !ok {
103+
// Try converting from float64 if rawVal is float64
104+
if f64Val, isFloat64 := rawVal.(float64); isFloat64 {
105+
if converted, convOk := FromFloat64[T](f64Val); convOk {
106+
return converted
107+
}
108+
}
109+
panic(fmt.Sprintf("GetTypedAtomValue %q value type mismatch (expected %T, got %T)", atomName, *new(T), rawVal))
110+
}
111+
return result
112+
}

tsunami/vdom/vdom.go

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -182,25 +182,6 @@ func UseState[T any](ctx context.Context, initialVal T) (T, func(T), func(func(T
182182
return rtnVal, typedSetVal, typedSetFuncVal
183183
}
184184

185-
func getTypedAtomValue[T any](rawVal any, atomName string) T {
186-
var result T
187-
if rawVal == nil {
188-
return *new(T)
189-
}
190-
191-
var ok bool
192-
result, ok = rawVal.(T)
193-
if !ok {
194-
// Try converting from float64 if rawVal is float64
195-
if f64Val, isFloat64 := rawVal.(float64); isFloat64 {
196-
if converted, convOk := util.FromFloat64[T](f64Val); convOk {
197-
return converted
198-
}
199-
}
200-
panic(fmt.Sprintf("UseAtom %q value type mismatch (expected %T, got %T)", atomName, *new(T), rawVal))
201-
}
202-
return result
203-
}
204185

205186
func useAtom[T any](ctx context.Context, hookName string, atomName string) (T, func(T), func(func(T) T)) {
206187
rc := vdomctx.GetRenderContext(ctx)
@@ -210,15 +191,15 @@ func useAtom[T any](ctx context.Context, hookName string, atomName string) (T, f
210191
val, setVal, setFn := rc.UseAtom(ctx, atomName)
211192

212193
// Adapt the "any" values to type "T"
213-
atomVal := getTypedAtomValue[T](val, atomName)
194+
atomVal := util.GetTypedAtomValue[T](val, atomName)
214195

215196
typedSetVal := func(newVal T) {
216197
setVal(newVal)
217198
}
218199

219200
typedSetFuncVal := func(updateFunc func(T) T) {
220201
setFn(func(oldVal any) any {
221-
typedOldVal := getTypedAtomValue[T](oldVal, atomName)
202+
typedOldVal := util.GetTypedAtomValue[T](oldVal, atomName)
222203
return updateFunc(typedOldVal)
223204
})
224205
}

0 commit comments

Comments
 (0)