docs: Improve docs add more details. (#1447)

- Also update "Compare to others", close #1452
This commit is contained in:
Jason Lee 2025-10-29 10:41:28 +08:00 committed by GitHub
parent 4eb1ed2cfd
commit d34ea6640a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 262 additions and 494 deletions

View file

@ -114,7 +114,7 @@ Check out [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
## Compare to others ## Compare to others
| Features | GPUI Component | [Iced] | [egui] | [QT 6] | | Features | GPUI Component | [Iced] | [egui] | [Qt 6] |
| --------------------- | ------------------------------ | ------------------ | --------------------- | ------------------------------------------------- | | --------------------- | ------------------------------ | ------------------ | --------------------- | ------------------------------------------------- |
| Language | Rust | Rust | Rust | C++/QML | | Language | Rust | Rust | Rust | C++/QML |
| Core Render | GPUI | wgpu | wgpu | QT | | Core Render | GPUI | wgpu | wgpu | QT |
@ -135,7 +135,7 @@ Check out [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
| Markdown Rendering | Yes | Yes | Basic | No | | Markdown Rendering | Yes | Yes | Basic | No |
| Markdown mix HTML | Yes | No | No | No | | Markdown mix HTML | Yes | No | No | No |
| HTML Rendering | Basic | No | No | Basic | | HTML Rendering | Basic | No | No | Basic |
| Text Selection | TextView | No | Any Label | No | | Text Selection | TextView | No | Any Label | Yes |
| Custom Theme | Yes | Yes | Yes | Yes | | Custom Theme | Yes | Yes | Yes | Yes |
| Built Themes | Yes | No | No | No | | Built Themes | Yes | No | No | No |
| I18n | Yes | Yes | Yes | Yes | | I18n | Yes | Yes | Yes | Yes |

View file

@ -93,13 +93,14 @@ const config: UserConfig = {
}, },
], ],
}, },
{
component: "GitHubStar",
},
], ],
sidebar: sidebar as any, sidebar: sidebar as any,
socialLinks: [ socialLinks: null,
{ icon: "github", link: "https://github.com/longbridge/gpui-component" },
],
editLink: { editLink: {
pattern: pattern:
"https://github.com/longbridge/gpui-component/edit/main/docs/:path", "https://github.com/longbridge/gpui-component/edit/main/docs/:path",

View file

@ -0,0 +1,40 @@
<template>
<a
href="https://github.com/longbridge/gpui-component"
target="_blank"
rel="noopener noreferrer"
class="github-star-button"
:title="`${stargazers_count} stars on GitHub`"
>
<svg viewBox="0 0 438.549 438.549">
<path
fill="currentColor"
d="M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z"
></path>
</svg>
<span>{{ starLabel }}</span>
</a>
</template>
<script setup>
import { data } from "../../../data/repo.data";
let stargazers_count = data.stargazers_count;
const starLabel =
stargazers_count / 1000 >= 1
? (stargazers_count / 1000.0).toFixed(1) + "k"
: stargazers_count.toString();
</script>
<style lang="scss" scoped>
@reference "../style.css";
.github-star-button {
@apply flex w-full py-3 px-0 lg:inline-flex lg:w-auto lg:py-0 lg:px-2;
@apply items-center text-sm gap-2 text-[var(--vp-c-text-1)] rounded hover:text-[var(--vp-c-brand-1)] no-underline;
svg {
@apply w-5 h-5;
}
}
</style>

View file

@ -3,7 +3,9 @@ import { h } from "vue";
import type { Theme } from "vitepress"; import type { Theme } from "vitepress";
import DefaultTheme from "vitepress/theme"; import DefaultTheme from "vitepress/theme";
import "./style.css"; import "./style.css";
import GitHubStar from "./components/GitHubStar.vue";
/** @type {import('vitepress').Theme} */
export default { export default {
extends: DefaultTheme, extends: DefaultTheme,
Layout: () => { Layout: () => {
@ -13,5 +15,6 @@ export default {
}, },
enhanceApp({ app, router, siteData }) { enhanceApp({ app, router, siteData }) {
// ... // ...
app.component("GitHubStar", GitHubStar);
}, },
} satisfies Theme; } satisfies Theme;

View file

@ -54,6 +54,8 @@
--vp-custom-block-tip-text: var(--vp-c-text-1); --vp-custom-block-tip-text: var(--vp-c-text-1);
--vp-custom-block-tip-bg: transparent; --vp-custom-block-tip-bg: transparent;
--vp-custom-block-tip-code-bg: var(--vp-c-default-soft); --vp-custom-block-tip-code-bg: var(--vp-c-default-soft);
--vp-input-switch-bg-color: var(--secondary);
--vp-input-border-color: var(--input);
} }
.dark { .dark {
@ -94,6 +96,20 @@
border-right: 1px solid var(--border); border-right: 1px solid var(--border);
} }
#app {
.VPMenu {
@apply p-1 rounded-md bg-[var(--popover)];
.link {
@apply text-sm py-1;
}
}
.DocSearch-Button {
@apply rounded-md py-0 px-2 h-8 lg:w-56 xl:w-64;
}
}
.vp-doc { .vp-doc {
[class*="language-"] pre { [class*="language-"] pre {
@apply rounded-md py-5 text-base font-mono; @apply rounded-md py-5 text-base font-mono;

View file

@ -22,18 +22,8 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from "vue"; import { data } from "./data/contributors.data";
const contributors = data;
const IGNORE_LOGINS = ["dependabot[bot]", "copilot"];
let contributors = ref([]);
fetch("https://api.github.com/repos/longbridge/gpui-component/contributors")
.then((res) => res.json())
.then((items) => {
let filtered = items.filter(
(item) => !IGNORE_LOGINS.includes(item.login.toLowerCase()),
);
contributors.value = filtered.slice(0, 24);
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View file

@ -0,0 +1,16 @@
const IGNORE_LOGINS = ["dependabot[bot]", "copilot"];
const API_URL =
"https://api.github.com/repos/longbridge/gpui-component/contributors";
export default {
async load() {
return await fetch(API_URL)
.then((res) => res.json())
.then((items) => {
let filtered = items.filter(
(item) => !IGNORE_LOGINS.includes(item.login.toLowerCase()),
);
return filtered.slice(0, 24);
});
},
};

7
docs/data/repo.data.js Normal file
View file

@ -0,0 +1,7 @@
const API_URL = "https://api.github.com/repos/longbridge/gpui-component";
export default {
async load() {
return await fetch(API_URL).then((res) => res.json());
},
};

View file

@ -86,29 +86,12 @@ Accordion::new("my-accordion")
## API Reference ## API Reference
### Accordion - [Accordion]
- [AccordionItem]
| Method | Description |
| --------------------- | -------------------------------------------------------------------- |
| `new(id)` | Create a new accordion with the given ID |
| `multiple(bool)` | Allow multiple items to be open simultaneously |
| `bordered(bool)` | Show borders around accordion items |
| `disabled(bool)` | Disable all accordion items |
| `item(fn)` | Add an accordion item using a builder function |
| `on_toggle_click(fn)` | Callback when items are toggled, receives `&[usize]` of open indices |
### AccordionItem
| Method | Description |
| ---------------- | --------------------------------- |
| `header(str)` | Set the header text |
| `child(el)` | Add content to the accordion item |
| `open(bool)` | Set initial open state |
| `disabled(bool)` | Disable this specific item |
### Sizing ### Sizing
Implements `Sizable` trait: Implements [Sizable] trait:
- `small()` - Small size - `small()` - Small size
- `medium()` - Medium size (default) - `medium()` - Medium size (default)
@ -145,3 +128,7 @@ Accordion::new("outer")
) )
}) })
``` ```
[Accordion]: https://docs.rs/gpui-component/latest/gpui_component/accordion/struct.Accordion.html
[AccordionItem]: https://docs.rs/gpui-component/latest/gpui_component/accordion/struct.AccordionItem.html
[Sizable]: https://docs.rs/gpui-component/latest/gpui_component/trait.Sizable.html

