我们的 List
组件提供了开箱即用的用户体验:
将相关项分组到带有标题和子标题的 section 中。
搜索栏
搜索栏允许用户与列表项快速交互。默认情况下,如果用户的输入可以与项目的 title
或 keyword
(模糊)匹配,则显示 List.Items 。
自定义过滤
有时,您可能不想依赖 Raycast 的过滤,而是 使用/实现 您自己的过滤。如果是这种情况,您可以将列表的过滤属性设置为 false
,这时显示的项目将独立于搜索栏的文本。请注意,如果指定了 onSearchTextChange
侦听器,过滤也会隐式设置为 false
。如果您想指定更改侦听器并仍然利用 Raycast 的内置过滤功能,则需要显式将过滤设置为 true
。
import { useEffect, useState } from "react";
import { Action, ActionPanel, List } from "@raycast/api";
const items = ["Augustiner Helles", "Camden Hells", "Leffe Blonde", "Sierra Nevada IPA"];
export default function Command() {
const [searchText, setSearchText] = useState("");
const [filteredList, filterList] = useState(items);
useEffect(() => {
filterList(items.filter((item) => item.includes(searchText)));
}, [searchText]);
return (
<List
filtering={false}
onSearchTextChange={setSearchText}
navigationTitle="Search Beers"
searchBarPlaceholder="Search your favorite beer"
>
{filteredList.map((item) => (
<List.Item
key={item}
title={item}
actions={
<ActionPanel>
<Action title="Select" onAction={() => console.log(`${item} selected`)} />
</ActionPanel>
}
/>
))}
</List>
);
}
用编程的方式更新搜索栏
在其他时候,您可能希望扩展程序更新搜索栏的内容,例如,您可以存储用户之前的搜索列表,并在下次访问时允许他们从上次中断的地方“继续”。
为此,您可以使用 searchText
属性。
import { useEffect, useState } from "react";
import { Action, ActionPanel, List } from "@raycast/api";
const items = ["Augustiner Helles", "Camden Hells", "Leffe Blonde", "Sierra Nevada IPA"];
export default function Command() {
const [searchText, setSearchText] = useState("");
return (
<List
searchText={searchText}
onSearchTextChange={setSearchText}
navigationTitle="Search Beers"
searchBarPlaceholder="Search your favorite beer"
>
{items.map((item) => (
<List.Item
key={item}
title={item}
actions={
<ActionPanel>
<Action title="Select" onAction={() => setSearchText(item)} />
</ActionPanel>
}
/>
))}
</List>
);
}
下拉菜单
某些扩展可能会为用户提供第二个过滤维度,比如待办事项扩展可能允许用户使用不同的组,阅读报纸扩展可能希望允许快速切换类别等。
这就是 searchBarAccessory
属性有用的地方。向其传递一个 List.Dropdown 组件,它将显示在搜索栏的右侧。通过使用全局快捷键 ⌘
P
或单击它来调用它。
例子
import { List } from "@raycast/api";
export default function Command() {
return (
<List>
<List.Item title="Item 1" />
<List.Item title="Item 2" subtitle="Optional subtitle" />
</List>
);
}
import { List } from "@raycast/api";
export default function Command() {
return (
<List>
<List.Section title="Section 1">
<List.Item title="Item 1" />
</List.Section>
<List.Section title="Section 2" subtitle="Optional subtitle">
<List.Item title="Item 1" />
</List.Section>
</List>
);
}
import { ActionPanel, Action, List } from "@raycast/api";
export default function Command() {
return (
<List>
<List.Item
title="Item 1"
actions={
<ActionPanel>
<Action.CopyToClipboard content="👋" />
</ActionPanel>
}
/>
</List>
);
}
import { useState } from "react";
import { Action, ActionPanel, List } from "@raycast/api";
import { useCachedPromise } from "@raycast/utils";
interface Pokemon {
name: string;
height: number;
weight: number;
id: string;
types: string[];
abilities: Array<{ name: string; isMainSeries: boolean }>;
}
const pokemons: Pokemon[] = [
{
name: "bulbasaur",
height: 7,
weight: 69,
id: "001",
types: ["Grass", "Poison"],
abilities: [
{ name: "Chlorophyll", isMainSeries: true },
{ name: "Overgrow", isMainSeries: true },
],
},
{
name: "ivysaur",
height: 10,
weight: 130,
id: "002",
types: ["Grass", "Poison"],
abilities: [
{ name: "Chlorophyll", isMainSeries: true },
{ name: "Overgrow", isMainSeries: true },
],
},
];
export default function Command() {
const [showingDetail, setShowingDetail] = useState(true);
const { data, isLoading } = useCachedPromise(() => new Promise<Pokemon[]>((resolve) => resolve(pokemons)));
return (
<List isLoading={isLoading} isShowingDetail={showingDetail}>
{data &&
data.map((pokemon) => {
const props: Partial<List.Item.Props> = showingDetail
? {
detail: (
<List.Item.Detail
markdown={`\n\n${pokemon.types.join(" ")}`}
/>
),
}
: { accessories: [{ text: pokemon.types.join(" ") }] };
return (
<List.Item
key={pokemon.id}
title={pokemon.name}
subtitle={`#${pokemon.id}`}
{...props}
actions={
<ActionPanel>
<Action.OpenInBrowser url={`https://www.pokemon.com/us/pokedex/${pokemon.name}`} />
<Action title="Toggle Detail" onAction={() => setShowingDetail(!showingDetail)} />
</ActionPanel>
}
/>
);
})}
</List>
);
}
import { useEffect, useState } from "react";
import { List } from "@raycast/api";
export default function CommandWithCustomEmptyView() {
const [state, setState] = useState({ searchText: "", items: [] });
useEffect(() => {
// perform an API call that eventually populates `items`.
}, [state.searchText]);
return (
<List onSearchTextChange={(newValue) => setState((previous) => ({ ...previous, searchText: newValue }))}>
{state.searchText === "" && state.items.length === 0 ? (
<List.EmptyView icon={{ source: "https://placekitten.com/500/500" }} title="Type something to get started" />
) : (
state.items.map((item) => <List.Item key={item} title={item} />)
)}
</List>
);
}
API 参考
List
参考 List.Section 或 List.Item.
该列表通过对列表项的标题和附加关键字建立索引来使用内置过滤。
例子
import { List } from "@raycast/api";
export default function Command() {
return (
<List navigationTitle="Search Beers" searchBarPlaceholder="Search your favorite beer">
<List.Item title="Augustiner Helles" />
<List.Item title="Camden Hells" />
<List.Item title="Leffe Blonde" />
<List.Item title="Sierra Nevada IPA" />
</List>
);
}
参数
切换 Raycast 过滤。如果为 true
,Raycast 将使用搜索栏中的查询来过滤项目。当为 false
时,扩展程序需要负责过滤。
boolean
or { keepSectionOrder: boolean }
当指定 onSearchTextChange
时为 false
,否则为 true
。
列表是否应在项目右侧有一个区域以显示有关所选项的其他详细信息。
onSearchTextChange
处理程序是在每次按下键盘时触发还是延迟以限制事件。当自定义过滤逻辑与异步操作(例如网络请求)结合使用时,建议设置为 true
。
List.Dropdown
显示在搜索栏右侧的下拉菜单。
例子
import { List } from "@raycast/api";
type DrinkType = { id: string; name: string };
function DrinkDropdown(props: { drinkTypes: DrinkType[]; onDrinkTypeChange: (newValue: string) => void }) {
const { drinkTypes, onDrinkTypeChange } = props;
return (
<List.Dropdown
tooltip="Select Drink Type"
storeValue={true}
onChange={(newValue) => {
onDrinkTypeChange(newValue);
}}
>
<List.Dropdown.Section title="Alcoholic Beverages">
{drinkTypes.map((drinkType) => (
<List.Dropdown.Item key={drinkType.id} title={drinkType.name} value={drinkType.id} />
))}
</List.Dropdown.Section>
</List.Dropdown>
);
}
export default function Command() {
const drinkTypes: DrinkType[] = [
{ id: "1", name: "Beer" },
{ id: "2", name: "Wine" },
];
const onDrinkTypeChange = (newValue: string) => {
console.log(newValue);
};
return (
<List
navigationTitle="Search Beers"
searchBarPlaceholder="Search your favorite drink"
searchBarAccessory={<DrinkDropdown drinkTypes={drinkTypes} onDrinkTypeChange={onDrinkTypeChange} />}
>
<List.Item title="Augustiner Helles" />
<List.Item title="Camden Hells" />
<List.Item title="Leffe Blonde" />
<List.Item title="Sierra Nevada IPA" />
</List>
);
}
参数
下拉部分或 item。如果指定了 Dropdown.Item
元素,则会自动创建默认部分。
下拉列表的默认值。请记住,defaultValue
将在每个组件生命周期配置一次。这意味着如果用户更改该值,则重新渲染时不会配置 defaultValue
。
切换 Raycast 过滤。如果为 true
,Raycast 将使用搜索栏中的查询来过滤项目。当为 false
时,扩展程序需要负责过滤。
boolean
or { keepSectionOrder: boolean }
当指定 onSearchTextChange
时为 false
,否则为 true
。
是否应在搜索栏旁边显示或隐藏 loading 指示器
下拉列表的值是否应在选择后保留,并在下次渲染下拉列表时恢复。
定义 onSearchTextChange
处理程序是在每次按下键盘时触发还是延迟以限制事件。当将自定义过滤逻辑与异步操作(例如网络请求)结合使用时,建议设置为 true
。
(newValue: string) => void
List.Dropdown.Item
List.Dropdown 中的下拉项
例子
import { List } from "@raycast/api";
export default function Command() {
return (
<List
searchBarAccessory={
<List.Dropdown tooltip="Dropdown With Items">
<List.Dropdown.Item title="One" value="one" />
<List.Dropdown.Item title="Two" value="two" />
<List.Dropdown.Item title="Three" value="three" />
</List.Dropdown>
}
>
<List.Item title="Item in the Main List" />
</List>
);
}
参数
一个可选属性,用于提供额外的可索引字符串以供搜索。在 Raycast 中过滤项目时,除了标题之外还会搜索关键字。
The title of its section if any
List.Dropdown.Section
分离的下拉项组。
使用 section 将相关菜单项分到一个组。
例子
import { List } from "@raycast/api";
export default function Command() {
return (
<List
searchBarAccessory={
<List.Dropdown tooltip="Dropdown With Sections">
<List.Dropdown.Section title="First Section">
<List.Dropdown.Item title="One" value="one" />
</List.Dropdown.Section>
<List.Dropdown.Section title="Second Section">
<List.Dropdown.Item title="Two" value="two" />
</List.Dropdown.Section>
</List.Dropdown>
}
>
<List.Item title="Item in the Main List" />
</List>
);
}
参数
List.EmptyView
当没有任何可用项目时显示的视图。
Raycast 提供了一个默认的 EmptyView
,如果 List 组件没有子组件,或者有子组件,但没有一个与搜索栏中的查询匹配,则将显示该 EmptyView
。也可以通过与其他 List.Item
一起传递空视图来覆盖。
请注意,如果 List 的 isLoading
属性为 true
并且搜索栏为空,则永远不会显示 EmptyView
。
例子
import { useEffect, useState } from "react";
import { List } from "@raycast/api";
export default function CommandWithCustomEmptyView() {
const [state, setState] = useState({ searchText: "", items: [] });
useEffect(() => {
// perform an API call that eventually populates `items`.
}, [state.searchText]);
return (
<List onSearchTextChange={(newValue) => setState((previous) => ({ ...previous, searchText: newValue }))}>
{state.searchText === "" && state.items.length === 0 ? (
<List.EmptyView icon={{ source: "https://placekitten.com/500/500" }} title="Type something to get started" />
) : (
state.items.map((item) => <List.Item key={item} title={item} />)
)}
</List>
);
}
参数
List.Item
List 中的一项
这是 Raycast 的基本 UI 组件之一。列表项代表单个实体。它可以是 GitHub PR、文件或其他任何内容。您很可能想要对此项目执行操作,因此请让用户清楚该列表项的含义。
例子
import { Icon, List } from "@raycast/api";
export default function Command() {
return (
<List>
<List.Item icon={Icon.Star} title="Augustiner Helles" subtitle="0,5 Liter" accessories={[{ text: "Germany" }]} />
</List>
);
}
参数
string
或 { tooltip: string; value: string }
当父列表显示详细信息并且选择该项目时,List.Item.Detail 将在右侧区域呈现。
当选择该项时,此字符串将传递到列表的 onSelectionChange
处理。确保为每个项目分配一个唯一的 ID,否则将自动生成 UUID。
一个可选属性,用于提供额外的可索引字符串以供搜索。当通过搜索栏过滤 Raycast 中的列表时,除了标题之外还会搜索关键字。
{ name: string; path: string }
string
或 { tooltip: string; value: string }
List.Item.Detail
在列表右侧的详细信息视图。 显示时,建议不要在 List.Item
上显示任何附件,最好将这些附加信息显示在 List.Item.Detail
视图中。
例子
import { List } from "@raycast/api";
export default function Command() {
return (
<List isShowingDetail>
<List.Item
title="Pikachu"
subtitle="Electric"
detail={
<List.Item.Detail markdown="" />
}
/>
</List>
);
}
参数
是否应在详细信息上方显示或隐藏 loading 栏
当父列表显示详细信息并且选择该项时,要在右侧区域呈现的 CommonMark
字符串。
要在 List.Item.Detail
底部呈现的 List.Item.Detail.Metadata
List.Item.Detail.Metadata
在 List.Item.Detail
底部的元数据视图。 使用它来显示有关 List.Item
内容的附加结构化数据。
例子
参数
List.Item.Detail.Metadata.Label
标题的右侧可以选择带有图标 和/或 文本。
例子
import { List } from "@raycast/api";
export default function Metadata() {
return (
<List isShowingDetail>
<List.Item
title="Bulbasaur"
detail={
<List.Item.Detail
metadata={
<List.Item.Detail.Metadata>
<List.Item.Detail.Metadata.Label title="Type" icon="pokemon_types/grass.svg" text="Grass" />
</List.Item.Detail.Metadata>
}
/>
}
/>
</List>
);
}
参数
List.Item.Detail.Metadata.Link
显示链接的项。
例子
import { List } from "@raycast/api";
export default function Metadata() {
return (
<List isShowingDetail>
<List.Item
title="Bulbasaur"
detail={
<List.Item.Detail
metadata={
<List.Item.Detail.Metadata>
<List.Item.Detail.Metadata.Link
title="Evolution"
target="https://www.pokemon.com/us/pokedex/pikachu"
text="Raichu"
/>
</List.Item.Detail.Metadata>
}
/>
}
/>
</List>
);
}
参数
List.Item.Detail.Metadata.TagList
单行显示的 Tags
列表。
例子
import { List } from "@raycast/api";
export default function Metadata() {
return (
<List isShowingDetail>
<List.Item
title="Bulbasaur"
detail={
<List.Item.Detail
metadata={
<List.Item.Detail.Metadata>
<List.Item.Detail.Metadata.TagList title="Type">
<List.Item.Detail.Metadata.TagList.Item text="Electric" color={"#eed535"} />
</List.Item.Detail.Metadata.TagList>
</List.Item.Detail.Metadata>
}
/>
}
/>
</List>
);
}
参数
List.Item.Detail.Metadata.TagList.Item
List.Item.Detail.Metadata.TagList
中的 tag。
参数
将文本颜色更改为提供的颜色,并设置相同颜色的透明背景。
List.Item.Detail.Metadata.Separator
显示分隔线的元数据项。使用它来分组和直观地分隔元数据项。
例子
import { List } from "@raycast/api";
export default function Metadata() {
return (
<List isShowingDetail>
<List.Item
title="Bulbasaur"
detail={
<List.Item.Detail
metadata={
<List.Item.Detail.Metadata>
<List.Item.Detail.Metadata.Label title="Type" icon="pokemon_types/grass.svg" text="Grass" />
<List.Item.Detail.Metadata.Separator />
<List.Item.Detail.Metadata.Label title="Type" icon="pokemon_types/poison.svg" text="Poison" />
</List.Item.Detail.Metadata>
}
/>
}
/>
</List>
);
}
List.Section
一组 List.Item.
section 是构建列表的好方法。例如,将具有相同状态的 GitHub 问题分组并按优先级排序。这样,用户可以快速访问最相关的内容。
例子
import { List } from "@raycast/api";
export default function Command() {
return (
<List>
<List.Section title="Lager">
<List.Item title="Camden Hells" />
</List.Section>
<List.Section title="IPA">
<List.Item title="Sierra Nevada IPA" />
</List.Section>
</List>
);
}
参数
类型
List.Item.Accessory
描述 List.Item
中的附件视图的接口。
属性
例子
import { Color, Icon, List } from "@raycast/api";
export default function Command() {
return (
<List>
<List.Item
title="An Item with Accessories"
accessories={[
{ text: `An Accessory Text`, icon: Icon.Hammer },
{ text: { value: `A Colored Accessory Text`, color: Color.Orange }, icon: Icon.Hammer },
{ icon: Icon.Person, tooltip: "A person" },
{ text: "Just Do It!" },
{ date: new Date() },
{ tag: new Date() },
{ tag: { value: new Date(), color: Color.Magenta } },
{ tag: { value: "User", color: Color.Magenta }, tooltip: "Tag with tooltip" },
]}
/>
</List>
);
}