列表交互

1import { Button, Circle, HStack, Label, List, Navigation, NavigationStack, Script, Text, useState, VStack } from "scripting"
2
3type Message = {
4  from: string
5  content: string
6  isUnread: boolean
7}
8
9function MessageCell({
10  message
11}: {
12  message: Message
13}) {
14  return <HStack>
15    <Circle
16      fill={message.isUnread ? "systemBlue" : "clear"}
17      frame={{
18        width: 16,
19        height: 16,
20      }}
21    />
22    <VStack
23      alignment={"leading"}
24    >
25      <Text font={"headline"}>{message.from}</Text>
26      <Text>{message.content}</Text>
27    </VStack>
28  </HStack>
29}
30
31function Example() {
32  const [messages, setMessages] = useState<Message[]>(() => [
33    {
34      from: "Maria Ruiz",
35      content: "If you have a list of messages, you can add an action to toggle a message as unread on a swipe from the leading edge, and actions to delete or flag messages on a trailing edge swipe.",
36      isUnread: true,
37    },
38    {
39      from: "Mei Chen",
40      content: "Actions appear in the order you list them, starting from the swipe’s originating edge. In the example, the Delete action appears closest to the screen’s trailing edge",
41      isUnread: true,
42    },
43    {
44      from: "Maria Ruiz",
45      content: "By default, the user can perform the first action for a given swipe direction with a full swipe. The user can perform both the toggle unread and delete actions with full swipes. You can opt out of this behavior for an edge by setting the allowsFullSwipe parameter to false.",
46      isUnread: false,
47    },
48    {
49      from: "Mei Chen",
50      content: "When you set a role for a button using one of the values from the ButtonRole, system styles the button according to its role. In the example above, the delete action appears in red because it has the destructive role. If you want to set a different color, add the tint property to the button",
51      isUnread: true,
52    }
53  ])
54
55  function toggleUnread(message: Message) {
56    setMessages(messages.map(item => item !== message ? item : {
57      ...message,
58      isUnread: !item.isUnread
59    }))
60  }
61
62  function deleteMessage(message: Message) {
63    setMessages(messages.filter(item => item !== message))
64  }
65
66  return <NavigationStack>
67    <List
68      navigationTitle={"Messages"}
69      navigationBarTitleDisplayMode={"inline"}
70      listStyle={"inset"}
71    >
72      {messages.map(message =>
73        <MessageCell
74          message={message}
75          leadingSwipeActions={{
76            allowsFullSwipe: false,
77            actions: [
78              <Button
79                action={() => toggleUnread(message)}
80                tint={"systemBlue"}
81              >
82                {message.isUnread
83                  ? <Label title={"Read"} systemImage={"envelope.open"} />
84                  : <Label title={"Unread"} systemImage={"envelope.badge"} />
85                }
86              </Button>
87            ]
88          }}
89          trailingSwipeActions={{
90            actions: [
91              <Button
92                role={"destructive"}
93                action={() => deleteMessage(message)}
94              >
95                <Label title={"Delete"} systemImage={"trash"} />
96              </Button>,
97              <Button
98                action={() => { }}
99                tint={"systemOrange"}
100              >
101                <Label title={"Flag"} systemImage={"flag"} />
102              </Button>
103            ]
104          }}
105        />
106      )}
107    </List>
108  </NavigationStack>
109}
110
111async function run() {
112  await Navigation.present({
113    element: <Example />
114  })
115
116  Script.exit()
117}
118
119run()