View file

@ -51,25 +51,27 @@ Alert::error("error-alert", "An error occurred while processing your request.")
### Alert Sizes ### Alert Sizes
```rust ```rust
Alert::info("alert", "Message content") use gpui_component::{alert::Alert, Sizable as _};
.with_size(Size::XSmall) // Extra small
.title("XSmall Alert")
Alert::info("alert", "Message content") Alert::info("alert", "Message content")
.with_size(Size::Small) // Small .xsmall()
.title("XSmall Alert")
Alert::info("alert", "Message content")
.small()
.title("Small Alert") .title("Small Alert")
Alert::info("alert", "Message content") Alert::info("alert", "Message content")
.with_size(Size::Medium) // Medium (default)
.title("Medium Alert") .title("Medium Alert")
Alert::info("alert", "Message content") Alert::info("alert", "Message content")
.with_size(Size::Large) // Large .large()
.title("Large Alert") .title("Large Alert")
``` ```
### Closable Alerts ### Closable Alerts
When you add an `on_close` handler, a close button appears on the alert:
```rust ```rust
Alert::info("closable-alert", "This alert can be dismissed.") Alert::info("closable-alert", "This alert can be dismissed.")
.title("Dismissible") .title("Dismissible")
@ -140,40 +142,7 @@ Alert::info("conditional-alert", "This alert may be hidden.")
## API Reference ## API Reference
### Alert Methods - [Alert]
| Method | Description |
| ---------------------- | --------------------------------------------------- |
| `new(id, message)` | Create a new alert with default (secondary) variant |
| `info(id, message)` | Create an info alert with blue styling |
| `success(id, message)` | Create a success alert with green styling |
| `warning(id, message)` | Create a warning alert with yellow/orange styling |
| `error(id, message)` | Create an error alert with red styling |
| `title(text)` | Set the alert title (not shown in banner mode) |
| `icon(icon)` | Set a custom icon for the alert |
| `banner()` | Enable banner mode (full width, no title) |
| `on_close(callback)` | Make alert closable with close button |
| `visible(bool)` | Control alert visibility |
| `with_size(size)` | Set alert size (XSmall, Small, Medium, Large) |
### Alert Variants
| Variant | Description | Default Icon |
| ----------- | ----------------------------- | ------------- |
| `Secondary` | Default gray styling | Info |
| `Info` | Blue informational styling | Info |
| `Success` | Green success styling | CircleCheck |
| `Warning` | Yellow/orange warning styling | TriangleAlert |
| `Error` | Red error styling | CircleX |
### Size Options
| Size | Padding | Gap | Border Radius |
| -------- | --------- | ---- | ------------- |
| `XSmall` | 12px/6px | 6px | Default |
| `Small` | 12px/8px | 6px | Default |
| `Medium` | 16px/10px | 12px | Default |
| `Large` | 20px/14px | 12px | Large |
## Examples ## Examples
@ -188,7 +157,6 @@ Alert::error(
- Terms of service must be accepted" - Terms of service must be accepted"
) )
.title("Validation Failed") .title("Validation Failed")
.with_size(Size::Medium)
``` ```
### Success Notification ### Success Notification
@ -210,7 +178,7 @@ Alert::warning(
Some services may be temporarily unavailable." Some services may be temporarily unavailable."
) )
.banner() .banner()
.with_size(Size::Large) .large()
``` ```
### Interactive Alert with Custom Action ### Interactive Alert with Custom Action
@ -245,3 +213,5 @@ Alert::warning(
.title("Security Alert") .title("Security Alert")
.icon(IconName::Shield) .icon(IconName::Shield)
``` ```
[Alert]: https://docs.rs/gpui-component/latest/gpui_component/alert/struct.Alert.html

View file

@ -17,11 +17,12 @@ use gpui_component::avatar::{Avatar, AvatarGroup};
### Basic Avatar ### Basic Avatar
You can create an [Avatar] by providing an image source URL and a user name:
```rust ```rust
// Avatar with image
Avatar::new() Avatar::new()
.src("https://example.com/avatar.jpg")
.name("John Doe") .name("John Doe")
.src("https://example.com/avatar.jpg")
``` ```
### Avatar with Fallback Text ### Avatar with Fallback Text
@ -91,7 +92,7 @@ Avatar::new()
## AvatarGroup ## AvatarGroup
Display multiple avatars in a compact, overlapping layout: The [AvatarGroup] component allows you to display multiple avatars in a compact, overlapping layout:
### Basic Group ### Basic Group
@ -117,7 +118,9 @@ AvatarGroup::new()
### Group with Ellipsis ### Group with Ellipsis
Show an ellipsis indicator when avatars are hidden due to the limit: Show an ellipsis indicator when avatars are hidden due to the limit.
In this example, only 3 avatars are shown, and "..." indicates there are more:
```rust ```rust
AvatarGroup::new() AvatarGroup::new()
@ -132,6 +135,8 @@ AvatarGroup::new()
### Group Sizes ### Group Sizes
The [Sizeable] trait can also be applied to AvatarGroup, and it will set the size for all contained avatars.
```rust ```rust
// Extra small group // Extra small group
AvatarGroup::new() AvatarGroup::new()
@ -175,44 +180,8 @@ AvatarGroup::new()
## API Reference ## API Reference
### Avatar - [Avatar]
- [AvatarGroup]
| Method | Description |
| ------------------- | ------------------------------------------ |
| `new()` | Create a new avatar |
| `src(source)` | Set image source (ImageSource) |
| `name(name)` | Set user name (used for initials fallback) |
| `placeholder(icon)` | Set placeholder icon (default: User icon) |
### Avatar Sizes (via Sizable trait)
| Method | Description |
| ------------------- | --------------------- |
| `xsmall()` | 20px avatar |
| `small()` | 24px avatar |
| `medium()` | 48px avatar (default) |
| `large()` | 80px avatar |
| `with_size(pixels)` | Custom size in pixels |
### AvatarGroup
| Method | Description |
| ------------------- | --------------------------------------- |
| `new()` | Create a new avatar group |
| `child(avatar)` | Add single avatar to group |
| `children(avatars)` | Add multiple avatars to group |
| `limit(count)` | Maximum avatars to display (default: 3) |
| `ellipsis()` | Show "..." when limit exceeded |
### AvatarGroup Sizes (via Sizable trait)
| Method | Description |
| ----------------- | ------------------------------- |
| `xsmall()` | Group of 20px avatars |
| `small()` | Group of 24px avatars |
| `medium()` | Group of 48px avatars (default) |
| `large()` | Group of 80px avatars |
| `with_size(size)` | Custom size for all avatars |
## Examples ## Examples
@ -276,3 +245,7 @@ Avatar::new().name("Alice") // Gets one color
Avatar::new().name("Bob") // Gets a different color Avatar::new().name("Bob") // Gets a different color
Avatar::new().name("Charlie") // Gets another color Avatar::new().name("Charlie") // Gets another color
``` ```
[Avatar]: https://docs.rs/gpui-component/latest/gpui_component/avatar/struct.Avatar.html
[AvatarGroup]: https://docs.rs/gpui-component/latest/gpui_component/avatar/struct.AvatarGroup.html
[Sizable]: https://docs.rs/gpui-component/latest/gpui_component/trait.Sizable.html

View file

@ -15,7 +15,11 @@ use gpui_component::badge::Badge;
## Usage ## Usage
### Basic Badge with Count ### Badge with Count
Use `count` to display a numeric badge, if the count is greater than zero (`> 0`) the badge will be shown, otherwise it will be hidden.
There is a default maximum count of `99`, any count above this will be displayed as `99+`. You can customize this maximum using the [max](https://docs.rs/gpui-component/latest/gpui_component/badge/struct.Badge.html#method.max) method.
```rust ```rust
Badge::new() Badge::new()
@ -23,7 +27,11 @@ Badge::new()
.child(Icon::new(IconName::Bell)) .child(Icon::new(IconName::Bell))
``` ```
### Badge Variants ### Variants
- Default: Displays a numeric count.
- Dot: A small dot indicator, typically used for status.
- Icon: Displays an icon instead of a number.
```rust ```rust
// Number badge (default) // Number badge (default)
@ -44,6 +52,8 @@ Badge::new()
### Badge Sizes ### Badge Sizes
The Badge is also implemented with the [Sizable] trait, allowing you to set small, medium (default), or large sizes.
```rust ```rust
// Small badge // Small badge
Badge::new() Badge::new()
@ -161,26 +171,7 @@ Badge::new()
## API Reference ## API Reference
### Badge - [Badge]
| Method | Description |
| ---------------- | -------------------------------------------- |
| `new()` | Create a new badge |
| `count(usize)` | Set the count to display (0 hides the badge) |
| `dot()` | Display as a small dot indicator |
| `icon(icon)` | Display an icon instead of count |
| `max(usize)` | Set maximum count to show (default: 99) |
| `color(color)` | Set badge background color |
| `child(element)` | Add child element to position badge on |
### Size Methods (from Sizable trait)
| Method | Description |
| ----------------- | --------------------------------- |
| `small()` | Small badge size (10px) |
| `medium()` | Medium badge size (16px, default) |
| `large()` | Large badge size (24px) |
| `with_size(size)` | Custom size |
## Examples ## Examples
@ -251,3 +242,6 @@ Badge::new().count(1000).max(999) // Shows "999+"
// Zero count hides the badge // Zero count hides the badge
Badge::new().count(0) // Badge not visible Badge::new().count(0) // Badge not visible
``` ```
[Badge]: https://docs.rs/gpui_component/latest/gpui_component/badge/struct.Badge.html
[Sizable]: https://docs.rs/gpui-component/latest/gpui_component/trait.Sizable.html

View file

@ -5,7 +5,7 @@ description: Displays a button or a component that looks like a button.
# Button # Button
A versatile button component with multiple variants, sizes, and states. Supports icons, loading states, and can be grouped together. The [Button] element with multiple variants, sizes, and states. Supports icons, loading states, and can be grouped together.
## Import ## Import
@ -25,7 +25,7 @@ Button::new("my-button")
}) })
``` ```
### Button Variants ### Variants
```rust ```rust
// Primary button // Primary button
@ -58,12 +58,27 @@ Button::new("btn-text").text().label("Text")
### Outline Buttons ### Outline Buttons
Outline style is not a variant itself, but can be combined with other variants.
```rust ```rust
Button::new("btn").primary().outline().label("Primary Outline") Button::new("btn").primary().outline().label("Primary Outline")
Button::new("btn").danger().outline().label("Danger Outline") Button::new("btn").danger().outline().label("Danger Outline")
``` ```
### Button Sizes ### Compact Button
The `compact` method reduces the padding of the button for a more condensed appearance.
```rust
// Compact (reduced padding)
Button::new("btn")
.label("Compact")
.compact()
```
### Sizeable
The Button supports the [Sizable] trait for different sizes.
```rust ```rust
Button::new("btn").xsmall().label("Extra Small") Button::new("btn").xsmall().label("Extra Small")
@ -94,6 +109,8 @@ Button::new("btn")
### Button States ### Button States
There have `disabled`, `loading`, `selected` state for buttons to indicate different statuses.
```rust ```rust
// Disabled // Disabled
Button::new("btn") Button::new("btn")
@ -109,14 +126,9 @@ Button::new("btn")
Button::new("btn") Button::new("btn")
.label("Selected") .label("Selected")
.selected(true) .selected(true)
// Compact (reduced padding)
Button::new("btn")
.label("Compact")
.compact()
``` ```
### Button Group ## Button Group
```rust ```rust
ButtonGroup::new("btn-group") ButtonGroup::new("btn-group")
@ -138,7 +150,7 @@ ButtonGroup::new("toggle-group")
}) })
``` ```
### Dropdown Button ## Dropdown Button
```rust ```rust
use gpui::Corner; use gpui::Corner;
@ -160,7 +172,7 @@ DropdownButton::new("dropdown")
}) })
``` ```
### Custom Variant ## Custom Variant
```rust ```rust
use gpui_component::button::ButtonCustomVariant; use gpui_component::button::ButtonCustomVariant;
@ -179,57 +191,10 @@ Button::new("custom-btn")
## API Reference ## API Reference
### Button - [Button]
- [ButtonGroup]
| Method | Description | - [DropdownButton]
| -------------------- | ------------------------------------- | - [ButtonCustomVariant]
| `new(id)` | Create a new button with the given ID |
| `label(str)` | Set button label text |
| `icon(icon)` | Add icon to button (before label) |
| `loading_icon(icon)` | Custom loading icon |
| `child(el)` | Add custom child element |
| `on_click(fn)` | Click event handler |
| `on_hover(fn)` | Hover event handler |
| `disabled(bool)` | Set disabled state |
| `loading(bool)` | Set loading state |
| `selected(bool)` | Set selected state |
| `compact()` | Reduce padding |
### Button Variants
| Method | Description |
| ----------------- | -------------------------------------- |
| `primary()` | Primary button style |
| `danger()` | Danger button style |
| `warning()` | Warning button style |
| `success()` | Success button style |
| `info()` | Info button style |
| `ghost()` | Ghost button style |
| `link()` | Link button style |
| `text()` | Text button style |
| `outline()` | Outline style (combines with variants) |
| `custom(variant)` | Custom variant |
### ButtonGroup
| Method | Description |
| ---------------- | ---------------------------------- |
| `new(id)` | Create a new button group |
| `child(button)` | Add button to group |
| `multiple(bool)` | Allow multiple selections |
| `compact()` | Compact spacing |
| `outline()` | Apply outline style to all buttons |
| `disabled(bool)` | Disable all buttons |
| `on_click(fn)` | Called with selected indices |
### DropdownButton
| Method | Description |
| --------------------------------------- | ----------------------------- |
| `new(id)` | Create a new dropdown button |
| `button(btn)` | Set the trigger button |
| `dropdown_menu(fn)` | Set dropdown menu builder |
| `dropdown_menu_with_anchor(corner, fn)` | Set menu with anchor position |
## Examples ## Examples
@ -254,3 +219,9 @@ Button::new("btn")
.child(IconName::Eye) .child(IconName::Eye)
) )
``` ```
[Button]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.Button.html
[ButtonGroup]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.ButtonGroup.html
[DropdownButton]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.DropdownButton.html
[ButtonCustomVariant]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.ButtonCustomVariant.html
[Sizable]: https://docs.rs/gpui-component/latest/gpui_component/trait.Sizable.html

