@westopp/windo 0.1.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/LICENSE +21 -0
- package/README.md +146 -0
- package/dist/chunk-5RM2VYAM.js +150 -0
- package/dist/chunk-5RM2VYAM.js.map +1 -0
- package/dist/cli.cjs +303 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +138 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +219 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +374 -0
- package/dist/index.d.ts +374 -0
- package/dist/index.js +182 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.cjs +185 -0
- package/dist/plugin.cjs.map +1 -0
- package/dist/plugin.d.cts +11 -0
- package/dist/plugin.d.ts +11 -0
- package/dist/plugin.js +11 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +95 -0
- package/src/cli/index.ts +160 -0
- package/src/client/App.tsx +310 -0
- package/src/client/Canvas.tsx +358 -0
- package/src/client/Inspector.tsx +586 -0
- package/src/client/Sidebar.tsx +108 -0
- package/src/client/bridge.ts +124 -0
- package/src/client/chrome.css +1966 -0
- package/src/client/icons.tsx +110 -0
- package/src/client/index.ts +15 -0
- package/src/client/internal-types.ts +147 -0
- package/src/client/persist.ts +38 -0
- package/src/define-config.ts +54 -0
- package/src/descriptor.test.ts +59 -0
- package/src/descriptor.ts +185 -0
- package/src/globals.d.ts +9 -0
- package/src/index.ts +54 -0
- package/src/plugin/index.ts +181 -0
- package/src/preview/ctx.ts +43 -0
- package/src/preview/index.ts +283 -0
- package/src/preview/preview.css +81 -0
- package/src/preview/registry.ts +159 -0
- package/src/preview/render.tsx +90 -0
- package/src/preview/virtual.d.ts +8 -0
- package/src/protocol.ts +59 -0
- package/src/types.ts +319 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// Host-side bridge. Owns the postMessage conversation with the preview iframe:
|
|
2
|
+
// subscribes to preview messages, surfaces the latest state, and exposes the
|
|
3
|
+
// outbound host messages as stable callbacks.
|
|
4
|
+
|
|
5
|
+
import type { RefObject } from 'react'
|
|
6
|
+
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
7
|
+
import type { WindoHostMessage } from '../protocol'
|
|
8
|
+
import { isPreviewMessage, isWindoMessage, WINDO_MSG } from '../protocol'
|
|
9
|
+
import type { WindoContextMeta, WindoEnvState, WindoFieldError, WindoGroup, WindoManifestEntry } from '../types'
|
|
10
|
+
import type { BridgeApi, WindoDescribe, WindoLogRow } from './internal-types'
|
|
11
|
+
|
|
12
|
+
const MAX_LOGS = 200
|
|
13
|
+
|
|
14
|
+
export function useWindoBridge(iframeRef: RefObject<HTMLIFrameElement | null>): BridgeApi {
|
|
15
|
+
const [ready, setReady] = useState(false)
|
|
16
|
+
const [readyNonce, setReadyNonce] = useState(0)
|
|
17
|
+
const [title, setTitle] = useState('')
|
|
18
|
+
const [groups, setGroups] = useState<WindoGroup[]>([])
|
|
19
|
+
const [contexts, setContexts] = useState<WindoContextMeta[]>([])
|
|
20
|
+
const [manifest, setManifest] = useState<WindoManifestEntry[]>([])
|
|
21
|
+
const [describe, setDescribe] = useState<WindoDescribe | null>(null)
|
|
22
|
+
const [parseErrors, setParseErrors] = useState<WindoFieldError[]>([])
|
|
23
|
+
const [renderError, setRenderError] = useState<{ message: string; stack?: string } | null>(null)
|
|
24
|
+
const [logs, setLogs] = useState<WindoLogRow[]>([])
|
|
25
|
+
const [stateValues, setStateValues] = useState<Record<string, Record<string, unknown>>>({})
|
|
26
|
+
const [actionDisabled, setActionDisabled] = useState<Record<string, Record<string, boolean>>>({})
|
|
27
|
+
const seqRef = useRef(0)
|
|
28
|
+
|
|
29
|
+
const post = useCallback(
|
|
30
|
+
(msg: WindoHostMessage) => {
|
|
31
|
+
iframeRef.current?.contentWindow?.postMessage(msg, '*')
|
|
32
|
+
},
|
|
33
|
+
[iframeRef]
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const handler = useRef((e: MessageEvent) => {
|
|
37
|
+
// Only the main preview iframe drives this bridge. Variant-gallery cells run
|
|
38
|
+
// their own preview iframes and post the same message shapes; ignore them so
|
|
39
|
+
// their logs / describe / errors don't leak into the main panels.
|
|
40
|
+
if (e.source !== iframeRef.current?.contentWindow) return
|
|
41
|
+
if (!isWindoMessage(e.data)) return
|
|
42
|
+
if (!isPreviewMessage(e.data)) return
|
|
43
|
+
const msg = e.data
|
|
44
|
+
switch (msg.type) {
|
|
45
|
+
case 'ready':
|
|
46
|
+
setReady(true)
|
|
47
|
+
setReadyNonce(n => n + 1)
|
|
48
|
+
post({ source: WINDO_MSG, dir: 'host', type: 'request-manifest' })
|
|
49
|
+
break
|
|
50
|
+
case 'manifest':
|
|
51
|
+
setTitle(msg.title)
|
|
52
|
+
setManifest(msg.entries)
|
|
53
|
+
setGroups(msg.groups)
|
|
54
|
+
setContexts(msg.contexts)
|
|
55
|
+
break
|
|
56
|
+
case 'describe':
|
|
57
|
+
setDescribe({
|
|
58
|
+
id: msg.id,
|
|
59
|
+
descriptor: msg.descriptor,
|
|
60
|
+
props: msg.props,
|
|
61
|
+
variants: msg.variants,
|
|
62
|
+
defaults: msg.defaults,
|
|
63
|
+
code: msg.code,
|
|
64
|
+
})
|
|
65
|
+
setRenderError(null)
|
|
66
|
+
break
|
|
67
|
+
case 'parse-ok':
|
|
68
|
+
setParseErrors([])
|
|
69
|
+
setRenderError(null)
|
|
70
|
+
break
|
|
71
|
+
case 'parse-error':
|
|
72
|
+
setParseErrors(msg.errors)
|
|
73
|
+
break
|
|
74
|
+
case 'log': {
|
|
75
|
+
const row: WindoLogRow = { ...msg.entry, seq: seqRef.current++ }
|
|
76
|
+
setLogs(prev => [...prev, row].slice(-MAX_LOGS))
|
|
77
|
+
break
|
|
78
|
+
}
|
|
79
|
+
case 'state':
|
|
80
|
+
setStateValues(prev => ({ ...prev, [msg.id]: msg.state }))
|
|
81
|
+
setActionDisabled(prev => ({ ...prev, [msg.id]: Object.fromEntries(msg.actions.map(a => [a.id, a.disabled])) }))
|
|
82
|
+
break
|
|
83
|
+
case 'render-error':
|
|
84
|
+
setRenderError({ message: msg.message, stack: msg.stack })
|
|
85
|
+
break
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
const onMessage = (e: MessageEvent) => handler.current(e)
|
|
91
|
+
window.addEventListener('message', onMessage)
|
|
92
|
+
return () => window.removeEventListener('message', onMessage)
|
|
93
|
+
}, [])
|
|
94
|
+
|
|
95
|
+
const select = useCallback((id: string) => post({ source: WINDO_MSG, dir: 'host', type: 'select', id }), [post])
|
|
96
|
+
|
|
97
|
+
const setProps = useCallback((id: string, json: string) => post({ source: WINDO_MSG, dir: 'host', type: 'set-props', id, json }), [post])
|
|
98
|
+
|
|
99
|
+
const setEnv = useCallback((env: WindoEnvState) => post({ source: WINDO_MSG, dir: 'host', type: 'set-env', env }), [post])
|
|
100
|
+
|
|
101
|
+
const invokeAction = useCallback((id: string, actionId: string) => post({ source: WINDO_MSG, dir: 'host', type: 'invoke-action', id, actionId }), [post])
|
|
102
|
+
|
|
103
|
+
const clearLogs = useCallback(() => setLogs([]), [])
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
ready,
|
|
107
|
+
readyNonce,
|
|
108
|
+
title,
|
|
109
|
+
groups,
|
|
110
|
+
contexts,
|
|
111
|
+
manifest,
|
|
112
|
+
describe,
|
|
113
|
+
parseErrors,
|
|
114
|
+
renderError,
|
|
115
|
+
logs,
|
|
116
|
+
clearLogs,
|
|
117
|
+
stateValues,
|
|
118
|
+
actionDisabled,
|
|
119
|
+
select,
|
|
120
|
+
setProps,
|
|
121
|
+
setEnv,
|
|
122
|
+
invokeAction,
|
|
123
|
+
}
|
|
124
|
+
}
|