1import { Button, HStack, Image, List, Navigation, NavigationStack, Script, Section, Text, TextField, useMemo, useState, VStack, WebView } from "scripting"
2
3function WebViewControllerExample() {
4 const [logs, setLogs] = useState<{
5 content: string
6 error: boolean
7 }[]>([])
8
9 function addLog(content: string, error = false) {
10 setLogs(logs => [...logs, { content, error }])
11 }
12
13 async function runCode() {
14 setLogs([])
15 const controller = new WebViewController()
16
17 addLog("WebViewController created.")
18 addLog("Start loading...")
19
20 if (await controller.loadURL("https://github.com")) {
21 addLog("Website is loaded.")
22 addLog("Calling controller.evaluateJavaScript...")
23 const title = await controller.evaluateJavaScript<string>("document.title")
24
25 if (title != null) {
26 addLog(`Title: ${title}`)
27 } else {
28 addLog("Failed to get the title.", true)
29 }
30 } else {
31 addLog("Failed to load the website.", true)
32 }
33
34 controller.dispose()
35 addLog("The controller is disposed.")
36 }
37
38 return <Section
39 header={
40 <Text>WebView controller</Text>
41 }
42 >
43 <VStack
44 frame={{
45 maxWidth: "infinity"
46 }}
47 alignment={"leading"}
48 >
49 <Text font={"headline"}>This example will follow these steps:</Text>
50 <VStack
51 padding={{
52 leading: 16
53 }}
54 spacing={16}
55 foregroundStyle={"secondaryLabel"}
56 alignment={"leading"}
57 >
58 <Text>Create a WebViewController instane</Text>
59 <Text>Load https://github.com</Text>
60 <Text>Call evaluateJavaScript and get the title of the website</Text>
61 </VStack>
62 <HStack
63 alignment={"center"}
64 frame={{
65 maxWidth: "infinity"
66 }}
67 >
68 <Button
69 title={"Run"}
70 action={runCode}
71 />
72 </HStack>
73
74 <VStack
75 alignment={"leading"}
76 spacing={8}
77 >
78 {logs.map(log =>
79 <Text
80 font={"caption"}
81 monospaced
82 padding={{
83 leading: 16
84 }}
85 foregroundStyle={log.error ? "systemRed" : "systemGreen"}
86 >{log.content}</Text>
87 )}
88 </VStack>
89 </VStack>
90 </Section>
91}
92
93function PresentWebViewExample() {
94
95 function run() {
96 const controller = new WebViewController()
97 controller.loadURL("https://github.com")
98
99 controller.present({
100 fullscreen: true,
101 navigationTitle: "Github"
102 }).then(() => {
103 console.log("WebView is dismissed")
104 controller.dispose()
105 })
106 }
107
108 return <Section
109 header={
110 <Text>Present a WebView as a independent page</Text>
111 }
112 >
113 <Button
114 title={"Present"}
115 action={run}
116 />
117 </Section>
118}
119
120function EmbedAWebViewExample() {
121 const controller = useMemo(() => new WebViewController(), [])
122 const [url, setUrl] = useState("")
123
124 return <Section
125 header={
126 <Text>Embed a WebView</Text>
127 }
128 >
129 <VStack>
130 <HStack>
131 <Button action={() => {
132 controller.goBack()
133 }}>
134 <Image
135 systemName={"arrow.left"}
136 />
137 </Button>
138 <Button action={() => {
139 controller.goForward()
140 }}>
141 <Image
142 systemName={"arrow.right"}
143 />
144 </Button>
145 <Button action={() => {
146 controller.reload()
147 }}>
148 <Image
149 systemName={"arrow.clockwise"}
150 />
151 </Button>
152 <TextField
153 title={"Website URL"}
154 textFieldStyle={"roundedBorder"}
155 value={url}
156 onChanged={setUrl}
157 keyboardType={"URL"}
158 textInputAutocapitalization={"never"}
159 frame={{
160 maxWidth: "infinity"
161 }}
162 />
163 <Button
164 action={() => controller.loadURL(url)}
165 >
166 <Image
167 systemName={"arrow.right.circle"}
168 />
169 </Button>
170 </HStack>
171 <WebView
172 controller={controller}
173 frame={{
174 height: 400
175 }}
176 />
177 </VStack>
178 </Section>
179}
180
181function Example() {
182 return <NavigationStack>
183 <List
184 navigationTitle={"WebView"}
185 navigationBarTitleDisplayMode={"inline"}
186 >
187 <WebViewControllerExample />
188 <PresentWebViewExample />
189 <EmbedAWebViewExample />
190 </List>
191 </NavigationStack>
192}
193
194async function run() {
195 await Navigation.present({
196 element: <Example />
197 })
198
199 Script.exit()
200}
201
202run()