View file

@ -7,6 +7,9 @@ description: A flexible calendar component for displaying months, navigating dat
A standalone calendar component that provides a rich interface for date selection and navigation. The Calendar component supports single date selection, date range selection, multiple month views, custom disabled dates, and comprehensive keyboard navigation. A standalone calendar component that provides a rich interface for date selection and navigation. The Calendar component supports single date selection, date range selection, multiple month views, custom disabled dates, and comprehensive keyboard navigation.
- [CalendarState]: For managing calendar state and selection.
- [Calendar]: For rendering the calendar UI.
## Import ## Import
```rust ```rust
@ -20,9 +23,8 @@ use gpui_component::{
### Basic Calendar ### Basic Calendar
```rust ```rust
let calendar = cx.new(|cx| CalendarState::new(window, cx)); let state = cx.new(|cx| CalendarState::new(window, cx));
Calendar::new(&state)
Calendar::new(&calendar)
``` ```
### Calendar with Initial Date ### Calendar with Initial Date
@ -30,13 +32,13 @@ Calendar::new(&calendar)
```rust ```rust
use chrono::Local; use chrono::Local;
let calendar = cx.new(|cx| { let state = cx.new(|cx| {
let mut state = CalendarState::new(window, cx); let mut state = CalendarState::new(window, cx);
state.set_date(Local::now().naive_local().date(), window, cx); state.set_date(Local::now().naive_local().date(), window, cx);
state state
}); });
Calendar::new(&calendar) Calendar::new(&state)
``` ```
### Date Range Calendar ### Date Range Calendar
@ -44,7 +46,7 @@ Calendar::new(&calendar)
```rust ```rust
use chrono::{Local, Days}; use chrono::{Local, Days};
let calendar = cx.new(|cx| { let state = cx.new(|cx| {
let mut state = CalendarState::new(window, cx); let mut state = CalendarState::new(window, cx);
let now = Local::now().naive_local().date(); let now = Local::now().naive_local().date();
state.set_date( state.set_date(
@ -55,27 +57,27 @@ let calendar = cx.new(|cx| {
state state
}); });
Calendar::new(&calendar) Calendar::new(&state)
``` ```
### Multiple Months Display ### Multiple Months Display
```rust ```rust
// Show 2 months side by side // Show 2 months side by side
Calendar::new(&calendar) Calendar::new(&state)
.number_of_months(2) .number_of_months(2)
// Show 3 months // Show 3 months
Calendar::new(&calendar) Calendar::new(&state)
.number_of_months(3) .number_of_months(3)
``` ```
### Calendar Sizes ### Calendar Sizes
```rust ```rust
Calendar::new(&calendar).large() Calendar::new(&state).large()
Calendar::new(&calendar) // medium (default) Calendar::new(&state) // medium (default)
Calendar::new(&calendar).small() Calendar::new(&state).small()
``` ```
## Date Restrictions ## Date Restrictions
@ -83,24 +85,24 @@ Calendar::new(&calendar).small()
### Disabled Weekends ### Disabled Weekends
```rust ```rust
let calendar = cx.new(|cx| { let state = cx.new(|cx| {
CalendarState::new(window, cx) CalendarState::new(window, cx)
.disabled_matcher(vec![0, 6]) // Sunday=0, Saturday=6 .disabled_matcher(vec![0, 6]) // Sunday=0, Saturday=6
}); });
Calendar::new(&calendar) Calendar::new(&state)
``` ```
### Disabled Specific Weekdays ### Disabled Specific Weekdays
```rust ```rust
// Disable Sundays, Wednesdays, and Saturdays // Disable Sundays, Wednesdays, and Saturdays
let calendar = cx.new(|cx| { let state = cx.new(|cx| {
CalendarState::new(window, cx) CalendarState::new(window, cx)
.disabled_matcher(vec![0, 3, 6]) .disabled_matcher(vec![0, 3, 6])
}); });
Calendar::new(&calendar) Calendar::new(&state)
``` ```
### Disabled Date Range ### Disabled Date Range
@ -110,7 +112,7 @@ use chrono::{Local, Days};
let now = Local::now().naive_local().date(); let now = Local::now().naive_local().date();
let calendar = cx.new(|cx| { let state = cx.new(|cx| {
CalendarState::new(window, cx) CalendarState::new(window, cx)
.disabled_matcher(Matcher::range( .disabled_matcher(Matcher::range(
Some(now), Some(now),
@ -118,14 +120,14 @@ let calendar = cx.new(|cx| {
)) ))
}); });
Calendar::new(&calendar) Calendar::new(&state)
``` ```
### Disabled Date Interval ### Disabled Date Interval
```rust ```rust
// Disable dates outside the interval (before/after specified dates) // Disable dates outside the interval (before/after specified dates)
let calendar = cx.new(|cx| { let state = cx.new(|cx| {
CalendarState::new(window, cx) CalendarState::new(window, cx)
.disabled_matcher(Matcher::interval( .disabled_matcher(Matcher::interval(
Some(now.checked_sub_days(Days::new(30)).unwrap()), Some(now.checked_sub_days(Days::new(30)).unwrap()),
@ -133,41 +135,41 @@ let calendar = cx.new(|cx| {
)) ))
}); });
Calendar::new(&calendar) Calendar::new(&state)
``` ```
### Custom Disabled Dates ### Custom Disabled Dates
```rust ```rust
// Disable first 5 days of each month // Disable first 5 days of each month
let calendar = cx.new(|cx| { let state = cx.new(|cx| {
CalendarState::new(window, cx) CalendarState::new(window, cx)
.disabled_matcher(Matcher::custom(|date| { .disabled_matcher(Matcher::custom(|date| {
date.day0() < 5 // day0() returns 0-based day date.day0() < 5 // day0() returns 0-based day
})) }))
}); });
Calendar::new(&calendar) Calendar::new(&state)
// Disable all Mondays // Disable all Mondays
let calendar = cx.new(|cx| { let state = cx.new(|cx| {
CalendarState::new(window, cx) CalendarState::new(window, cx)
.disabled_matcher(Matcher::custom(|date| { .disabled_matcher(Matcher::custom(|date| {
date.weekday() == chrono::Weekday::Mon date.weekday() == chrono::Weekday::Mon
})) }))
}); });
Calendar::new(&calendar) Calendar::new(&state)
// Disable past dates // Disable past dates
let calendar = cx.new(|cx| { let state = cx.new(|cx| {
CalendarState::new(window, cx) CalendarState::new(window, cx)
.disabled_matcher(Matcher::custom(|date| { .disabled_matcher(Matcher::custom(|date| {
*date < Local::now().naive_local().date() *date < Local::now().naive_local().date()
})) }))
}); });
Calendar::new(&calendar) Calendar::new(&state)
``` ```
## Month/Year Navigation ## Month/Year Navigation
@ -182,20 +184,20 @@ The Calendar automatically provides navigation controls:
### Custom Year Range ### Custom Year Range
```rust ```rust
let calendar = cx.new(|cx| { let state = cx.new(|cx| {
CalendarState::new(window, cx) CalendarState::new(window, cx)
.year_range((2020, 2030)) // Limit to specific year range .year_range((2020, 2030)) // Limit to specific year range
}); });
Calendar::new(&calendar) Calendar::new(&state)
``` ```
## Handle Selection Events ## Handle Selection Events
```rust ```rust
let calendar = cx.new(|cx| CalendarState::new(window, cx)); let state = cx.new(|cx| CalendarState::new(window, cx));
cx.subscribe(&calendar, |view, _, event, _| { cx.subscribe(&state, |view, _, event, _| {
match event { match event {
CalendarEvent::Selected(date) => { CalendarEvent::Selected(date) => {
match date { match date {
@ -216,7 +218,7 @@ cx.subscribe(&calendar, |view, _, event, _| {
} }
}); });
Calendar::new(&calendar) Calendar::new(&state)
``` ```
## Advanced Examples ## Advanced Examples
@ -226,14 +228,14 @@ Calendar::new(&calendar)
```rust ```rust
use chrono::Weekday; use chrono::Weekday;
let business_calendar = cx.new(|cx| { let state = cx.new(|cx| {
CalendarState::new(window, cx) CalendarState::new(window, cx)
.disabled_matcher(Matcher::custom(|date| { .disabled_matcher(Matcher::custom(|date| {
matches!(date.weekday(), Weekday::Sat | Weekday::Sun) matches!(date.weekday(), Weekday::Sat | Weekday::Sun)
})) }))
}); });
Calendar::new(&business_calendar) Calendar::new(&state)
``` ```
### Holiday Calendar ### Holiday Calendar
@ -249,36 +251,36 @@ let holidays: HashSet<NaiveDate> = [
NaiveDate::from_ymd_opt(2024, 12, 25).unwrap(), // Christmas NaiveDate::from_ymd_opt(2024, 12, 25).unwrap(), // Christmas
].into_iter().collect(); ].into_iter().collect();
let holiday_calendar = cx.new(|cx| { let state = cx.new(|cx| {
CalendarState::new(window, cx) CalendarState::new(window, cx)
.disabled_matcher(Matcher::custom(move |date| { .disabled_matcher(Matcher::custom(move |date| {
holidays.contains(date) holidays.contains(date)
})) }))
}); });
Calendar::new(&holiday_calendar) Calendar::new(&state)
``` ```
### Multi-Month Range Selector ### Multi-Month Range Selector
```rust ```rust
let range_calendar = cx.new(|cx| { let state = cx.new(|cx| {
let mut state = CalendarState::new(window, cx); let mut state = CalendarState::new(window, cx);
state.set_date(Date::Range(None, None), window, cx); // Range mode state.set_date(Date::Range(None, None), window, cx); // Range mode
state state
}); });
Calendar::new(&range_calendar) Calendar::new(&state)
.number_of_months(3) // Show 3 months for easier range selection .number_of_months(3) // Show 3 months for easier range selection
``` ```
### Quarterly View Calendar ### Quarterly View Calendar
```rust ```rust
let quarterly_calendar = cx.new(|cx| CalendarState::new(window, cx)); let state = cx.new(|cx| CalendarState::new(window, cx));
// Update to show current quarter's months // Update to show current quarter's months
Calendar::new(&quarterly_calendar) Calendar::new(&state)
.number_of_months(3) .number_of_months(3)
``` ```
@ -299,115 +301,9 @@ Calendar::new(&calendar)
## API Reference ## API Reference
### CalendarState - [Calendar]
- [CalendarState]
| Method | Description | - [RangeMatcher]
| ----------------------------------------- | ----------------------------------- |
| `new(window, cx)` | Create a new calendar state |
| `disabled_matcher(matcher)` | Set date disabling rules |
| `set_date(date, window, cx)` | Set selected date programmatically |
| `date()` | Get current selected date |
| `set_number_of_months(count, window, cx)` | Set number of months to display |
| `year_range(range)` | Set available year range (min, max) |
### Calendar
| Method | Description |
| ------------------------- | ---------------------------------------- |
| `new(state)` | Create calendar with state entity |
| `number_of_months(count)` | Set number of months to display |
| `with_size(size)` | Set calendar size (Small, Medium, Large) |
| `large()` | Large size variant |
| `small()` | Small size variant |
### Date
| Variant | Description |
| --------------------------------------------- | -------------------------- |
| `Single(Option<NaiveDate>)` | Single date selection mode |
| `Range(Option<NaiveDate>, Option<NaiveDate>)` | Date range selection mode |
| Method | Description |
| -------------------- | -------------------------------------- |
| `is_active(date)` | Check if date is currently selected |
| `is_single()` | Check if in single date mode |
| `is_in_range(date)` | Check if date is within selected range |
| `is_some()` | Check if any date is selected |
| `is_complete()` | Check if selection is complete |
| `start()` | Get start date of selection |
| `end()` | Get end date of selection |
| `format(format_str)` | Format date(s) using chrono format |
### Matcher
| Variant | Description |
| ----------------------------------------- | ------------------------------------------------ |
| `DayOfWeek(Vec<u32>)` | Disable specific weekdays (0=Sunday, 6=Saturday) |
| `Interval(IntervalMatcher)` | Disable dates outside interval |
| `Range(RangeMatcher)` | Disable dates within range |
| `Custom(Box<dyn Fn(&NaiveDate) -> bool>)` | Custom disable function |
| Method | Description |
| ------------------------- | -------------------------------------- |
| `interval(before, after)` | Create interval matcher |
| `range(from, to)` | Create range matcher |
| `custom(fn)` | Create custom matcher |
| `matched(date)` | Check if date matches the matcher |
| `date_matched(date)` | Check if Date enum matches the matcher |
### CalendarEvent
| Event | Description |
| ---------------- | ------------------------------- |
| `Selected(Date)` | Date or range selection changed |
## Size Variants
| Size | Description | Dimensions |
| -------- | ----------------- | -------------------------------- |
| `Small` | Compact calendar | Smaller spacing and text |
| `Medium` | Default size | Standard spacing and readability |
| `Large` | Spacious calendar | Larger touch targets and text |
## View Modes
The calendar supports three view modes:
1. **Day View**: Default monthly calendar grid
2. **Month View**: Grid of months for quick month selection
3. **Year View**: Grid of years for quick year selection
Users can navigate between views by clicking on the month/year buttons in the header.
## Keyboard Navigation
### Day View
- **Arrow Keys**: Navigate between dates
- **Enter**: Select current date
- **Escape**: Clear selection
- **Tab**: Navigate to header controls
- **Page Up/Down**: Previous/next month
- **Home**: Go to first day of month
- **End**: Go to last day of month
### Month View
- **Arrow Keys**: Navigate between months
- **Enter**: Select month and return to day view
- **Escape**: Return to day view
### Year View
- **Arrow Keys**: Navigate between years
- **Enter**: Select year and return to day view
- **Escape**: Return to day view
- **Page Up/Down**: Previous/next year page
### Header Navigation
- **Tab**: Navigate between prev/next buttons and month/year selectors
- **Enter/Space**: Activate buttons or toggle view modes
## Examples ## Examples
@ -476,3 +372,7 @@ Calendar::new(&availability_calendar)
``` ```
The Calendar component provides a foundation for any date-related UI requirements, from simple date pickers to complex scheduling interfaces. The Calendar component provides a foundation for any date-related UI requirements, from simple date pickers to complex scheduling interfaces.
[Calendar]: https://docs.rs/gpui-component/latest/gpui_component/calendar/struct.Calendar.html
[CalendarState]: https://docs.rs/gpui-component/latest/gpui_component/calendar/struct.CalendarState.html
[RangeMatcher]: https://docs.rs/gpui-component/latest/gpui_component/calendar/struct.RangeMatcher.html

View file

@ -82,17 +82,7 @@ Checkbox::new("checkbox")
## API Reference ## API Reference
### Checkbox - [Checkbox]
| Method | Description |
| ------------------ | ----------------------------------------------------------- |
| `new(id)` | Create a new checkbox with the given ID |
| `label(text)` | Set label text |
| `checked(bool)` | Set checked state |
| `disabled(bool)` | Set disabled state |
| `on_click(fn)` | Callback when clicked, receives `&bool` (new checked state) |
| `tab_stop(bool)` | Enable/disable tab navigation (default: true) |
| `tab_index(isize)` | Set tab order index (default: 0) |
### Styling ### Styling
@ -145,3 +135,5 @@ v_flex()
})) }))
) )
``` ```
[Checkbox]: https://docs.rs/gpui-component/latest/gpui_component/checkbox/struct.Checkbox.html

View file

@ -87,86 +87,7 @@ Input::new(&url_state)
## API Reference ## API Reference
### Clipboard - [Clipboard]
| Method | Description |
| --------------- | ------------------------------------------------------- |
| `new(id)` | Create a new clipboard component with the given ID |
| `value(str)` | Set static text to copy to clipboard |
| `value_fn(fn)` | Set dynamic function that returns the value to copy |
| `content(fn)` | Set custom content to display alongside the copy button |
| `on_copied(fn)` | Callback executed when content is successfully copied |
### Method Details
#### `value(value: impl Into<SharedString>)`
Sets a static value that will be copied to the clipboard when the button is clicked.
```rust
Clipboard::new("static")
.value("Static text to copy")
```
#### `value_fn(fn: impl Fn(&mut Window, &mut App) -> SharedString + 'static)`
Sets a function that will be called to get the value when the copy action occurs. This is useful for dynamic content that may change over time.
```rust
Clipboard::new("dynamic")
.value_fn(|_, cx| {
format!("Current time: {}", SystemTime::now())
})
```
#### `content(fn: impl Fn(&mut Window, &mut App) -> E + 'static)`
Sets custom content to display before the copy button. The content can be any element that implements `IntoElement`.
```rust
Clipboard::new("with-content")
.content(|_, _| Label::new("Copy me"))
.value("Hello")
```
#### `on_copied(fn: impl Fn(SharedString, &mut Window, &mut App) + 'static)`
Sets a callback that is executed when content is successfully copied. Receives the copied value as the first parameter.
```rust
Clipboard::new("with-callback")
.value("Hello")
.on_copied(|value, window, cx| {
println!("Copied: {}", value);
window.push_notification("Copied to clipboard!", cx);
})
```
## Behavior
### Visual States
The clipboard button has two visual states:
1. **Default State**: Shows a copy icon (IconName::Copy)
2. **Copied State**: Shows a checkmark icon (IconName::Check) for 2 seconds after successful copy
### Copy Process
1. User clicks the clipboard button
2. The component determines the value to copy:
- If `value_fn` is set, calls the function to get the current value
- Otherwise, uses the static `value`
3. Writes the value to the system clipboard using `ClipboardItem::new_string()`
4. Changes the button icon to a checkmark
5. Calls the `on_copied` callback if provided
6. After 2 seconds, resets the icon back to the copy icon
### Event Handling
- Click events are handled internally and call `cx.stop_propagation()` to prevent bubbling
- The component is disabled (unclickable) while in the "copied" state
- Uses GPUI's clipboard API (`cx.write_to_clipboard()`) for system integration
## Examples ## Examples
@ -247,3 +168,5 @@ The Clipboard component currently supports copying text strings to the clipboard
- Plain text strings - Plain text strings
- UTF-8 encoded content - UTF-8 encoded content
- Cross-platform clipboard integration - Cross-platform clipboard integration
[Clipboard]: https://docs.rs/gpui-component/latest/gpui_component/clipboard/struct.Clipboard.html

View file

@ -212,49 +212,9 @@ The color picker preserves alpha values when selecting colors and allows modific
## API Reference ## API Reference
### ColorPickerState - [ColorPicker]
- [ColorPickerState]
| Method | Description | - [ColorPickerEvent]
| ------------------------------ | -------------------------------------- |
| `new(window, cx)` | Create a new color picker state |
| `default_value(color)` | Set the default selected color |
| `set_value(color, window, cx)` | Programmatically set the current color |
| `value()` | Get the currently selected color |
### ColorPicker
| Method | Description |
| ------------------------- | -------------------------------------------------- |
| `new(state)` | Create a new color picker with the given state |
| `featured_colors(colors)` | Set custom featured colors array |
| `size(size)` | Set the picker size (XSmall, Small, Medium, Large) |
| `icon(icon)` | Display icon instead of color square |
| `label(text)` | Add a label to the color picker |
| `anchor(corner)` | Set dropdown anchor position |
### ColorPickerEvent
| Event | Description |
| ---------------------- | ------------------------------------ |
| `Change(Option<Hsla>)` | Emitted when color selection changes |
### Size Options
| Size | Description |
| -------------- | ------------------------------ |
| `Size::XSmall` | Extra small picker button |
| `Size::Small` | Small picker button |
| `Size::Medium` | Medium picker button (default) |
| `Size::Large` | Large picker button |
### Anchor Positions
| Corner | Description |
| --------------------- | ------------------------------------- |
| `Corner::TopLeft` | Dropdown opens below and to the right |
| `Corner::TopRight` | Dropdown opens below and to the left |
| `Corner::BottomLeft` | Dropdown opens above and to the right |
| `Corner::BottomRight` | Dropdown opens above and to the left |
## Examples ## Examples
@ -409,3 +369,7 @@ let _subscription = cx.subscribe(&color_picker, |this, _, ev, _| match ev {
} }
}); });
``` ```
[ColorPicker]: https://docs.rs/gpui-component/latest/gpui_component/color_picker/struct.ColorPicker.html
[ColorPickerState]: https://docs.rs/gpui-component/latest/gpui_component/color_picker/struct.ColorPickerState.html
[ColorPickerEvent]: https://docs.rs/gpui-component/latest/gpui_component/color_picker/enum.ColorPickerEvent.html

View file

@ -11,7 +11,7 @@ The Menu component provides both context menus (right-click menus) and popup men
```rust ```rust
use gpui_component::{ use gpui_component::{
menu::{PopupMenu, ContextMenuExt, DropdownMenu}, menu::{PopupMenu, PopupMenuItem, ContextMenuExt, DropdownMenu},
Button Button
}; };
use gpui::{actions, Action}; use gpui::{actions, Action};
@ -19,7 +19,7 @@ use gpui::{actions, Action};
## Usage ## Usage
### Context Menu ### ContextMenu
Context menus appear when right-clicking on an element: Context menus appear when right-clicking on an element:
@ -41,18 +41,38 @@ div()
Dropdown menus are triggered by buttons or other interactive elements: Dropdown menus are triggered by buttons or other interactive elements:
```rust ```rust
use gpui_component::menu::DropdownMenu; use gpui_component::popup_menu::{PopupMenuExt as _, PopupMenuItem};
let view = cx.entity();
Button::new("menu-btn") Button::new("menu-btn")
.label("Open Menu") .label("Open Menu")
.dropdown_menu(|menu, window, cx| { .dropdown_menu(|menu, window, cx| {
menu.menu("New File", Box::new(NewFile)) menu.menu("New File", Box::new(NewFile))
.menu("Open File", Box::new(OpenFile)) .menu("Open File", Box::new(OpenFile))
.link("Documentation", "https://longbridge.github.io/gpui-component/")
.separator()
.item(PopupMenuItem::new("Custom Action")
.on_click(window.listener_for(&view, |this, _, window, cx| {
// Custom action logic here
this.
})
)
.separator() .separator()
.menu("Exit", Box::new(Exit)) .menu("Exit", Box::new(Exit))
}) })
``` ```
:::tip
As you see, the each menu item is associated with an [Action],
we choice this design to better integrate with GPUI's action and key binding system,
allowing menu items to automatically display keyboard shortcuts when applicable.
So, the [Action] is the recommended way to define menu item behaviors.
However, if you prefer not to use [Action]s, you can create custom menu items using the `item` method along with [PopupMenuItem].
There have a `on_click` callback to handle the click event directly.
:::
### Menu with Anchor Position ### Menu with Anchor Position
Control where the dropdown menu appears relative to the trigger: Control where the dropdown menu appears relative to the trigger:
@ -438,6 +458,7 @@ Button::new("settings")
7. **Clear Labels**: Use descriptive, action-oriented labels 7. **Clear Labels**: Use descriptive, action-oriented labels
8. **Reasonable Limits**: Use scrollable menus for more than 10-15 items 8. **Reasonable Limits**: Use scrollable menus for more than 10-15 items
[PopupMenu]: https://docs.rs/gpui-component/latest/gpui_component/menu/popup_menu/struct.PopupMenu.html [PopupMenu]: https://docs.rs/gpui-component/latest/gpui_component/menu/struct.PopupMenu.html
[PopupMenuItem]: https://docs.rs/gpui-component/latest/gpui_component/menu/popup_menu/struct.PopupMenuItem.html [PopupMenuItem]: https://docs.rs/gpui-component/latest/gpui_component/menu/struct.PopupMenuItem.html
[context_menu]: https://docs.rs/gpui-component/latest/gpui_component/menu/context_menu/trait.ContextMenuExt.html#method.context_menu [context_menu]: https://docs.rs/gpui-component/latest/gpui_component/menu/trait.ContextMenuExt.html#method.context_menu
[Action]: https://docs.rs/gpui/latest/gpui/trait.Action.html

View file

@ -25,8 +25,8 @@ Button::new("ok")
Add the following to your `Cargo.toml`: Add the following to your `Cargo.toml`:
```toml ```toml
gpui-component = "0.2"
gpui = "0.2" gpui = "0.2"
gpui-component = "0.3"
``` ```
## Hello World ## Hello World