From b6a442ce736735104f1c06aa0ec2fe7f647a2717 Mon Sep 17 00:00:00 2001
From: thororen1234 <78185467+thororen1234@users.noreply.github.com>
Date: Fri, 24 Apr 2026 12:50:30 -0400
Subject: [PATCH] Drop Components
---
.../components/ComponentsTab.tsx | 209 -----------
.../components.dev/components/DocPage.tsx | 258 -------------
.../components/SectionWrapper.tsx | 23 --
.../components/icons/EquicordIcon.tsx | 16 -
.../components.dev/components/index.tsx | 350 ------------------
.../components/tabs/AccordionTab.tsx | 102 -----
.../components/tabs/AlertTab.tsx | 129 -------
.../components/tabs/AnchorTab.tsx | 109 ------
.../components/tabs/AnimationsTab.tsx | 220 -----------
.../components/tabs/AvatarTab.tsx | 157 --------
.../components/tabs/BadgeTab.tsx | 142 -------
.../components/tabs/ButtonsTab.tsx | 142 -------
.../components/tabs/CalendarTab.tsx | 194 ----------
.../components/tabs/CardTab.tsx | 117 ------
.../components/tabs/CheckboxGroupTab.tsx | 133 -------
.../components/tabs/CheckboxTab.tsx | 147 --------
.../components/tabs/ChipTab.tsx | 71 ----
.../components/tabs/ClickableTab.tsx | 141 -------
.../components/tabs/CodeBlockTab.tsx | 122 ------
.../components/tabs/ColorPickerTab.tsx | 243 ------------
.../components/tabs/ComboboxTab.tsx | 202 ----------
.../components/tabs/DividerTab.tsx | 56 ---
.../components/tabs/ErrorBoundaryTab.tsx | 169 ---------
.../components/tabs/FocusLockTab.tsx | 101 -----
.../components/tabs/GuildIconTab.tsx | 147 --------
.../components/tabs/HeadingTab.tsx | 118 ------
.../components/tabs/LayerModalTab.tsx | 135 -------
.../components/tabs/ListboxTab.tsx | 175 ---------
.../components/tabs/MenuTab.tsx | 235 ------------
.../components/tabs/ModalTab.tsx | 273 --------------
.../components/tabs/NoticeTab.tsx | 112 ------
.../components/tabs/PaginatorTab.tsx | 105 ------
.../components/tabs/PopoverTab.tsx | 142 -------
.../components/tabs/ProgressBarTab.tsx | 159 --------
.../components/tabs/RadioGroupTab.tsx | 164 --------
.../components/tabs/RichTooltipTab.tsx | 126 -------
.../components/tabs/ScrollerTab.tsx | 90 -----
.../components/tabs/SearchBarTab.tsx | 94 -----
.../components/tabs/SelectTab.tsx | 155 --------
.../components/tabs/SkeletonTab.tsx | 69 ----
.../components/tabs/SliderTab.tsx | 148 --------
.../components/tabs/SpinnerTab.tsx | 85 -----
.../components/tabs/SwitchTab.tsx | 151 --------
.../components/tabs/TabBarTab.tsx | 179 ---------
.../components/tabs/TextAreaTab.tsx | 100 -----
.../components/tabs/TextButtonTab.tsx | 80 ----
.../components/tabs/TextInputTab.tsx | 121 ------
.../components/tabs/TimestampTab.tsx | 158 --------
.../components/tabs/ToastTab.tsx | 153 --------
.../components/tabs/TooltipTab.tsx | 157 --------
.../components/tabs/TypographyTab.tsx | 144 -------
.../components/tabs/UserSummaryItemTab.tsx | 149 --------
.../components.dev/constants.ts | 184 ---------
src/equicordplugins/components.dev/index.tsx | 164 --------
src/equicordplugins/components.dev/styles.css | 314 ----------------
.../components.dev/types/accordion.d.ts | 18 -
.../components.dev/types/alert.d.ts | 23 --
.../components.dev/types/anchor.d.ts | 19 -
.../components.dev/types/avatar.d.ts | 52 ---
.../components.dev/types/badge.d.ts | 57 ---
.../components.dev/types/button.d.ts | 60 ---
.../components.dev/types/calendar.d.ts | 40 --
.../components.dev/types/checkbox.d.ts | 50 ---
.../components.dev/types/chip.d.ts | 20 -
.../components.dev/types/clickable.d.ts | 19 -
.../components.dev/types/colorpicker.d.ts | 77 ----
.../components.dev/types/errorboundary.d.ts | 31 --
.../components.dev/types/focuslock.d.ts | 11 -
.../components.dev/types/guildicon.d.ts | 15 -
.../components.dev/types/heading.d.ts | 32 --
.../components.dev/types/index.d.ts | 40 --
.../components.dev/types/input.d.ts | 121 ------
.../components.dev/types/menu.d.ts | 211 -----------
.../components.dev/types/modal.d.ts | 119 ------
.../components.dev/types/notice.d.ts | 20 -
.../components.dev/types/paginator.d.ts | 24 --
.../components.dev/types/progress.d.ts | 29 --
.../components.dev/types/radio.d.ts | 44 ---
.../components.dev/types/scroller.d.ts | 46 ---
.../components.dev/types/select.d.ts | 73 ----
.../components.dev/types/skeleton.d.ts | 10 -
.../components.dev/types/slider.d.ts | 50 ---
.../components.dev/types/spinner.d.ts | 30 --
.../components.dev/types/switch.d.ts | 17 -
.../components.dev/types/tabbar.d.ts | 55 ---
.../components.dev/types/timestamp.d.ts | 28 --
.../components.dev/types/toast.d.ts | 32 --
.../components.dev/types/tooltip.d.ts | 89 -----
.../components.dev/types/usersummary.d.ts | 28 --
89 files changed, 9729 deletions(-)
delete mode 100644 src/equicordplugins/components.dev/components/ComponentsTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/DocPage.tsx
delete mode 100644 src/equicordplugins/components.dev/components/SectionWrapper.tsx
delete mode 100644 src/equicordplugins/components.dev/components/icons/EquicordIcon.tsx
delete mode 100644 src/equicordplugins/components.dev/components/index.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/AccordionTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/AlertTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/AnchorTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/AnimationsTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/AvatarTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/BadgeTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/ButtonsTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/CalendarTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/CardTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/CheckboxGroupTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/CheckboxTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/ChipTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/ClickableTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/CodeBlockTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/ColorPickerTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/ComboboxTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/DividerTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/ErrorBoundaryTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/FocusLockTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/GuildIconTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/HeadingTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/LayerModalTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/ListboxTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/MenuTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/ModalTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/NoticeTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/PaginatorTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/PopoverTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/ProgressBarTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/RadioGroupTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/RichTooltipTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/ScrollerTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/SearchBarTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/SelectTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/SkeletonTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/SliderTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/SpinnerTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/SwitchTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/TabBarTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/TextAreaTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/TextButtonTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/TextInputTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/TimestampTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/ToastTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/TooltipTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/TypographyTab.tsx
delete mode 100644 src/equicordplugins/components.dev/components/tabs/UserSummaryItemTab.tsx
delete mode 100644 src/equicordplugins/components.dev/constants.ts
delete mode 100644 src/equicordplugins/components.dev/index.tsx
delete mode 100644 src/equicordplugins/components.dev/styles.css
delete mode 100644 src/equicordplugins/components.dev/types/accordion.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/alert.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/anchor.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/avatar.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/badge.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/button.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/calendar.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/checkbox.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/chip.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/clickable.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/colorpicker.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/errorboundary.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/focuslock.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/guildicon.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/heading.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/index.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/input.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/menu.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/modal.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/notice.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/paginator.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/progress.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/radio.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/scroller.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/select.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/skeleton.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/slider.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/spinner.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/switch.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/tabbar.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/timestamp.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/toast.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/tooltip.d.ts
delete mode 100644 src/equicordplugins/components.dev/types/usersummary.d.ts
diff --git a/src/equicordplugins/components.dev/components/ComponentsTab.tsx b/src/equicordplugins/components.dev/components/ComponentsTab.tsx
deleted file mode 100644
index 724a76cc9..000000000
--- a/src/equicordplugins/components.dev/components/ComponentsTab.tsx
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import ErrorBoundary from "@components/ErrorBoundary";
-import { Heading } from "@components/Heading";
-import { SettingsTab, wrapTab } from "@components/settings";
-import { Margins } from "@utils/margins";
-import { TabBar, useMemo, useState } from "@webpack/common";
-
-import { SearchBar } from ".";
-import AccordionTab from "./tabs/AccordionTab";
-import AlertTab from "./tabs/AlertTab";
-import AnchorTab from "./tabs/AnchorTab";
-import AnimationsTab from "./tabs/AnimationsTab";
-import AvatarTab from "./tabs/AvatarTab";
-import BadgeTab from "./tabs/BadgeTab";
-import ButtonsTab from "./tabs/ButtonsTab";
-import CalendarTab from "./tabs/CalendarTab";
-import CardTab from "./tabs/CardTab";
-import CheckboxGroupTab from "./tabs/CheckboxGroupTab";
-import CheckboxTab from "./tabs/CheckboxTab";
-import ChipTab from "./tabs/ChipTab";
-import ClickableTab from "./tabs/ClickableTab";
-import CodeBlockTab from "./tabs/CodeBlockTab";
-import ColorPickerTab from "./tabs/ColorPickerTab";
-import ComboboxTab from "./tabs/ComboboxTab";
-import DividerTab from "./tabs/DividerTab";
-import ErrorBoundaryTab from "./tabs/ErrorBoundaryTab";
-import FocusLockTab from "./tabs/FocusLockTab";
-import GuildIconTab from "./tabs/GuildIconTab";
-import HeadingTab from "./tabs/HeadingTab";
-import LayerModalTab from "./tabs/LayerModalTab";
-import ListboxTab from "./tabs/ListboxTab";
-import MenuTab from "./tabs/MenuTab";
-import ModalTab from "./tabs/ModalTab";
-import NoticeTab from "./tabs/NoticeTab";
-import PaginatorTab from "./tabs/PaginatorTab";
-import PopoverTab from "./tabs/PopoverTab";
-import ProgressBarTab from "./tabs/ProgressBarTab";
-import RadioGroupTab from "./tabs/RadioGroupTab";
-import RichTooltipTab from "./tabs/RichTooltipTab";
-import ScrollerTab from "./tabs/ScrollerTab";
-import SearchBarTab from "./tabs/SearchBarTab";
-import SelectTab from "./tabs/SelectTab";
-import SkeletonTab from "./tabs/SkeletonTab";
-import SliderTab from "./tabs/SliderTab";
-import SpinnerTab from "./tabs/SpinnerTab";
-import SwitchTab from "./tabs/SwitchTab";
-import TabBarTab from "./tabs/TabBarTab";
-import TextAreaTab from "./tabs/TextAreaTab";
-import TextButtonTab from "./tabs/TextButtonTab";
-import TextInputTab from "./tabs/TextInputTab";
-import TimestampTab from "./tabs/TimestampTab";
-import ToastTab from "./tabs/ToastTab";
-import TooltipTab from "./tabs/TooltipTab";
-import TypographyTab from "./tabs/TypographyTab";
-import UserSummaryItemTab from "./tabs/UserSummaryItemTab";
-
-const TABS = [
- { id: "accordion", label: "Accordion" },
- { id: "alert", label: "Alert" },
- { id: "animations", label: "Animations" },
- { id: "anchor", label: "Anchor" },
- { id: "avatar", label: "Avatar" },
- { id: "badge", label: "Badge" },
- { id: "buttons", label: "Buttons" },
- { id: "calendar", label: "Calendar" },
- { id: "card", label: "Card" },
- { id: "chip", label: "Chip" },
- { id: "checkbox", label: "Checkbox" },
- { id: "checkboxgroup", label: "CheckboxGroup" },
- { id: "clickable", label: "Clickable" },
- { id: "codeblock", label: "CodeBlock" },
- { id: "colorpicker", label: "ColorPicker" },
- { id: "combobox", label: "Combobox" },
- { id: "divider", label: "Divider" },
- { id: "errorboundary", label: "ErrorBoundary" },
- { id: "focuslock", label: "FocusLock" },
- { id: "guildicon", label: "GuildIcon" },
- { id: "heading", label: "Heading" },
- { id: "layermodal", label: "LayerModal" },
- { id: "listbox", label: "Listbox" },
- { id: "menu", label: "Menu" },
- { id: "modal", label: "Modal" },
- { id: "notice", label: "Notice" },
- { id: "paginator", label: "Paginator" },
- { id: "popover", label: "Popover" },
- { id: "progressbar", label: "ProgressBar" },
- { id: "radiogroup", label: "RadioGroup" },
- { id: "richtooltip", label: "RichTooltip" },
- { id: "scroller", label: "Scroller" },
- { id: "searchbar", label: "SearchBar" },
- { id: "select", label: "Select" },
- { id: "skeleton", label: "Skeleton" },
- { id: "slider", label: "Slider" },
- { id: "spinner", label: "Spinner" },
- { id: "switch", label: "Switch" },
- { id: "tabbar", label: "TabBar" },
- { id: "textarea", label: "TextArea" },
- { id: "textbutton", label: "TextButton" },
- { id: "textinput", label: "TextInput" },
- { id: "timestamp", label: "Timestamp" },
- { id: "toast", label: "Toast" },
- { id: "tooltip", label: "Tooltip" },
- { id: "typography", label: "Typography" },
- { id: "usersummaryitem", label: "UserSummaryItem" },
-
-].sort((a, b) => a.label.localeCompare(b.label));
-
-type TabId = typeof TABS[number]["id"];
-
-const TAB_COMPONENTS: Record = {
- accordion: AccordionTab,
- alert: AlertTab,
- animations: AnimationsTab,
- anchor: AnchorTab,
- avatar: AvatarTab,
- badge: BadgeTab,
- buttons: ButtonsTab,
- calendar: CalendarTab,
- card: CardTab,
- chip: ChipTab,
- checkbox: CheckboxTab,
- checkboxgroup: CheckboxGroupTab,
- clickable: ClickableTab,
- codeblock: CodeBlockTab,
- colorpicker: ColorPickerTab,
- combobox: ComboboxTab,
- divider: DividerTab,
- errorboundary: ErrorBoundaryTab,
- focuslock: FocusLockTab,
- guildicon: GuildIconTab,
- heading: HeadingTab,
- layermodal: LayerModalTab,
- listbox: ListboxTab,
- menu: MenuTab,
- modal: ModalTab,
- notice: NoticeTab,
- paginator: PaginatorTab,
- popover: PopoverTab,
- progressbar: ProgressBarTab,
- radiogroup: RadioGroupTab,
- richtooltip: RichTooltipTab,
- scroller: ScrollerTab,
- searchbar: SearchBarTab,
- select: SelectTab,
- skeleton: SkeletonTab,
- slider: SliderTab,
- spinner: SpinnerTab,
- switch: SwitchTab,
- tabbar: TabBarTab,
- textarea: TextAreaTab,
- textbutton: TextButtonTab,
- textinput: TextInputTab,
- timestamp: TimestampTab,
- toast: ToastTab,
- tooltip: TooltipTab,
- typography: TypographyTab,
- usersummaryitem: UserSummaryItemTab,
-};
-
-function ComponentsTab() {
- const [currentTab, setCurrentTab] = useState("avatar");
- const [search, setSearch] = useState("");
- const TabComponent = TAB_COMPONENTS[currentTab];
-
- const filteredTabs = useMemo(() => {
- if (!search.trim()) return TABS;
- const query = search.toLowerCase();
- return TABS.filter(tab => tab.label.toLowerCase().includes(query));
- }, [search]);
-
- return (
-
- Components
-
- setSearch("")}
- placeholder="Search components..."
- />
-
-
- {filteredTabs.map(tab => (
-
- {tab.label}
-
- ))}
-
-
-
-
-
-
-
- );
-}
-
-export default wrapTab(ComponentsTab, "ComponentsTab");
diff --git a/src/equicordplugins/components.dev/components/DocPage.tsx b/src/equicordplugins/components.dev/components/DocPage.tsx
deleted file mode 100644
index 59de63cae..000000000
--- a/src/equicordplugins/components.dev/components/DocPage.tsx
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2026 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { CodeBlock } from "@components/CodeBlock";
-import { classNameFactory } from "@utils/css";
-
-import { DiscordHeading, DiscordText, Divider, InlineCode, Notice, Paragraph } from ".";
-
-const cl = classNameFactory("vc-compfinder-");
-
-export interface PropDef {
- name: string;
- type: string;
- default?: string;
- required?: boolean;
- internal?: boolean;
- description: string;
-}
-
-export interface DocNotice {
- type: "info" | "warn" | "danger" | "positive";
- children: React.ReactNode;
-}
-
-export interface DemoSection {
- title: string;
- description?: string;
- children: React.ReactNode;
- code?: string;
- relevantProps?: string[];
- notice?: DocNotice;
- id?: string;
-}
-
-export interface PropGroup {
- title: string;
- props: PropDef[];
-}
-
-export interface CodeExample {
- label: string;
- code: string;
-}
-
-export interface DocPageConfig {
- overview: string;
- importPath: string;
- sections?: DemoSection[];
- demos?: DemoSection[];
- props: PropDef[] | PropGroup[];
- examples?: CodeExample[];
- componentName?: string;
- notices?: DocNotice[];
- showToc?: boolean;
-}
-
-function isGrouped(props: PropDef[] | PropGroup[]): props is PropGroup[] {
- return props.length > 0 && "props" in props[0];
-}
-
-function allProps(props: PropDef[] | PropGroup[]): PropDef[] {
- return isGrouped(props) ? props.flatMap(g => g.props) : props;
-}
-
-function generateId(title: string): string {
- return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
-}
-
-function PropsTable({ props, showLegend }: { props: PropDef[]; showLegend?: boolean; }) {
- const hasRequired = props.some(p => p.required);
- const hasInternal = props.some(p => p.internal);
- return (
- <>
-
-
-
-
- FIELD
- TYPE
- DEFAULT
- DESCRIPTION
-
-
-
- {props.map(p => (
-
-
- {p.name}
-
- {p.type}
- {p.default ?? - }
- {p.description}
-
- ))}
-
-
-
- {showLegend && (hasRequired || hasInternal) && (
-
- {hasRequired && Required }
- {hasInternal && Internal }
-
- )}
- >
- );
-}
-
-function TableOfContents({ entries }: { entries: { id: string; label: string; }[]; }) {
- return (
-
- );
-}
-
-function MajorSection({ title, id, children }: { title: string; id: string; children: React.ReactNode; }) {
- return (
-
- {title}
- {children}
-
- );
-}
-
-function DemoSectionBlock({ section, relevantProps }: { section: DemoSection; relevantProps: PropDef[] | null; }) {
- const id = section.id ?? generateId(section.title);
- return (
-
-
{section.title}
- {section.notice && (
-
{section.notice.children}
- )}
- {section.description && (
-
{section.description}
- )}
-
- {section.children}
-
- {section.code && (
-
- )}
- {relevantProps && (
-
- )}
-
- );
-}
-
-export function DocPage({ componentName, overview, importPath, sections, demos, props, examples, notices, showToc }: DocPageConfig) {
- const items = sections ?? demos ?? [];
- const flat = allProps(props);
-
- const tocEntries = [
- { id: "overview", label: "Overview" },
- { id: "import", label: "Import" },
- ...items.map(s => ({ id: s.id ?? generateId(s.title), label: s.title })),
- { id: "api-reference", label: "API Reference" },
- ...(examples?.length ? [{ id: "examples", label: "Examples" }] : []),
- ];
-
- const shouldShowToc = showToc ?? items.length >= 4;
-
- return (
-
- {componentName && (
-
- {componentName}
-
- )}
-
-
-
Overview
-
{overview}
-
-
- {notices?.map((notice, i) => (
-
{notice.children}
- ))}
-
- {shouldShowToc &&
}
-
-
-
-
-
- {items.map(section => {
- const relevant = section.relevantProps?.length
- ? flat.filter(p => section.relevantProps!.includes(p.name))
- : null;
-
- return [
-
,
-
,
- ];
- })}
-
-
-
-
- {isGrouped(props) ? (
- props.map(group => (
-
- ))
- ) : (
-
- )}
-
-
- {examples?.length ? (
- <>
-
-
- {examples.map(ex => (
-
- ))}
-
- >
- ) : null}
-
- );
-}
diff --git a/src/equicordplugins/components.dev/components/SectionWrapper.tsx b/src/equicordplugins/components.dev/components/SectionWrapper.tsx
deleted file mode 100644
index be236a9c3..000000000
--- a/src/equicordplugins/components.dev/components/SectionWrapper.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Heading } from "@components/Heading";
-import { Margins } from "@utils/margins";
-import { classes } from "@utils/misc";
-
-interface SectionWrapperProps {
- title: string;
- children: React.ReactNode;
-}
-
-export function SectionWrapper({ title, children }: SectionWrapperProps) {
- return (
-
- {title}
- {children}
-
- );
-}
diff --git a/src/equicordplugins/components.dev/components/icons/EquicordIcon.tsx b/src/equicordplugins/components.dev/components/icons/EquicordIcon.tsx
deleted file mode 100644
index 4999f587b..000000000
--- a/src/equicordplugins/components.dev/components/icons/EquicordIcon.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export function EquicordIcon({ className, size, color }: { className?: string; size?: string; color?: string; }) {
- const dimension = size === "xs" ? 12 : size === "sm" ? 16 : size === "lg" ? 24 : 20;
- return (
-
-
-
-
-
- );
-}
diff --git a/src/equicordplugins/components.dev/components/index.tsx b/src/equicordplugins/components.dev/components/index.tsx
deleted file mode 100644
index e20d627d8..000000000
--- a/src/equicordplugins/components.dev/components/index.tsx
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Button } from "@components/Button";
-import { Card } from "@components/Card";
-import { Heading } from "@components/Heading";
-import { Paragraph } from "@components/Paragraph";
-import { TooltipContainer } from "@components/TooltipContainer";
-import { proxyLazy } from "@utils/lazy";
-import { filters, findByCodeLazy, findByPropsLazy, findComponentByCodeLazy, findCssClassesLazy, findLazy, mapMangledModuleLazy, waitFor, wreq } from "@webpack";
-import {
- GuildStore,
- ListScrollerAuto,
- ListScrollerThin,
- OAuth2AuthorizeModal,
- ScrollerAuto,
- ScrollerNone,
- ScrollerThin,
- SearchableSelect,
- TabBar,
- useEffect,
- useRef,
- UserStore,
- useState,
-} from "@webpack/common";
-
-import { ToastPosition, ToastType } from "../constants";
-import type {
- AccordionProps,
- AlertsType,
- AnchorProps,
- AvatarProps,
- BadgeShapesType,
- CircleBadgeProps,
- ClickableProps,
- ColorPickerWithSwatchesProps,
- ColorSwatchProps,
- ConfirmModalProps,
- ContextMenuApiType,
- CustomColorButtonProps,
- DefaultColorButtonProps,
- DiscordHeadingProps,
- DiscordTextProps,
- ErrorBoundaryProps,
- ExpressiveModalProps,
- FocusLockProps,
- GuildIconProps,
- IconBadgeProps,
- LocalErrorBoundaryProps,
- ManaButtonProps,
- ManaCheckboxGroupProps,
- ManaCheckboxProps,
- ManaListboxProps,
- ManaPopoverProps,
- ManaRichTooltipProps,
- ManaSelectProps,
- ManaTextAreaProps,
- ManaTextButtonProps,
- ManaTextInputProps,
- ManaTooltipProps,
- MenuType,
- ModalProps,
- ModalRenderFn,
- NoticeProps,
- NumberBadgeProps,
- OpenModalOptions,
- PaginatorProps,
- PremiumBadgeProps,
- ProgressBarProps,
- SearchBarProps,
- SliderProps,
- SpinnerComponent,
- TextBadgeProps,
- TimestampProps,
- ToastData,
- ToastOptions,
- ToastsModule,
- ToastTypeValue,
- UserSummaryItemProps,
-} from "../types";
-
-export * from "../constants";
-export type * from "../types";
-
-export {
- Button,
- Card,
- GuildStore,
- Heading,
- ListScrollerAuto,
- ListScrollerThin,
- OAuth2AuthorizeModal,
- Paragraph,
- ScrollerAuto,
- ScrollerNone,
- ScrollerThin,
- SearchableSelect,
- TabBar,
- TooltipContainer,
- useEffect,
- useRef,
- UserStore,
- useState,
-};
-
-export const Anchor = findComponentByCodeLazy("getDefaultLinkInterceptor", "useDefaultUnderlineStyles") as React.ComponentType;
-export const Clickable = findByCodeLazy("ignoreKeyPress", "renderNonInteractive") as React.ComponentType;
-
-export const ManaButton = findComponentByCodeLazy('"data-mana-component":"button"') as React.ComponentType;
-export const ManaTextButton = findComponentByCodeLazy('"data-mana-component":"text-button"') as React.ComponentType;
-export const ManaTextInput = findComponentByCodeLazy('"data-mana-component":"text-input"') as React.ComponentType;
-export const ManaTextArea = findComponentByCodeLazy('"data-mana-component":"text-area"') as React.ComponentType;
-export const ManaCheckbox = findComponentByCodeLazy('"data-mana-component":"checkbox"') as React.ComponentType;
-export const ManaSelect = findComponentByCodeLazy('"data-mana-component":"select"') as React.ComponentType;
-export const ManaListbox = findComponentByCodeLazy('"data-mana-component":"listbox"') as React.ComponentType;
-export const ManaCheckboxGroup = findComponentByCodeLazy('"data-mana-component":"checkbox-group"') as React.ComponentType;
-export const ManaTooltip = findComponentByCodeLazy("VoidTooltip cannot find DOM node") as React.ComponentType;
-export const ManaRichTooltip = findComponentByCodeLazy('"data-mana-component":"rich-tooltip"') as React.ComponentType;
-export const ManaPopover = findByCodeLazy("title", "body", "badge", "graphic", "actions", "textLink", "gradientColor", "popoverRef") as React.ComponentType;
-
-export const Slider = findComponentByCodeLazy("stickToMarkers", "onMarkerRender", "grabberClassName") as React.ComponentType;
-export const Avatar = findComponentByCodeLazy("statusTooltip", "statusBackdropColor", "isSpeaking") as React.ComponentType;
-export const ProgressBar = findComponentByCodeLazy("progressContainer", "labelledBy", "aria-valuenow") as React.ComponentType;
-export const Spinner = findComponentByCodeLazy("spinningCircleSimple", "pulsingEllipsis", "wanderingCubes") as unknown as SpinnerComponent;
-export const SearchBar = findComponentByCodeLazy("#{intl::SEARCH}", "clearable", "autoComplete") as React.ComponentType;
-export const Paginator = findComponentByCodeLazy("#{intl::BACK}", "#{intl::NEXT}", "renderPageWrapper") as React.ComponentType;
-export const Notice = findComponentByCodeLazy("messageType", '="text-default"', '="text-sm/medium"') as React.ComponentType;
-export const Accordion = findComponentByCodeLazy("scrollHeight)}", "onExpandedChange", "defaultExpanded") as React.ComponentType;
-export const Timestamp = findComponentByCodeLazy("#{intl::MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL}", "isVisibleOnlyOnHover") as React.ComponentType;
-export const GuildIcon = findComponentByCodeLazy("Masks.CLAN_ICON,width", "acronymClassName") as React.ComponentType;
-export const FocusLock = findComponentByCodeLazy(".containerRef,{keyboardModeEnabled:") as React.ComponentType;
-export const UserSummaryItem = findComponentByCodeLazy("popoutUserId") as React.ComponentType;
-
-export const Animations = findByPropsLazy("useSpring", "animated", "useTransition");
-
-export const SpringConfigs = proxyLazy(() => Animations.config) as {
- default: object;
- gentle: object;
- wobbly: object;
- stiff: object;
- slow: object;
- molasses: object;
-};
-
-export const useSpring = proxyLazy(() => Animations.useSpring) as (config: object) => object;
-export const useTransition = proxyLazy(() => Animations.useTransition) as (items: T[], config: object) => (callback: (style: object, item: T) => React.ReactNode) => React.ReactNode[];
-export const useTrail = proxyLazy(() => Animations.useTrail) as (count: number, config: object) => object[];
-
-const ColorPickerModule = findLazy(m => {
- const values = Object.values(m);
- return values.length === 4 &&
- values.some(v => typeof v === "function" && v.toString?.().includes('id:"color-picker"')) &&
- values.some(v => typeof v === "function" && v.toString?.().includes("isDefault:!0"));
-});
-
-function getColorPickerExport(check: (fn: Function) => boolean): React.ComponentType {
- for (const value of Object.values(ColorPickerModule)) {
- if (typeof value === "function" && check(value)) return value as React.ComponentType;
- }
- return (() => null) as React.ComponentType;
-}
-
-export const ColorPickerWithSwatches: React.ComponentType = proxyLazy(() =>
- getColorPickerExport(fn => fn.toString().includes('id:"color-picker"'))
-);
-export const ColorSwatch: React.ComponentType = proxyLazy(() =>
- getColorPickerExport(fn => fn.toString().includes("isDefault") && fn.toString().includes("isCustom") && fn.toString().includes("colorPickerSwatch"))
-);
-export const DefaultColorButton: React.ComponentType = proxyLazy(() =>
- getColorPickerExport(fn => fn.toString().includes("isDefault:!0") && fn.toString().includes("allowBlackCustomColor"))
-);
-export const CustomColorButton: React.ComponentType = proxyLazy(() =>
- getColorPickerExport(fn => fn.toString().includes("isCustom:!0") && fn.toString().includes("presets"))
-);
-
-const BadgeModule = findLazy(m => {
- const values = Object.values(m);
- return values.length < 15 &&
- values.some(v => typeof v === "function" && v.toString?.().includes("BADGE_NOTIFICATION_BACKGROUND")) &&
- values.some(v => typeof v === "object" && (v as BadgeShapesType)?.ROUND && (v as BadgeShapesType)?.ROUND_LEFT);
-});
-
-function getBadgeExport(check: (fn: Function) => boolean): React.ComponentType {
- for (const value of Object.values(BadgeModule)) {
- if (typeof value === "function" && check(value)) return value as React.ComponentType;
- }
- return (() => null) as React.ComponentType;
-}
-
-export const NumberBadge: React.ComponentType = proxyLazy(() =>
- getBadgeExport(fn => fn.toString().includes("numberBadge"))
-);
-export const TextBadge: React.ComponentType = proxyLazy(() =>
- getBadgeExport(fn => fn.toString().includes("textBadge"))
-);
-export const IconBadge: React.ComponentType = proxyLazy(() =>
- getBadgeExport(fn => fn.toString().includes("iconBadge"))
-);
-export const CircleBadge: React.ComponentType = proxyLazy(() =>
- getBadgeExport(fn =>
- fn.toString().includes("disableColor") &&
- !fn.toString().includes("iconBadge") &&
- !fn.toString().includes("textBadge") &&
- !fn.toString().includes("numberBadge") &&
- !fn.toString().includes("premiumBadge")
- )
-);
-export const PremiumBadge: React.ComponentType = proxyLazy(() =>
- getBadgeExport(fn => fn.toString().includes("premiumBadge"))
-);
-export const BadgeShapes = proxyLazy(() =>
- Object.values(BadgeModule).find(v => typeof v === "object" && (v as BadgeShapesType)?.ROUND) as BadgeShapesType ??
- { ROUND: "", ROUND_LEFT: "", ROUND_RIGHT: "", SQUARE: "" }
-);
-
-export const getBadgeWidthForValue: (count: number) => number = proxyLazy(() => {
- for (const value of Object.values(BadgeModule)) {
- if (typeof value === "function" && value.toString().includes("e<10?16:e<100")) return value as (count: number) => number;
- }
- return (count: number) => count < 10 ? 16 : count < 100 ? 22 : 30;
-});
-
-export const getBadgeCountString: (count: number) => string = proxyLazy(() => {
- for (const value of Object.values(BadgeModule)) {
- if (typeof value === "function" && value.toString().includes("e<1e3")) return value as (count: number) => string;
- }
- return (count: number) => count < 1000 ? `${count}` : `${Math.min(Math.floor(count / 1000), 9)}k+`;
-});
-
-const ToastsModule = findByPropsLazy("showToast", "popToast");
-export const Toasts: ToastsModule = proxyLazy(() => ({
- Type: ToastType,
- Position: ToastPosition,
- genId: () => Math.random().toString(36).slice(2),
- show: (toast: ToastData) => ToastsModule.showToast(toast),
- pop: () => ToastsModule.popToast(),
- create: (message: string, type: ToastTypeValue, options?: ToastOptions) => ToastsModule.createToast(message, type, options),
-}));
-
-export const showToast = (message: string, type: ToastTypeValue = ToastType.MESSAGE) =>
- ToastsModule.showToast(ToastsModule.createToast(message, type));
-
-const ModalModule = findByPropsLazy("Modal", "ConfirmModal");
-const ModalAPIModule = findByPropsLazy("openModal", "closeModal");
-
-export const Modal: React.ComponentType = proxyLazy(() => ModalModule.Modal);
-export const ConfirmModal: React.ComponentType = proxyLazy(() => ModalModule.ConfirmModal);
-export const ExpressiveModal: React.ComponentType = proxyLazy(() => ModalModule.ExpressiveModal);
-
-export const openModal = (render: ModalRenderFn, options?: OpenModalOptions): string =>
- ModalAPIModule.openModal(render, options);
-export const closeModal = (modalKey: string): void =>
- ModalAPIModule.closeModal(modalKey);
-export const closeAllModals = (): void =>
- ModalAPIModule.closeAllModals();
-export const hasModalOpen = (modalKey: string): boolean =>
- ModalAPIModule.hasModalOpen(modalKey);
-export const hasAnyModalOpen = (): boolean =>
- ModalAPIModule.hasAnyModalOpen();
-
-const DiscordTextModule = findByPropsLazy("Heading", "Text");
-
-export function DiscordHeading(props: DiscordHeadingProps) {
- return ;
-}
-
-export function DiscordText(props: DiscordTextProps) {
- return ;
-}
-
-export function Divider({ className, style, ...restProps }: React.ComponentPropsWithoutRef<"hr">) {
- return ;
-}
-
-const CodeContainerClasses = findCssClassesLazy("markup", "codeContainer");
-
-export function InlineCode({ children }: { children: React.ReactNode; }) {
- return (
-
- {children}
-
- );
-}
-
-const AlertsModule = findByPropsLazy("show", "close", "confirm");
-
-export const Alerts: AlertsType = {
- show: options => AlertsModule.show(options),
- close: () => AlertsModule.close(),
- confirm: options => AlertsModule.confirm(options),
-};
-
-const MenuComponents: Record> = {};
-
-waitFor(m => m.name === "MenuCheckboxItem", (_, id) => {
- const exports = wreq(id);
- for (const key in exports) {
- try {
- const value = exports[key];
- if (typeof value === "function" && value.name?.startsWith("Menu")) {
- MenuComponents[value.name] = value;
- }
- } catch { }
- }
-});
-
-waitFor(filters.componentByCode('path:["empty"]'), m => { MenuComponents.Menu = m; });
-waitFor(filters.componentByCode("SLIDER)", "handleSize:16"), m => { MenuComponents.MenuSliderControl = m; });
-waitFor(filters.componentByCode(".SEARCH)", ".focus()", "query:"), m => { MenuComponents.MenuSearchControl = m; });
-
-waitFor(m => m.name === "MenuCheckboxItem", (_, id) => {
- const exports = wreq(id);
- for (const key in exports) {
- try {
- const value = exports[key];
- if (typeof value !== "function") continue;
- const str = value.toString();
- if (str.length === 26 && str.endsWith("(e){return null}") && value.name === "l") {
- Object.defineProperty(value, "name", { value: "MenuSwitchItem" });
- MenuComponents.MenuSwitchItem = value;
- break;
- }
- } catch { }
- }
-});
-
-export const Menu: MenuType = proxyLazy(() => ({
- Menu: MenuComponents.Menu,
- MenuItem: MenuComponents.MenuItem,
- MenuCheckboxItem: MenuComponents.MenuCheckboxItem,
- MenuRadioItem: MenuComponents.MenuRadioItem,
- MenuSwitchItem: MenuComponents.MenuSwitchItem,
- MenuGroup: MenuComponents.MenuGroup,
- MenuSeparator: MenuComponents.MenuSeparator,
- MenuControlItem: MenuComponents.MenuControlItem,
- MenuSliderControl: MenuComponents.MenuSliderControl,
- MenuSearchControl: MenuComponents.MenuSearchControl,
-}));
-
-export const ContextMenuApi: ContextMenuApiType = mapMangledModuleLazy('type:"CONTEXT_MENU_OPEN', {
- closeContextMenu: filters.byCode("CONTEXT_MENU_CLOSE"),
- openContextMenu: filters.byCode("renderLazy:"),
- openContextMenuLazy: e => typeof e === "function" && e.toString().length < 100
-});
-
-export const ErrorBoundary = findComponentByCodeLazy("this.resetErrorBoundary", "onReset", "FallbackComponent") as React.ComponentType;
-export const LocalErrorBoundary = findComponentByCodeLazy("LocalErrorBoundary", "text-feedback-critical") as React.ComponentType;
diff --git a/src/equicordplugins/components.dev/components/tabs/AccordionTab.tsx b/src/equicordplugins/components.dev/components/tabs/AccordionTab.tsx
deleted file mode 100644
index 320f26008..000000000
--- a/src/equicordplugins/components.dev/components/tabs/AccordionTab.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Accordion, Paragraph, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const ACCORDION_PROPS: PropDef[] = [
- { name: "title", type: "string", required: true, description: "Header title text. Rendered as text-sm/medium." },
- { name: "children", type: "ReactNode", required: true, description: "Content revealed when expanded." },
- { name: "subtitle", type: "string", description: "Optional subtitle below the title. Rendered as text-xs/medium in text-subtle." },
- { name: "icon", type: "ReactNode", description: "Optional icon displayed before the title." },
- { name: "defaultExpanded", type: "boolean", default: "false", description: "Initial expanded state for uncontrolled usage." },
- { name: "isExpanded", type: "boolean", description: "Controlled expanded state. When set, the component becomes controlled." },
- { name: "onExpandedChange", type: "(expanded: boolean) => void", description: "Called when expanded state changes. Works in both controlled and uncontrolled modes." },
- { name: "onOpen", type: "() => void", description: "Called only when the accordion opens, not when it closes." },
- { name: "maxHeight", type: "number | string", description: "Maximum content height when expanded. Numbers are converted to px. Without this, height is based on scrollHeight." },
- { name: "className", type: "string", description: "Additional CSS class name on the root element." },
-];
-
-function ControlledDemo() {
- const [controlled, setControlled] = useState(false);
-
- return (
-
- This accordion's state is controlled externally.
-
- );
-}
-
-export default function AccordionTab() {
- return (
-
- This is the accordion content that is revealed when expanded.
-
- ),
- code: '\n Hidden content here. \n ',
- relevantProps: ["title", "children"]
- },
- {
- title: "With Subtitle",
- description: "A subtitle renders below the title in smaller, subtler text.",
- children: (
-
- Content with a subtitle in the header.
-
- ),
- relevantProps: ["subtitle", "icon"]
- },
- {
- title: "Default Expanded",
- description: "Starts open on mount using defaultExpanded.",
- children: (
-
- This accordion starts expanded by default.
-
- ),
- relevantProps: ["defaultExpanded"]
- },
- {
- title: "Controlled",
- description: "Use isExpanded and onExpandedChange to manage state externally.",
- children: ,
- code: '\n Controlled content. \n ',
- relevantProps: ["isExpanded", "onExpandedChange"]
- },
- {
- title: "With Max Height",
- description: "Constrains expanded content height. Overflowing content is clipped.",
- children: (
-
- Line 1
- Line 2
- Line 3
- Line 4
- Line 5
- Line 6
-
- ),
- code: ' } maxHeight={200}>\n Scrollable content area. \n',
- relevantProps: ["maxHeight"]
- },
- ]}
- props={ACCORDION_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/AlertTab.tsx b/src/equicordplugins/components.dev/components/tabs/AlertTab.tsx
deleted file mode 100644
index 089f9fb5b..000000000
--- a/src/equicordplugins/components.dev/components/tabs/AlertTab.tsx
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Alerts, Button, showToast, ToastType } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const ALERT_PROPS: PropDef[] = [
- { name: "title", type: "string", required: true, description: "Alert dialog title." },
- { name: "body", type: "ReactNode", required: true, description: "Alert body content. Can be a string or JSX." },
- { name: "confirmText", type: "string", description: "Text for the confirm button. Defaults to a localized \"Okay\" string." },
- { name: "cancelText", type: "string", description: "Text for the cancel button. Only shown when set to a non-empty string." },
- { name: "confirmVariant", type: '"primary" | "critical-primary" | "expressive"', default: '"primary"', description: "Visual variant for the confirm button." },
- { name: "onConfirm", type: "() => void", description: "Called when the confirm button is clicked." },
- { name: "onCancel", type: "() => void", description: "Called when the cancel button is clicked." },
- { name: "onCloseCallback", type: "() => void", description: "Called when the alert closes, regardless of which button was pressed." },
- { name: "contextKey", type: "string", description: "Optional context key passed to the modal system." },
-];
-
-export default function AlertTab() {
- return (
- that cleanly integrates with async flows." },
- ]}
- importPath={'import { Alerts } from "../components";'}
- sections={[
- {
- title: "Basic Alert",
- description: "Simple alert with just a title and body. Only shows a confirm button.",
- children: (
- {
- Alerts.show({
- title: "Basic Alert",
- body: "This is a basic alert dialog with just an OK button.",
- });
- }}>
- Show Basic Alert
-
- ),
- code: 'Alerts.show({ title: "Done", body: "Operation completed successfully." });',
- relevantProps: ["title", "body"]
- },
- {
- title: "Confirm Alert",
- description: "Alert with confirm and cancel buttons. Both fire callbacks on click.",
- children: (
- {
- Alerts.show({
- title: "Confirm Action",
- body: "Are you sure you want to proceed with this action?",
- confirmText: "Yes, proceed",
- cancelText: "Cancel",
- onConfirm: () => showToast("Confirmed!", ToastType.SUCCESS),
- onCancel: () => showToast("Cancelled", ToastType.MESSAGE),
- });
- }}>
- Show Confirm Alert
-
- ),
- relevantProps: ["confirmText", "cancelText", "onConfirm", "onCancel"]
- },
- {
- title: "Danger Alert",
- description: "Uses critical-primary variant for destructive actions.",
- children: (
- {
- Alerts.show({
- title: "Delete Item",
- body: "This action cannot be undone. Are you sure you want to delete this item?",
- confirmText: "Delete",
- confirmVariant: "critical-primary",
- cancelText: "Keep it",
- onConfirm: () => showToast("Deleted!", ToastType.SUCCESS),
- });
- }}>
- Show Danger Alert
-
- ),
- code: 'Alerts.show({\n title: "Delete?",\n body: "This cannot be undone.",\n confirmText: "Delete",\n confirmVariant: "critical-primary",\n cancelText: "Cancel",\n onConfirm: () => deleteItem(),\n});',
- relevantProps: ["confirmVariant"]
- },
- {
- title: "Expressive Alert",
- description: "Uses the expressive variant for premium or promotional actions.",
- children: (
- {
- Alerts.show({
- title: "Premium Feature",
- body: "This feature requires a premium subscription.",
- confirmText: "Upgrade Now",
- confirmVariant: "expressive",
- cancelText: "Maybe Later",
- onConfirm: () => showToast("Upgrading!", ToastType.SUCCESS),
- });
- }}>
- Show Expressive Alert
-
- ),
- relevantProps: ["confirmVariant"]
- },
- {
- title: "Promise-based Confirm",
- description: "Alerts.confirm() returns a Promise. Resolves true on confirm, false on cancel.",
- children: (
- {
- const result = await Alerts.confirm({
- title: "Async Confirm",
- body: "This uses Alerts.confirm() which returns a promise.",
- confirmText: "Accept",
- cancelText: "Decline",
- });
- showToast(result ? "Accepted!" : "Declined", result ? ToastType.SUCCESS : ToastType.MESSAGE);
- }}>
- Show Promise Confirm
-
- ),
- code: 'const confirmed = await Alerts.confirm({\n title: "Proceed?",\n body: "Are you sure?",\n confirmText: "Yes",\n cancelText: "No",\n});\nif (confirmed) doSomething();'
- },
- ]}
- props={ALERT_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/AnchorTab.tsx b/src/equicordplugins/components.dev/components/tabs/AnchorTab.tsx
deleted file mode 100644
index 1a5f568b9..000000000
--- a/src/equicordplugins/components.dev/components/tabs/AnchorTab.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Anchor, Paragraph } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const ANCHOR_PROPS: PropDef[] = [
- { name: "href", type: "string", description: "Link URL. External links automatically get rel=\"noreferrer noopener\" and target=\"_blank\"." },
- { name: "children", type: "ReactNode", description: "Link content." },
- { name: "onClick", type: "MouseEventHandler", description: "Click handler. If omitted and href is set, uses Discord's default link interceptor." },
- { name: "useDefaultUnderlineStyles", type: "boolean", default: "true", description: "Whether to show underline on hover." },
- { name: "title", type: "string", description: "Tooltip text shown on hover." },
- { name: "target", type: "string", description: "Link target. Auto-set to _blank for external URLs." },
- { name: "rel", type: "string", description: "Link relationship. Auto-set to \"noreferrer noopener\" for external URLs." },
- { name: "focusProps", type: "Record", internal: true, description: "Props forwarded to the focus management wrapper." },
- { name: "ref", type: "Ref", description: "Ref to the underlying anchor element." },
- { name: "className", type: "string", description: "Additional CSS class name." },
- { name: "style", type: "CSSProperties", description: "Inline styles." },
-];
-
-export default function AnchorTab() {
- return (
-
- Discord Homepage
-
- ),
- code: 'Visit Example ',
- relevantProps: ["href", "children"]
- },
- {
- title: "Without Underline",
- description: "Disable the default underline-on-hover behavior with useDefaultUnderlineStyles={false}.",
- children: (
-
- No underline on hover
-
- ),
- relevantProps: ["useDefaultUnderlineStyles"]
- },
- {
- title: "With Title Tooltip",
- description: "Hover to see the native title tooltip.",
- children: (
-
- Hover for tooltip
-
- ),
- relevantProps: ["title"]
- },
- {
- title: "Custom Styling",
- children: (
-
- Green styled link
-
- ),
- relevantProps: ["style", "className"]
- },
- {
- title: "With onClick Handler",
- description: "Custom click handler prevents default navigation.",
- children: (
- {
- e.preventDefault();
- alert("Link clicked!");
- }}
- >
- Click me (shows alert)
-
- ),
- code: ' { e.preventDefault(); doSomething(); }}>\n Click me\n ',
- relevantProps: ["onClick"]
- },
- {
- title: "Inline in Text",
- description: "Links used naturally within a paragraph.",
- children: (
-
- Check out the Terms of Service and{" "}
- Privacy Policy for more info.
-
- ),
- code: '\n Read the documentation .\n '
- },
- ]}
- props={ANCHOR_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/AnimationsTab.tsx b/src/equicordplugins/components.dev/components/tabs/AnimationsTab.tsx
deleted file mode 100644
index 05602a228..000000000
--- a/src/equicordplugins/components.dev/components/tabs/AnimationsTab.tsx
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Animations, ManaButton, Paragraph, SpringConfigs, useSpring, useState, useTrail, useTransition } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const { animated } = Animations;
-
-const TRAIL_ITEMS = ["Discord", "uses", "react-spring", "for", "animations"];
-
-const SPRING_CONFIG_PROPS: PropDef[] = [
- { name: "default", type: "{ tension: 170, friction: 26 }", description: "Standard spring. Balanced speed and bounce." },
- { name: "gentle", type: "{ tension: 120, friction: 14 }", description: "Soft, slow spring with more bounce." },
- { name: "wobbly", type: "{ tension: 180, friction: 12 }", description: "Bouncy, playful spring with high overshoot." },
- { name: "stiff", type: "{ tension: 210, friction: 20 }", description: "Quick, snappy spring with minimal bounce." },
- { name: "slow", type: "{ tension: 280, friction: 60 }", description: "High tension with heavy damping. Slow and deliberate." },
- { name: "molasses", type: "{ tension: 280, friction: 120 }", description: "Extremely slow and heavily damped. No bounce." },
-];
-
-function SpringDemo() {
- const [toggled, setToggled] = useState(false);
- const [config, setConfig] = useState("default");
-
- const spring = useSpring({
- opacity: toggled ? 1 : 0.3,
- transform: toggled ? "scale(1) rotate(0deg)" : "scale(0.8) rotate(-10deg)",
- backgroundColor: toggled ? "var(--brand-500)" : "var(--background-tertiary)",
- config: SpringConfigs[config]
- });
-
- return (
- <>
-
- {(Object.keys(SpringConfigs) as (keyof typeof SpringConfigs)[]).map(c => (
- setConfig(c)}
- />
- ))}
-
- setToggled(!toggled)}
- style={{
- ...spring,
- width: 120,
- height: 120,
- borderRadius: 12,
- cursor: "pointer",
- display: "flex",
- alignItems: "center",
- justifyContent: "center"
- }}
- >
- Click me
-
- >
- );
-}
-
-function TransitionDemo() {
- const [items, setItems] = useState([1, 2, 3]);
- const [nextId, setNextId] = useState(4);
-
- const transitions = useTransition(items, {
- from: { opacity: 0, transform: "translateX(-20px) scale(0.9)" },
- enter: { opacity: 1, transform: "translateX(0px) scale(1)" },
- leave: { opacity: 0, transform: "translateX(20px) scale(0.9)" },
- keys: item => item,
- config: SpringConfigs.gentle
- });
-
- return (
- <>
-
- {
- setItems([...items, nextId]);
- setNextId(nextId + 1);
- }} />
- setItems([])}
- disabled={items.length === 0}
- />
-
-
- {transitions((style, item) => (
-
setItems(items.filter(i => i !== item))}
- >
- Item {item}
-
- ))}
-
- >
- );
-}
-
-function TrailDemo() {
- const [show, setShow] = useState(true);
-
- const trail = useTrail(TRAIL_ITEMS.length, {
- opacity: show ? 1 : 0,
- transform: show ? "translateY(0px)" : "translateY(20px)",
- config: SpringConfigs.gentle
- }) as object[];
-
- return (
- <>
-
- setShow(!show)}
- />
-
-
- {trail.map((style, i) => (
-
- {TRAIL_ITEMS[i]}
-
- ))}
-
- >
- );
-}
-
-function AnimatedElementsDemo() {
- const [hover, setHover] = useState(false);
-
- const hoverSpring = useSpring({
- scale: hover ? 1.05 : 1,
- boxShadow: hover
- ? "0 8px 24px rgba(0,0,0,0.3)"
- : "0 2px 8px rgba(0,0,0,0.1)",
- config: SpringConfigs.wobbly
- });
-
- return (
- setHover(true)}
- onMouseLeave={() => setHover(false)}
- style={{
- ...hoverSpring,
- width: 100,
- height: 100,
- background: "var(--background-secondary)",
- borderRadius: 12,
- display: "flex",
- alignItems: "center",
- justifyContent: "center",
- cursor: "pointer"
- }}
- >
- Hover me
-
- );
-}
-
-export default function AnimationsTab() {
- return (
- ,
- code: "const spring = useSpring({ opacity: visible ? 1 : 0, config: SpringConfigs.gentle });\nreturn Content ;"
- },
- {
- title: "useTransition",
- description: "Animate items entering and leaving a list. Click items to remove them, or use the buttons to add/clear.",
- children: ,
- code: "const transitions = useTransition(items, {\n from: { opacity: 0 },\n enter: { opacity: 1 },\n leave: { opacity: 0 },\n keys: item => item.id,\n});\nreturn transitions((style, item) => {item.name} );"
- },
- {
- title: "useTrail",
- description: "Staggered animations for multiple items. Each item animates slightly after the previous one.",
- children: ,
- code: 'const trail = useTrail(items.length, {\n opacity: show ? 1 : 0,\n transform: show ? "translateY(0)" : "translateY(20px)",\n config: SpringConfigs.gentle,\n});'
- },
- {
- title: "animated Elements",
- description: "Use animated.div, animated.span, animated.svg etc. to create spring-animated HTML elements. Hover the box below.",
- children:
- },
- ]}
- props={SPRING_CONFIG_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/AvatarTab.tsx b/src/equicordplugins/components.dev/components/tabs/AvatarTab.tsx
deleted file mode 100644
index 8a721c967..000000000
--- a/src/equicordplugins/components.dev/components/tabs/AvatarTab.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Avatar, AvatarSizes, AvatarStatuses, Paragraph, UserStore } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const AVATAR_PROPS: PropDef[] = [
- { name: "src", type: "string", description: "Avatar image URL." },
- { name: "size", type: "AvatarSize", description: "Avatar size constant (SIZE_16 through SIZE_152). Controls the SVG viewBox dimensions." },
- { name: "status", type: "AvatarStatus", description: "User presence status. Renders a colored indicator dot." },
- { name: "statusColor", type: "string", description: "Override the status indicator color." },
- { name: "statusBackdropColor", type: "string", description: "Background color behind the status indicator." },
- { name: "isMobile", type: "boolean", default: "false", description: "Shows the mobile phone status indicator instead of a dot." },
- { name: "isVR", type: "boolean", default: "false", description: "Shows the VR headset status indicator." },
- { name: "isTyping", type: "boolean", default: "false", description: "Shows a typing animation in the status area." },
- { name: "isSpeaking", type: "boolean", default: "false", description: "Renders an animated speaking ring around the avatar." },
- { name: "isLatched", type: "boolean", default: "false", description: "Latched speaking state for voice activity." },
- { name: "voiceDb", type: "number", description: "Voice volume level in dB for speaking animation intensity." },
- { name: "speakingStylesConfig", type: "Record", description: "Custom styles config for the speaking ring animation." },
- { name: "statusTooltip", type: "boolean", default: "false", description: "Shows a tooltip with the status text on hover." },
- { name: "statusTooltipDelay", type: "number", description: "Delay in ms before the status tooltip appears." },
- { name: "typingIndicatorRef", type: "Ref", description: "Ref for the typing indicator element." },
- { name: "avatarContentRef", type: "Ref", description: "Ref for the avatar image foreignObject content." },
- { name: "CutoutIcon", type: "ComponentType", description: "Custom icon component rendered as a cutout overlay on the avatar." },
- { name: "avatarTooltipAsset", type: "ReactNode", description: "Custom tooltip asset displayed on the avatar." },
- { name: "avatarTooltipText", type: "string", description: "Tooltip text for the avatar overlay." },
- { name: "avatarTooltipTitle", type: "string", description: "Tooltip title for the avatar overlay." },
- { name: "avatarDecoration", type: "string", description: "URL for the avatar decoration overlay image." },
- { name: "aria-hidden", type: "boolean", default: "false", description: "Hides the avatar from screen readers." },
- { name: "aria-label", type: "string", description: "Accessibility label for the avatar." },
- { name: "imageClassName", type: "string", description: "CSS class applied to the avatar image element." },
- { name: "className", type: "string", description: "CSS class applied to the root wrapper." },
- { name: "onClick", type: "MouseEventHandler", description: "Click handler on the avatar wrapper. Makes the avatar interactive." },
- { name: "onMouseDown", type: "MouseEventHandler", description: "Mouse down handler on the avatar wrapper." },
- { name: "onKeyDown", type: "KeyboardEventHandler", description: "Key down handler on the avatar wrapper." },
- { name: "onContextMenu", type: "MouseEventHandler", description: "Context menu handler on the avatar wrapper." },
- { name: "onMouseEnter", type: "MouseEventHandler", description: "Mouse enter handler on the avatar wrapper." },
- { name: "onMouseLeave", type: "MouseEventHandler", description: "Mouse leave handler on the avatar wrapper." },
- { name: "tabIndex", type: "number", description: "Tab index for keyboard navigation on the avatar wrapper." },
- { name: "ref", type: "Ref", description: "Ref to the root SVG element." },
-];
-
-export default function AvatarTab() {
- const currentUser = UserStore.getCurrentUser();
- const avatarUrl = currentUser?.getAvatarURL?.(undefined, 128);
-
- return (
-
- {AvatarSizes.map(size => (
-
-
-
- {size.replace("SIZE_", "")}
-
-
- ))}
-
- )
- },
- {
- title: "Statuses",
- description: "All status indicator variants.",
- code: ' ',
- relevantProps: ["status", "statusColor", "statusBackdropColor"],
- children: (
-
- {AvatarStatuses.map(status => (
-
- ))}
-
- )
- },
- {
- title: "Mobile Status",
- description: "Shows the mobile phone icon instead of a status dot when isMobile is true.",
- code: ' ',
- relevantProps: ["isMobile", "isVR"],
- children: (
-
- )
- },
- {
- title: "Speaking State",
- description: "Animated ring indicator for voice activity.",
- code: ' ',
- relevantProps: ["isSpeaking", "isLatched", "voiceDb"],
- children: (
-
- )
- },
- {
- title: "Typing Indicator",
- description: "Shows a typing animation in the status area.",
- relevantProps: ["isTyping"],
- children: (
-
- )
- },
- {
- title: "Status Tooltip",
- description: "Hover to see the status text tooltip.",
- relevantProps: ["statusTooltip", "statusTooltipDelay"],
- children: (
-
- {AvatarStatuses.map(status => (
-
- ))}
-
- )
- },
- ]}
- props={AVATAR_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/BadgeTab.tsx b/src/equicordplugins/components.dev/components/tabs/BadgeTab.tsx
deleted file mode 100644
index 29aa9ce53..000000000
--- a/src/equicordplugins/components.dev/components/tabs/BadgeTab.tsx
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { BadgeShapes, CircleBadge, IconBadge, NumberBadge, PremiumBadge, TextBadge } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-import { EquicordIcon } from "../icons/EquicordIcon";
-
-const SHARED_PROPS: PropDef[] = [
- { name: "color", type: "string", default: "BADGE_NOTIFICATION_BACKGROUND", description: "Background color. Defaults to the notification red for most badges. CircleBadge defaults to INTERACTIVE_TEXT_ACTIVE instead." },
- { name: "disableColor", type: "boolean", default: "false", description: "Removes the background color entirely when true." },
- { name: "shape", type: "BadgeShapes", default: "ROUND", description: "Controls border radius. ROUND (pill), ROUND_LEFT, ROUND_RIGHT, or SQUARE." },
- { name: "className", type: "string", description: "Additional CSS class name." },
- { name: "style", type: "CSSProperties", description: "Inline styles." },
-];
-
-const ALL_PROPS: PropDef[] = [
- { name: "count", type: "number", required: true, description: "NumberBadge only. The count to display. Auto-abbreviates large values (1000+ becomes \"1k+\", capped at \"9k+\")." },
- { name: "renderBadgeCount", type: "(count: number) => string", description: "NumberBadge only. Custom formatter for the count display. Defaults to the built-in abbreviation." },
- { name: "text", type: "string", required: true, description: "TextBadge and PremiumBadge. The text content to display." },
- { name: "icon", type: "ComponentType<{ className?: string; color?: string; }>", required: true, description: "IconBadge only. Icon component to render inside the badge." },
- ...SHARED_PROPS,
-];
-
-export default function BadgeTab() {
- return (
- ",
- relevantProps: ["count", "renderBadgeCount"],
- children: (
-
-
-
-
-
-
-
- )
- },
- {
- title: "TextBadge",
- description: "Displays text content inside a badge.",
- relevantProps: ["text"],
- children: (
-
-
-
-
-
- )
- },
- {
- title: "PremiumBadge",
- description: "A TextBadge variant with an additional premium styling class applied.",
- relevantProps: ["text"],
- children: (
-
- )
- },
- {
- title: "IconBadge",
- description: "Renders an icon component inside a badge. The icon receives color=\"currentColor\".",
- code: ' ',
- relevantProps: ["icon"],
- children: (
-
-
-
-
-
- )
- },
- {
- title: "CircleBadge",
- description: "A simple circular dot indicator. Defaults to INTERACTIVE_TEXT_ACTIVE color unlike other badges.",
- children: (
-
-
-
-
-
-
- )
- },
- {
- title: "Shapes",
- description: "All four shape variants. SQUARE removes border radius entirely.",
- code: ' ',
- relevantProps: ["shape"],
- children: (
-
-
-
-
-
-
- )
- },
- {
- title: "Custom Colors",
- description: "Any CSS color value works. Use disableColor to remove the background entirely.",
- relevantProps: ["color", "disableColor"],
- children: (
-
-
-
-
-
-
-
- )
- },
- {
- title: "Custom Render",
- description: "NumberBadge accepts a custom renderBadgeCount function to format the display.",
- code: ' n > 99 ? "99+" : String(n)}\n/>',
- children: (
-
- `#${n}`} />
- `${n}%`} />
- "!"} />
-
- )
- },
- ]}
- props={ALL_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/ButtonsTab.tsx b/src/equicordplugins/components.dev/components/tabs/ButtonsTab.tsx
deleted file mode 100644
index 1cd50c2cc..000000000
--- a/src/equicordplugins/components.dev/components/tabs/ButtonsTab.tsx
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaButton, ManaButtonSizes, ManaButtonVariants, Paragraph, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const BUTTON_PROPS: PropDef[] = [
- { name: "text", type: "string", description: "Button label text." },
- { name: "variant", type: "ManaButtonVariant", default: '"primary"', description: "Visual style variant." },
- { name: "size", type: "ManaButtonSize", default: '"md"', description: "Button size. Also controls icon and text variant sizing internally." },
- { name: "disabled", type: "boolean", default: "false", description: "Disables the button. When true, all event handlers are suppressed." },
- { name: "loading", type: "boolean", default: "false", description: "Shows a loading spinner overlay and suppresses event handlers like disabled." },
- { name: "loadingStartedLabel", type: "string", description: "Accessibility label announced via live region when loading begins." },
- { name: "loadingFinishedLabel", type: "string", description: "Accessibility label announced via live region when loading ends." },
- { name: "fullWidth", type: "boolean", default: "false", description: "Expands the button to fill its container width. Can be overridden by a parent ButtonGroup context." },
- { name: "rounded", type: "boolean", default: "false", description: "Applies fully rounded pill-shaped corners." },
- { name: "icon", type: "ManaButtonIconType", description: "Icon to display. Accepts a component, or an object with type \"icon\", \"rive\", or \"sticker\"." },
- { name: "iconPosition", type: '"start" | "end"', default: '"start"', description: "Which side of the text the icon appears on." },
- { name: "iconOpticalOffsetMargin", type: "number", default: "0", description: "Pixel offset margin for optical icon alignment." },
- { name: "minWidth", type: "number | string", description: "Minimum button width. Numbers are converted to px." },
- { name: "role", type: "string", default: '"button"', description: "ARIA role attribute." },
- { name: "type", type: '"button" | "submit" | "reset"', default: '"button"', description: "HTML button type attribute." },
- { name: "rel", type: "string", description: "Relationship attribute for link-style buttons." },
- { name: "onClick", type: "(e: MouseEvent) => void", description: "Click handler. Suppressed when disabled or loading." },
- { name: "onDoubleClick", type: "(e: MouseEvent) => void", description: "Double-click handler. Suppressed when disabled or loading." },
- { name: "onMouseEnter", type: "(e: MouseEvent) => void", description: "Mouse enter handler. Suppressed when disabled or loading." },
- { name: "onMouseLeave", type: "(e: MouseEvent) => void", description: "Mouse leave handler. Suppressed when disabled or loading." },
- { name: "onMouseUp", type: "(e: MouseEvent) => void", description: "Mouse up handler. Suppressed when disabled or loading." },
- { name: "onMouseDown", type: "(e: MouseEvent) => void", description: "Mouse down handler. Suppressed when disabled or loading." },
- { name: "onKeyDown", type: "(e: KeyboardEvent) => void", description: "Keyboard handler. Suppressed when disabled or loading." },
- { name: "focusProps", type: "Record", internal: true, description: "Props forwarded to the focus management wrapper." },
- { name: "buttonRef", type: "Ref", internal: true, description: "Ref attached to the underlying button element." },
- { name: "className", type: "string", description: "Additional CSS class name." },
- { name: "style", type: "CSSProperties", description: "Inline styles applied to the button." },
-];
-
-function StatesDemo() {
- const [loading, setLoading] = useState(false);
-
- return (
-
-
- {
- setLoading(true);
- setTimeout(() => setLoading(false), 2000);
- }}
- />
-
-
-
- );
-}
-
-export default function ButtonsTab() {
- return (
-
- {ManaButtonVariants.map(variant => (
-
- ))}
-
- ),
- code: ' save()} />',
- relevantProps: ["variant"],
- },
- {
- title: "Sizes",
- description: "Each size maps to a specific text variant internally (xs to text-xs/medium, sm to text-sm/medium, md to text-md/medium) and a corresponding icon size.",
- children: (
-
- {ManaButtonSizes.map(size => (
-
- ))}
-
- ),
- code: ' ',
- relevantProps: ["size"],
- },
- {
- title: "States",
- description: "Disabled and loading both suppress all event handlers. Loading shows a spinner overlay with accessibility announcements.",
- children: ,
- code: '',
- relevantProps: ["disabled", "loading", "loadingStartedLabel", "loadingFinishedLabel", "rounded", "fullWidth"],
- },
- {
- title: "All Variants Disabled",
- description: "How each variant looks in its disabled state.",
- children: (
-
- {ManaButtonVariants.map(variant => (
-
- ))}
-
- ),
- },
- {
- title: "Size \u00d7 Variant Matrix",
- description: "Every combination of size and variant for comparison.",
- children: (
- <>
- {ManaButtonSizes.map(size => (
-
-
- Size: {size}
-
-
- {ManaButtonVariants.map(variant => (
-
- ))}
-
-
- ))}
- >
- ),
- },
- ]}
- props={BUTTON_PROPS}
- examples={[
- {
- label: "Destructive action with critical variant:",
- code: ' ',
- },
- ]}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/CalendarTab.tsx b/src/equicordplugins/components.dev/components/tabs/CalendarTab.tsx
deleted file mode 100644
index a66d4d4a0..000000000
--- a/src/equicordplugins/components.dev/components/tabs/CalendarTab.tsx
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaCalendar, ManaDatePicker } from "@equicordplugins/components.dev";
-
-import { useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const CALENDAR_PROPS: PropDef[] = [
- { name: "value", type: "CalendarDate | null", description: "The currently selected date value." },
- { name: "onChange", type: "(value: CalendarDate) => void", description: "Called when a date is selected." },
- { name: "minValue", type: "CalendarDate", description: "Minimum selectable date." },
- { name: "maxValue", type: "CalendarDate", description: "Maximum selectable date." },
- { name: "disabled", type: "boolean", default: "false", description: "Disables the entire calendar." },
- { name: "readOnly", type: "boolean", default: "false", description: "Makes the calendar read-only. Dates are visible but not selectable." },
- { name: "className", type: "string", description: "Additional CSS class on the root element." },
- { name: "aria-label", type: "string", description: "Accessibility label for the calendar." },
-];
-
-const DATEPICKER_PROPS: PropDef[] = [
- { name: "value", type: "CalendarDate | CalendarDateTime | null", description: "The currently selected date/time value." },
- { name: "onChange", type: "(value: CalendarDate | CalendarDateTime) => void", description: "Called when the value changes. Also closes the popover." },
- { name: "minValue", type: "CalendarDate", description: "Minimum selectable date." },
- { name: "maxValue", type: "CalendarDate", description: "Maximum selectable date." },
- { name: "placeholderValue", type: "CalendarDate | CalendarDateTime", description: "Placeholder date shown in the input when no value is selected." },
- { name: "granularity", type: '"day" | "hour" | "minute" | "second"', default: '"day"', description: "Time precision level. Day shows only date fields, others add time segments." },
- { name: "hourCycle", type: "12 | 24", description: "Whether to use 12-hour or 24-hour time format." },
- { name: "hideTimeZone", type: "boolean", default: "false", description: "Hides the time zone display when using time granularity." },
- { name: "label", type: "string", description: "Input field label." },
- { name: "hideLabel", type: "boolean", description: "Visually hides the label while keeping it accessible." },
- { name: "description", type: "string", description: "Help text shown below the label." },
- { name: "helperText", type: "string", description: "Additional help text shown below the input." },
- { name: "errorMessage", type: "string", description: "Error text shown below the input. Triggers error styling when non-empty." },
- { name: "successMessage", type: "string", description: "Success text shown below the input." },
- { name: "disabled", type: "boolean", description: "Disables the date picker input and calendar." },
- { name: "required", type: "boolean", default: "false", description: "Marks the field as required." },
- { name: "badge", type: "ReactNode", description: "Badge element displayed next to the label." },
- { name: "icon", type: "ReactNode", description: "Icon displayed in the field." },
- { name: "id", type: "string", description: "Custom ID for the input control." },
- { name: "layout", type: "string", description: "Field layout variant." },
- { name: "layoutConfig", type: "Record", description: "Configuration for the field layout." },
-];
-
-function CalendarDemo() {
- const [value, setValue] = useState(null);
-
- return (
-
- );
-}
-
-function DatePickerDemo() {
- const [value, setValue] = useState(null);
-
- return (
-
-
-
- );
-}
-
-function DatePickerTimeDemo() {
- const [value, setValue] = useState(null);
-
- return (
-
-
-
- );
-}
-
-function DatePickerStatesDemo() {
- const [value, setValue] = useState(null);
-
- return (
-
-
-
-
-
-
- );
-}
-
-export default function CalendarTab() {
- return (
- ',
- relevantProps: ["value", "onChange", "aria-label"],
- children:
- },
- {
- title: "Calendar (Disabled)",
- description: "All dates are visible but not interactive.",
- relevantProps: ["disabled"],
- children: (
- { }}
- disabled
- aria-label="Disabled calendar"
- />
- )
- },
- {
- title: "Calendar (Read Only)",
- description: "Dates are visible with current selection shown but cannot be changed.",
- relevantProps: ["readOnly"],
- children: (
- { }}
- readOnly
- aria-label="Read only calendar"
- />
- )
- },
- {
- title: "Date Picker",
- description: "Text input with a calendar popover. Click the calendar icon to open.",
- code: ' ',
- relevantProps: ["label", "description", "granularity"],
- children:
- },
- {
- title: "Date Picker with Time",
- description: "Using minute granularity adds hour and minute segments to the input.",
- code: ' ',
- relevantProps: ["granularity", "hourCycle"],
- children:
- },
- {
- title: "Date Picker States",
- description: "Disabled, required, error, and helper text states.",
- relevantProps: ["disabled", "required", "errorMessage", "helperText"],
- children:
- },
- ]}
- props={[
- ...CALENDAR_PROPS.map(p => ({ ...p, name: `[Calendar] ${p.name}` })),
- ...DATEPICKER_PROPS.map(p => ({ ...p, name: `[DatePicker] ${p.name}` })),
- ]}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/CardTab.tsx b/src/equicordplugins/components.dev/components/tabs/CardTab.tsx
deleted file mode 100644
index b3c55d07f..000000000
--- a/src/equicordplugins/components.dev/components/tabs/CardTab.tsx
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Card, CardVariants, Paragraph } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const CARD_PROPS: PropDef[] = [
- { name: "variant", type: '"primary" | "warning" | "danger" | "success" | "brand"', default: '"primary"', description: "Visual style variant controlling background color." },
- { name: "outline", type: "boolean", default: "false", description: "Renders with a border outline instead of filled background." },
- { name: "defaultPadding", type: "boolean", description: "Adds 1em padding to the card. Defaults to true when no className is provided, false otherwise." },
- { name: "children", type: "ReactNode", description: "Card content." },
- { name: "className", type: "string", description: "Additional CSS class. When set, defaultPadding becomes false unless explicitly overridden." },
- { name: "style", type: "CSSProperties", description: "Inline styles." },
- { name: "...restProps", type: "HTMLDivAttributes", description: "All other standard div attributes are forwarded to the root element." },
-];
-
-export default function CardTab() {
- return (
- \n Content here \n',
- relevantProps: ["variant", "children"],
- children: (
-
- {CardVariants.map(variant => (
-
-
- {variant.charAt(0).toUpperCase() + variant.slice(1)}
-
-
- {variant === "primary" ? "General purpose content container." :
- variant === "warning" ? "Cautionary or attention-needed messages." :
- variant === "danger" ? "Error states or destructive actions." :
- variant === "success" ? "Positive feedback or confirmations." :
- "Branded or highlighted content."}
-
-
- ))}
-
- )
- },
- {
- title: "Outline Mode",
- description: "Uses a border instead of a filled background.",
- code: '\n Heads up! \n ',
- relevantProps: ["outline"],
- children: (
-
- {CardVariants.map(variant => (
-
- {variant} outline
-
- ))}
-
- )
- },
- {
- title: "Padding Control",
- description: "Cards get 1em padding by default when no className is set. You can override this behavior explicitly.",
- code: '\n Keeps padding despite custom className \n ',
- relevantProps: ["defaultPadding", "className"],
- children: (
-
-
- defaultPadding=true
-
-
- defaultPadding=false (content adds own padding)
-
-
- )
- },
- {
- title: "Nested Cards",
- description: "Cards can nest for complex layouts.",
- children: (
-
- Outer Card
-
- Nested warning card
-
-
- Nested danger card
-
-
- )
- },
- {
- title: "Custom Styling",
- description: "Cards accept custom styles and all div attributes.",
- relevantProps: ["style"],
- children: (
-
- Card with custom border accent
-
- )
- },
- ]}
- props={CARD_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/CheckboxGroupTab.tsx b/src/equicordplugins/components.dev/components/tabs/CheckboxGroupTab.tsx
deleted file mode 100644
index 807c1154f..000000000
--- a/src/equicordplugins/components.dev/components/tabs/CheckboxGroupTab.tsx
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { CheckboxGroupOption, ManaCheckboxGroup, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-import { EquicordIcon } from "../icons/EquicordIcon";
-
-const BASIC_OPTIONS: CheckboxGroupOption[] = [
- { value: "option1", label: "Option 1" },
- { value: "option2", label: "Option 2" },
- { value: "option3", label: "Option 3" },
-];
-
-const OPTIONS_WITH_DESCRIPTIONS: CheckboxGroupOption[] = [
- { value: "notifications", label: "Notifications", description: "Receive push notifications" },
- { value: "sounds", label: "Sounds", description: "Play sounds for events" },
- { value: "badges", label: "Badges", description: "Show unread badges" },
-];
-
-const OPTIONS_WITH_ICONS: CheckboxGroupOption[] = [
- { value: "item1", label: "Item with icon", description: "This option has an icon", leadingIcon: EquicordIcon },
- { value: "item2", label: "Another with icon", leadingIcon: EquicordIcon },
- { value: "item3", label: "Third with icon", leadingIcon: EquicordIcon },
-];
-
-const OPTIONS_MIXED: CheckboxGroupOption[] = [
- { value: "enabled", label: "Enabled option" },
- { value: "disabled", label: "Disabled option", disabled: true },
- { value: "another", label: "Another enabled" },
-];
-
-const GROUP_PROPS: PropDef[] = [
- { name: "options", type: "CheckboxGroupOption[]", required: true, description: "Array of checkbox options to render." },
- { name: "selectedValues", type: "(string | number)[]", required: true, description: "Currently selected option values." },
- { name: "onChange", type: "(values: (string | number)[]) => void", description: "Called with the updated selection array when any checkbox is toggled." },
- { name: "disabled", type: "boolean", default: "false", description: "Disables the entire group. Individual option disabled flags still apply." },
- { name: "label", type: "string", description: "Field label displayed above the group." },
- { name: "hideLabel", type: "boolean", description: "Visually hides the label while keeping it accessible." },
- { name: "badge", type: "ReactNode", description: "Badge element displayed next to the label." },
- { name: "icon", type: "ReactNode", description: "Icon element displayed next to the label." },
- { name: "required", type: "boolean", description: "Marks the field as required." },
- { name: "description", type: "string", description: "Description text displayed below the label." },
- { name: "helperText", type: "string", description: "Helper text displayed below the group." },
- { name: "errorMessage", type: "string", description: "Error message displayed below the group." },
- { name: "successMessage", type: "string", description: "Success message displayed below the group." },
- { name: "id", type: "string", description: "Custom ID for the control element." },
- { name: "layout", type: "string", description: "Field layout variant." },
- { name: "layoutConfig", type: "Record", description: "Configuration for the field layout." },
-];
-
-const OPTION_PROPS: PropDef[] = [
- { name: "value", type: "string | number", required: true, description: "Unique identifier for this option." },
- { name: "label", type: "string", required: true, description: "Label text displayed next to the checkbox." },
- { name: "description", type: "string", description: "Description text below the label." },
- { name: "disabled", type: "boolean", description: "Disables this individual option." },
- { name: "leadingIcon", type: "ComponentType", description: "Icon component displayed before the checkbox." },
-];
-
-function BasicDemo() {
- const [selected, setSelected] = useState<(string | number)[]>(["option1"]);
- return ;
-}
-
-function DescriptionDemo() {
- const [selected, setSelected] = useState<(string | number)[]>(["notifications", "sounds"]);
- return ;
-}
-
-function IconDemo() {
- const [selected, setSelected] = useState<(string | number)[]>(["item1"]);
- return ;
-}
-
-function MixedDemo() {
- const [selected, setSelected] = useState<(string | number)[]>(["enabled"]);
- return ;
-}
-
-export default function CheckboxGroupTab() {
- return (
- ,
- code: '',
- relevantProps: ["options", "selectedValues", "onChange"],
- },
- {
- title: "With Descriptions",
- description: "Each option can have a description below its label.",
- children: ,
- },
- {
- title: "With Leading Icons",
- description: "Options can display an icon component before the checkbox.",
- children: ,
- },
- {
- title: "With Disabled Option",
- description: "Individual options can be disabled while others remain interactive.",
- children: ,
- },
- {
- title: "Entire Group Disabled",
- description: "The disabled prop on the group disables all options.",
- children: (
-
- ),
- relevantProps: ["disabled"],
- },
- ]}
- props={[
- { title: "ManaCheckboxGroup", props: GROUP_PROPS },
- { title: "CheckboxGroupOption", props: OPTION_PROPS },
- ]}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/CheckboxTab.tsx b/src/equicordplugins/components.dev/components/tabs/CheckboxTab.tsx
deleted file mode 100644
index c9312fa16..000000000
--- a/src/equicordplugins/components.dev/components/tabs/CheckboxTab.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaCheckbox, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-import { EquicordIcon } from "../icons/EquicordIcon";
-
-const CHECKBOX_PROPS: PropDef[] = [
- { name: "checked", type: "boolean", required: true, description: "Current checked state." },
- { name: "onChange", type: "(checked: boolean) => void", description: "Called when the checkbox is toggled." },
- { name: "label", type: "string", description: "Label text displayed next to the checkbox." },
- { name: "description", type: "string", description: "Description text below the label." },
- { name: "labelType", type: '"primary" | "secondary"', default: '"primary"', description: "Label text styling. Primary uses normal weight, secondary uses muted color." },
- { name: "leadingIcon", type: "ComponentType", description: "Icon component displayed before the checkbox." },
- { name: "usageVariant", type: '"single" | "indicator"', default: '"single"', internal: true, description: "Visual style. Single has full padding and spacing, indicator is compact." },
- { name: "disabled", type: "boolean", default: "false", description: "Disables the checkbox interaction." },
- { name: "displayOnly", type: "boolean", internal: true, description: "Renders the checkbox in a display-only state without interaction." },
- { name: "value", type: "string | number", description: "Value identifier used when inside a CheckboxGroup." },
- { name: "labeledBy", type: "string", internal: true, description: "ID of an external element that labels this checkbox for accessibility." },
-];
-
-function BasicDemo() {
- const [checked, setChecked] = useState(true);
- const [unchecked, setUnchecked] = useState(false);
-
- return (
-
-
-
-
- );
-}
-
-function DescriptionDemo() {
- const [checked, setChecked] = useState(true);
-
- return (
-
- );
-}
-
-function LabelTypesDemo() {
- const [primary, setPrimary] = useState(true);
- const [secondary, setSecondary] = useState(false);
-
- return (
-
-
-
-
- );
-}
-
-function IconDemo() {
- const [checked, setChecked] = useState(true);
-
- return (
-
- );
-}
-
-function UsageVariantsDemo() {
- const [single, setSingle] = useState(true);
- const [indicator, setIndicator] = useState(false);
-
- return (
-
-
-
-
- );
-}
-
-export default function CheckboxTab() {
- return (
- ,
- code: ' ',
- relevantProps: ["checked", "onChange", "label"],
- },
- {
- title: "With Description",
- description: "A description renders below the label in smaller text.",
- children: ,
- code: '',
- relevantProps: ["description"],
- },
- {
- title: "Label Types",
- description: "Primary uses normal text styling, secondary uses a muted, lighter appearance.",
- children: ,
- relevantProps: ["labelType"],
- },
- {
- title: "With Leading Icon",
- description: "An icon component displayed before the checkbox indicator.",
- children: ,
- code: '',
- relevantProps: ["leadingIcon"],
- },
- {
- title: "States",
- description: "Disabled prevents interaction. Display only renders without any interactive behavior.",
- children: (
-
-
-
-
-
- ),
- relevantProps: ["disabled", "displayOnly"],
- },
- {
- title: "Usage Variants",
- description: "Single has full padding and spacing for standalone use. Indicator is compact for inline contexts.",
- children: ,
- relevantProps: ["usageVariant"],
- },
- ]}
- props={CHECKBOX_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/ChipTab.tsx b/src/equicordplugins/components.dev/components/tabs/ChipTab.tsx
deleted file mode 100644
index 05fc15e22..000000000
--- a/src/equicordplugins/components.dev/components/tabs/ChipTab.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Chip } from "@equicordplugins/components.dev";
-
-import { Paragraph } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const CHIP_COLORS = ["blurple", "purple", "green", "orange", "yellow", "pink", "red", "gray"] as const;
-const CHIP_SHADES = ["Light", "Medium", "Dark"] as const;
-
-const CHIP_PROPS: PropDef[] = [
- { name: "text", type: "string", required: true, description: "Text displayed inside the chip." },
- { name: "variant", type: "ChipVariant", default: '"grayLight"', description: "Color variant in the format {color}{shade}. 8 colors (blurple, purple, green, orange, yellow, pink, red, gray) times 3 shades (Light, Medium, Dark) for 24 total variants." },
-];
-
-export default function ChipTab() {
- return (
-
- {CHIP_SHADES.map(shade => (
-
-
- {shade}
-
-
- {CHIP_COLORS.map(color => (
-
- ))}
-
-
- ))}
- >
- ),
- code: ' ',
- relevantProps: ["variant"],
- },
- {
- title: "Use Cases",
- description: "Common patterns for status labels and tags.",
- children: (
-
-
-
-
-
-
-
-
- ),
- },
- ]}
- props={CHIP_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/ClickableTab.tsx b/src/equicordplugins/components.dev/components/tabs/ClickableTab.tsx
deleted file mode 100644
index 7cc8e07ae..000000000
--- a/src/equicordplugins/components.dev/components/tabs/ClickableTab.tsx
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Clickable, Paragraph, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const CLICKABLE_PROPS: PropDef[] = [
- { name: "tag", type: "keyof JSX.IntrinsicElements", default: '"div"', description: "HTML element to render as." },
- { name: "onClick", type: "MouseEventHandler", description: "Click handler. When absent, renders as a non-interactive element without keyboard handling." },
- { name: "onKeyPress", type: "KeyboardEventHandler", description: "Key press handler called after internal Enter/Space handling." },
- { name: "role", type: "string", default: '"button"', description: "ARIA role attribute." },
- { name: "tabIndex", type: "number", default: "0", description: "Tab index for keyboard navigation." },
- { name: "ignoreKeyPress", type: "boolean", description: "When true, Enter and Space keys will not trigger onClick." },
- { name: "focusProps", type: "Record", internal: true, description: "Props forwarded to the focus management wrapper." },
- { name: "innerRef", type: "Ref", internal: true, description: "Ref to the underlying DOM element." },
- { name: "href", type: "string", description: "Optional href. Affects key handling behavior (Space won't preventDefault when set)." },
- { name: "className", type: "string", description: "Additional CSS class name." },
- { name: "children", type: "ReactNode", description: "Child elements." },
-];
-
-const boxStyle: React.CSSProperties = {
- padding: "8px 16px",
- backgroundColor: "var(--background-secondary)",
- borderRadius: 4,
- cursor: "pointer",
-};
-
-function BasicDemo() {
- const [count, setCount] = useState(0);
-
- return (
- <>
- Click count: {count}
- setCount(c => c + 1)} style={boxStyle}>
- Click me!
-
- >
- );
-}
-
-function TagDemo() {
- const [last, setLast] = useState("None");
-
- return (
- <>
-
- setLast("div")} style={{ ...boxStyle, backgroundColor: "var(--background-tertiary)" }}>
- tag="div"
-
- setLast("span")} style={{ ...boxStyle, backgroundColor: "var(--background-tertiary)" }}>
- tag="span"
-
- setLast("button")} style={{ ...boxStyle, backgroundColor: "var(--background-tertiary)", border: "none", color: "inherit" }}>
- tag="button"
-
-
- Last clicked: {last}
- >
- );
-}
-
-function KeyPressDemo() {
- const [last, setLast] = useState("None");
-
- return (
- <>
-
- setLast("Normal (keys work)")} style={boxStyle}>
- Normal (try Enter/Space)
-
- setLast("Keys blocked")} style={boxStyle}>
- ignoreKeyPress (keys blocked)
-
-
- Last action: {last}
- >
- );
-}
-
-export default function ClickableTab() {
- return (
- ,
- code: " doSomething()} style={myStyles}>\n Click me!\n ",
- relevantProps: ["onClick", "children"],
- },
- {
- title: "Custom Tag",
- description: "Clickable can render as any HTML element using the tag prop.",
- children: ,
- code: '\n I am a button element\n ',
- relevantProps: ["tag"],
- },
- {
- title: "Role and TabIndex",
- description: "Accessibility props for keyboard navigation. Defaults to role=\"button\" and tabIndex=0.",
- children: (
-
- { }} style={boxStyle}>
- role="button"
-
- { }} style={boxStyle}>
- role="link"
-
-
- ),
- relevantProps: ["role", "tabIndex"],
- },
- {
- title: "Ignore Key Press",
- description: "When ignoreKeyPress is true, Enter and Space will not trigger onClick. Only mouse clicks work.",
- children: ,
- relevantProps: ["ignoreKeyPress"],
- },
- {
- title: "Non-Interactive",
- description: "When no onClick is provided, renders without keyboard handling or interactive behavior.",
- children: (
-
- Non-interactive (no onClick)
-
- ),
- },
- ]}
- props={CLICKABLE_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/CodeBlockTab.tsx b/src/equicordplugins/components.dev/components/tabs/CodeBlockTab.tsx
deleted file mode 100644
index 691ca276a..000000000
--- a/src/equicordplugins/components.dev/components/tabs/CodeBlockTab.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { CodeBlock } from "@components/CodeBlock";
-
-import { InlineCode, Paragraph } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const CODEBLOCK_PROPS: PropDef[] = [
- { name: "content", type: "string", description: "The code text to render inside the block." },
- { name: "lang", type: "string", required: true, description: "Language identifier for syntax highlighting (e.g. \"tsx\", \"js\", \"css\", \"py\"). Use empty string for no highlighting." },
-];
-
-const INLINECODE_PROPS: PropDef[] = [
- { name: "children", type: "ReactNode", required: true, description: "Content to render as inline code." },
-];
-
-const JS_EXAMPLE = `function greet(name) {
- return \`Hello, \${name}!\`;
-}
-
-console.log(greet("World"));`;
-
-const TS_EXAMPLE = `interface User {
- id: string;
- name: string;
- email?: string;
-}
-
-const getUser = (id: string): User => {
- return { id, name: "John" };
-};`;
-
-const CSS_EXAMPLE = `.container {
- display: flex;
- gap: 8px;
- padding: 16px;
- background: var(--background-secondary);
- border-radius: 8px;
-}`;
-
-const PYTHON_EXAMPLE = `def fibonacci(n: int) -> list[int]:
- if n <= 0:
- return []
- sequence = [0, 1]
- while len(sequence) < n:
- sequence.append(sequence[-1] + sequence[-2])
- return sequence[:n]
-
-print(fibonacci(10))`;
-
-const JSON_EXAMPLE = `{
- "name": "equicord",
- "version": "1.0.0",
- "plugins": ["example"],
- "settings": {
- "enabled": true,
- "theme": "dark"
- }
-}`;
-
-export default function CodeBlockTab() {
- return (
-
- I really like cats so yeah
- Use console.log() to debug your code.
-
- Combine const with let and
- use === for strict equality.
-
- >
- ),
- code: "Use console.log() to debug. ",
- },
- {
- title: "JavaScript",
- children: ,
- code: ' ',
- relevantProps: ["content", "lang"],
- },
- {
- title: "TypeScript",
- children: ,
- },
- {
- title: "CSS",
- children: ,
- },
- {
- title: "Python",
- children: ,
- },
- {
- title: "JSON",
- children: ,
- },
- {
- title: "Plain Text",
- description: "Use an empty string for lang to render without syntax highlighting.",
- children: ,
- code: ' ',
- },
- ]}
- props={[
- { title: "CodeBlock", props: CODEBLOCK_PROPS },
- { title: "InlineCode", props: INLINECODE_PROPS },
- ]}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/ColorPickerTab.tsx b/src/equicordplugins/components.dev/components/tabs/ColorPickerTab.tsx
deleted file mode 100644
index 37877bb37..000000000
--- a/src/equicordplugins/components.dev/components/tabs/ColorPickerTab.tsx
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ColorPicker } from "@webpack/common";
-
-import { ColorPickerWithSwatches, ColorSwatch, DefaultColorButton, Paragraph, PresetColors, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const DEFAULT_COLOR = 0x5865F2;
-
-function intToHex(color: number): string {
- return "#" + color.toString(16).padStart(6, "0");
-}
-
-const PICKER_PROPS: PropDef[] = [
- { name: "color", type: "number", required: true, description: "Current color as an integer (e.g. 0x5865F2)." },
- { name: "onChange", type: "(color: number) => void", required: true, description: "Called with the new color integer when changed." },
- { name: "onClose", type: "() => void", description: "Called when the picker popout closes." },
- { name: "suggestedColors", type: "string[]", description: "Array of hex color strings shown as suggestions in the popout." },
- { name: "disabled", type: "boolean", description: "Disables the color picker." },
- { name: "label", type: "ReactNode", description: "Optional label displayed next to the swatch." },
- { name: "colorPickerMiddle", type: "ReactNode", internal: true, description: "Content injected in the middle of the popout." },
- { name: "colorPickerFooter", type: "ReactNode", internal: true, description: "Content injected in the footer of the popout." },
- { name: "showEyeDropper", type: "boolean", description: "Shows the eye dropper tool in the popout." },
-];
-
-const SWATCH_PROPS: PropDef[] = [
- { name: "color", type: "number", description: "Color value. Omit for a \"no color\" state." },
- { name: "isDefault", type: "boolean", description: "Renders in the larger default button style." },
- { name: "isCustom", type: "boolean", description: "Shows a dropper icon overlay." },
- { name: "isSelected", type: "boolean", description: "Shows a checkmark overlay." },
- { name: "disabled", type: "boolean", description: "Disables the swatch." },
- { name: "onClick", type: "(color) => void", description: "Click handler receiving the color or gradient object." },
- { name: "isGradient", type: "boolean", description: "Enables gradient rendering mode." },
- { name: "gradientStart", type: "number", description: "Start color for gradients." },
- { name: "gradientEnd", type: "number", description: "End color for gradients." },
- { name: "gradientDegrees", type: "number", default: "180", description: "Angle in degrees for the gradient." },
- { name: "aria-label", type: "string", description: "Accessibility label." },
- { name: "style", type: "CSSProperties", description: "Inline styles." },
-];
-
-const SWATCHES_PROPS: PropDef[] = [
- { name: "defaultColor", type: "number", required: true, description: "Default/reset color value." },
- { name: "colors", type: "number[] | GradientColor[]", required: true, description: "Array of preset color values or gradient definitions." },
- { name: "value", type: "number", required: true, description: "Currently selected color." },
- { name: "onChange", type: "(color: number) => void", required: true, description: "Called when a color is selected." },
- { name: "customColor", type: "number", description: "Current custom color for the custom button." },
- { name: "secondaryValue", type: "number", description: "Secondary color value for gradient mode." },
- { name: "disabled", type: "boolean", description: "Disables all swatches." },
- { name: "renderDefaultButton", type: "(props) => ReactNode", description: "Render prop for the default/reset button." },
- { name: "renderCustomButton", type: "(props) => ReactNode", description: "Render prop for the custom color button." },
- { name: "isGradient", type: "boolean", description: "Enables gradient mode for all swatches." },
- { name: "gradientDegrees", type: "number", description: "Gradient angle for all swatches." },
- { name: "allowBlackCustomColor", type: "boolean", description: "Allows selecting pure black (#000000)." },
- { name: "className", type: "string", description: "Additional CSS class on the root." },
- { name: "colorContainerClassName", type: "string", description: "CSS class on the swatch grid container." },
-];
-
-function BasicPickerDemo() {
- const [color, setColor] = useState(DEFAULT_COLOR);
-
- return (
- <>
- Selected: {color !== null ? intToHex(color) : DEFAULT_COLOR}
-
- >
- );
-}
-
-function EyeDropperDemo() {
- const [color, setColor] = useState(DEFAULT_COLOR);
-
- return ;
-}
-
-function SuggestedDemo() {
- const [color, setColor] = useState(0xE74C3C);
-
- return (
- <>
- Selected: {color !== null ? intToHex(color) : 0xE74C3C}
- >
- );
-}
-
-function SwatchSelectDemo() {
- const [selected, setSelected] = useState(0x2ECC71);
-
- return (
-
- {PresetColors.slice(0, 10).map(color => (
- setSelected(color)} />
- ))}
-
- );
-}
-
-function SwatchesGridDemo() {
- const [color, setColor] = useState(0x3498DB);
-
- return (
- <>
- Selected: {intToHex(color)}
- null}
- renderCustomButton={() => null}
- />
- >
- );
-}
-
-function FullPickerDemo() {
- const [color, setColor] = useState(0x9B59B6);
-
- return (
- <>
- Selected: {color !== null ? intToHex(color) : 0x9B59B6}
- }
- renderCustomButton={() => (
-
- )}
- />
- >
- );
-}
-
-export default function ColorPickerTab() {
- return (
- ,
- code: " ",
- relevantProps: ["color", "onChange"],
- },
- {
- title: "With Eye Dropper",
- description: "Includes the eye dropper tool for picking colors from screen.",
- children: ,
- relevantProps: ["showEyeDropper"],
- },
- {
- title: "With Suggested Colors",
- description: "Shows suggested color swatches inside the popout.",
- children: ,
- code: ' ',
- relevantProps: ["suggestedColors"],
- },
- {
- title: "Disabled",
- children: { }} disabled />,
- relevantProps: ["disabled"],
- },
- {
- title: "Color Swatches",
- description: "Individual swatch buttons. Click to select.",
- children: ,
- code: " setSelected(0x5865F2)} />",
- },
- {
- title: "Swatch States",
- description: "Normal, selected, default, custom, disabled, and no-color states.",
- children: (
-
- {([
- ["Normal", {}],
- ["Selected", { isSelected: true }],
- ["Default", { isDefault: true }],
- ["Custom", { isCustom: true }],
- ["Disabled", { disabled: true }],
- ] as const).map(([label, props]) => (
-
- ))}
-
-
- ),
- relevantProps: ["isSelected", "isDefault", "isCustom", "disabled"],
- },
- {
- title: "Gradient Swatches",
- description: "Gradient swatches with customizable angle.",
- children: (
-
-
-
-
-
- ),
- relevantProps: ["isGradient", "gradientStart", "gradientEnd", "gradientDegrees"],
- },
- {
- title: "Swatch Grid",
- description: "ColorPickerWithSwatches renders a grid of preset color swatches.",
- children: ,
- code: " null}\n renderCustomButton={() => null}\n/>",
- },
- {
- title: "Full Picker with Buttons",
- description: "Swatch grid with default reset button and custom color picker using render props.",
- children: ,
- relevantProps: ["renderDefaultButton", "renderCustomButton"],
- },
- ]}
- props={[
- { title: "ColorPicker", props: PICKER_PROPS },
- { title: "ColorSwatch", props: SWATCH_PROPS },
- { title: "ColorPickerWithSwatches", props: SWATCHES_PROPS },
- ]}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/ComboboxTab.tsx b/src/equicordplugins/components.dev/components/tabs/ComboboxTab.tsx
deleted file mode 100644
index 40f5f5403..000000000
--- a/src/equicordplugins/components.dev/components/tabs/ComboboxTab.tsx
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaCombobox } from "@equicordplugins/components.dev";
-
-import { Paragraph, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const COMBOBOX_PROPS: PropDef[] = [
- { name: "placeholder", type: "string", description: "Placeholder text for the search input." },
- { name: "value", type: "T | T[]", description: "Currently selected value or array of values for multi-select." },
- { name: "onChange", type: "(value: T | T[]) => void", description: "Called when the selection changes." },
- { name: "multiSelect", type: "boolean", default: "false", description: "Enable multiple selection mode." },
- { name: "autoFocus", type: "boolean", default: "false", description: "Focus the search input on mount." },
- { name: "maxVisibleItems", type: "number", default: "5", description: "Maximum items visible before scrolling." },
- { name: "itemToString", type: "(item: T) => string", description: "Converts an item to a string for display." },
- { name: "emptyStateHeader", type: "string", description: "Header text shown when no results match the query." },
- { name: "emptyStateText", type: "string", description: "Body text shown when no results match the query." },
- { name: "onQueryChange", type: "(query: string) => void", description: "Called when the search query changes. Useful for external filtering." },
- { name: "aria-label", type: "string", description: "Accessibility label for the combobox." },
- { name: "className", type: "string", description: "CSS class for the combobox container." },
- { name: "listClassName", type: "string", description: "CSS class for the dropdown list." },
- { name: "children", type: "(query: string) => ReactNode[]", required: true, description: "Render function receiving the search query. Return filterable items." },
-];
-
-const SAMPLE_ITEMS = [
- { id: "1", label: "Apple" },
- { id: "2", label: "Banana" },
- { id: "3", label: "Cherry" },
- { id: "4", label: "Date" },
- { id: "5", label: "Elderberry" },
- { id: "6", label: "Fig" },
- { id: "7", label: "Grape" },
- { id: "8", label: "Honeydew" },
-];
-
-function ComboboxItem({ item, isSelected, onClick }: { item: { id: string; label: string; }; isSelected: boolean; onClick: () => void; }) {
- return (
- (e.currentTarget.style.background = "var(--background-modifier-hover)")}
- onMouseLeave={e => (e.currentTarget.style.background = isSelected ? "var(--background-modifier-selected)" : "transparent")}
- >
- {item.label}
-
- );
-}
-
-function filterItems(query: string) {
- return SAMPLE_ITEMS.filter(item =>
- item.label.toLowerCase().includes(query.toLowerCase())
- );
-}
-
-function SingleSelectDemo() {
- const [value, setValue] = useState("");
-
- return (
-
-
- Selected: {SAMPLE_ITEMS.find(i => i.id === value)?.label ?? "None"}
-
-
setValue(v as string)}
- aria-label="Select a fruit"
- maxVisibleItems={5}
- emptyStateHeader="No results"
- emptyStateText="Try a different search term"
- >
- {query => filterItems(query).map(item => (
- setValue(item.id)}
- />
- ))}
-
-
- );
-}
-
-function MultiSelectDemo() {
- const [values, setValues] = useState([]);
-
- return (
-
-
- Selected: {values.length ? values.map(v => SAMPLE_ITEMS.find(i => i.id === v)?.label).join(", ") : "None"}
-
-
setValues(v as string[])}
- multiSelect
- aria-label="Select fruits"
- maxVisibleItems={5}
- >
- {query => filterItems(query).map(item => (
- {
- if (values.includes(item.id)) {
- setValues(values.filter(v => v !== item.id));
- } else {
- setValues([...values, item.id]);
- }
- }}
- />
- ))}
-
-
- );
-}
-
-function EmptyStateDemo() {
- return (
-
- { }}
- aria-label="Empty state demo"
- emptyStateHeader="Nothing found"
- emptyStateText="We couldn't find what you're looking for."
- >
- {() => []}
-
-
- );
-}
-
-export default function ComboboxTab() {
- return (
- ,
- code: ` setValue(v as string)}
- aria-label="Select a fruit"
- maxVisibleItems={5}
- emptyStateHeader="No results"
- emptyStateText="Try a different search term"
->
- {query => filterItems(query).map(item => (
-
- ))}
- `,
- relevantProps: ["value", "onChange", "placeholder", "maxVisibleItems"],
- },
- {
- title: "Multi Selection",
- description: "Enable multiSelect to allow choosing multiple items at once.",
- children: ,
- code: ` setValues(v as string[])}
- multiSelect
- aria-label="Select fruits"
->
- {query => filterItems(query).map(item => (
-
- ))}
- `,
- relevantProps: ["multiSelect"],
- },
- {
- title: "Empty State",
- description: "Custom header and text shown when the children function returns an empty array.",
- children: ,
- relevantProps: ["emptyStateHeader", "emptyStateText"],
- },
- ]}
- props={COMBOBOX_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/DividerTab.tsx b/src/equicordplugins/components.dev/components/tabs/DividerTab.tsx
deleted file mode 100644
index c23200a8d..000000000
--- a/src/equicordplugins/components.dev/components/tabs/DividerTab.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Divider, Paragraph } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const DIVIDER_PROPS: PropDef[] = [
- { name: "className", type: "string", description: "Custom CSS class for the divider." },
- { name: "style", type: "CSSProperties", description: "Inline styles applied to the hr element." },
- { name: "...restProps", type: "HTMLAttributes ", description: "Any other standard hr element attributes." },
-];
-
-export default function DividerTab() {
- return (
-
- Content above divider
-
- Content below divider
-
- ),
- code: " ",
- },
- {
- title: "Custom Spacing",
- description: "Control the spacing around dividers using inline styles.",
- children: (
-
-
Tight spacing (8px)
-
-
Medium spacing (16px)
-
-
Large spacing (24px)
-
-
End
-
- ),
- code: ' ',
- relevantProps: ["style"],
- },
- ]}
- props={DIVIDER_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/ErrorBoundaryTab.tsx b/src/equicordplugins/components.dev/components/tabs/ErrorBoundaryTab.tsx
deleted file mode 100644
index af58ced98..000000000
--- a/src/equicordplugins/components.dev/components/tabs/ErrorBoundaryTab.tsx
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { SimpleErrorBoundary } from "@equicordplugins/components.dev";
-
-import { Button, ErrorBoundary, LocalErrorBoundary, Paragraph, useState } from "..";
-import { DocPage, type PropDef, type PropGroup } from "../DocPage";
-
-function ThrowError(): never {
- throw new Error("This is a demo error thrown intentionally!");
-}
-
-function ErrorTrigger({ label }: { label: string; }) {
- const [shouldThrow, setShouldThrow] = useState(false);
-
- if (shouldThrow) {
- return ;
- }
-
- return (
- setShouldThrow(true)}>
- {label}
-
- );
-}
-
-function CustomFallback({ error, resetErrorBoundary }: { error: Error; resetErrorBoundary: () => void; }) {
- return (
-
-
- Custom Fallback UI
-
-
- Error: {error.message}
-
-
Reset
-
- );
-}
-
-const ERROR_BOUNDARY_PROPS: PropDef[] = [
- { name: "children", type: "ReactNode", required: true, description: "Content to wrap with error handling." },
- { name: "fallback", type: "ReactNode", description: "Static fallback content to show on error." },
- { name: "fallbackRender", type: "(props: { error, resetErrorBoundary }) => ReactNode", description: "Render function for dynamic fallback with error details and reset capability." },
- { name: "FallbackComponent", type: "ComponentType<{ error, resetErrorBoundary }>", description: "Component that receives error and reset props as fallback." },
- { name: "onError", type: "(error: Error, info: ErrorInfo) => void", description: "Callback fired when an error is caught." },
- { name: "onReset", type: "(details) => void", description: "Callback fired when the boundary is reset." },
- { name: "resetKeys", type: "any[]", description: "Array of values that trigger an automatic reset when changed." },
-];
-
-const SIMPLE_PROPS: PropDef[] = [
- { name: "children", type: "ReactNode", required: true, description: "Content to wrap with error handling." },
- { name: "fallback", type: "ReactNode", required: true, description: "Static content to display when an error occurs." },
-];
-
-const LOCAL_PROPS: PropDef[] = [
- { name: "children", type: "ReactNode", required: true, description: "Content to wrap. Shows inline error text on failure." },
-];
-
-const PROP_GROUPS: PropGroup[] = [
- { title: "ErrorBoundary", props: ERROR_BOUNDARY_PROPS },
- { title: "SimpleErrorBoundary", props: SIMPLE_PROPS },
- { title: "LocalErrorBoundary", props: LOCAL_PROPS },
-];
-
-function ErrorBoundaryDemo() {
- const [key, setKey] = useState(0);
-
- return (
-
- (
-
- )}
- onReset={() => setKey(k => k + 1)}
- >
-
-
-
- );
-}
-
-function SimpleDemo() {
- const [key, setKey] = useState(0);
-
- return (
-
-
- Something went wrong!
- setKey(k => k + 1)} style={{ marginTop: 8 }}>Reset
-
- }
- >
-
-
-
- );
-}
-
-function LocalDemo() {
- const [key, setKey] = useState(0);
-
- return (
-
-
-
-
- setKey(k => k + 1)} style={{ marginTop: 8 }}>
- Reset
-
-
- );
-}
-
-export default function ErrorBoundaryTab() {
- return (
- ,
- code: ` (
-
-
Error: {error.message}
-
Reset
-
- )}
- onError={(error, info) => console.error(error)}
- onReset={() => refetch()}
->
-
- `,
- relevantProps: ["fallbackRender", "onError", "onReset", "resetKeys"],
- },
- {
- title: "SimpleErrorBoundary",
- description: "Lightweight boundary that shows static fallback content on error.",
- children: ,
- code: `Something went wrong!
}>
-
-`,
- },
- {
- title: "LocalErrorBoundary",
- description: "Displays an inline error message for non-critical component failures. No fallback prop needed.",
- children: ,
- code: `
-
- `,
- },
- ]}
- props={PROP_GROUPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/FocusLockTab.tsx b/src/equicordplugins/components.dev/components/tabs/FocusLockTab.tsx
deleted file mode 100644
index f224c543a..000000000
--- a/src/equicordplugins/components.dev/components/tabs/FocusLockTab.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { FocusLock, ManaButton, ManaTextInput, Paragraph, useRef, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const FOCUSLOCK_PROPS: PropDef[] = [
- { name: "containerRef", type: "RefObject", required: true, description: "React ref pointing to the container element that defines the focus trap boundary." },
- { name: "keyboardModeEnabled", type: "boolean", description: "Enable keyboard-based focus trapping. When true, Tab key cycles through focusable elements inside the container." },
- { name: "children", type: "ReactNode", description: "Content rendered inside the focus trap." },
-];
-
-function FocusLockDemo() {
- const [enabled, setEnabled] = useState(false);
- const containerRef = useRef(null);
- const [inputValue, setInputValue] = useState("");
-
- return (
-
-
setEnabled(!enabled)}
- style={{ marginBottom: 16 }}
- />
-
- {enabled ? (
-
-
- Focus is trapped. Try pressing Tab to cycle through these elements:
-
-
-
-
{ }}
- placeholder="Second input"
- />
-
- { }} />
- { }} />
- setEnabled(false)} />
-
-
-
- ) : (
-
- Click "Enable Focus Lock" to activate the focus trap demo.
-
- )}
-
-
- );
-}
-
-export default function FocusLockTab() {
- return (
- ,
- code: `const containerRef = useRef(null);
-
-
-
-
- OK
- Cancel
-
-
`,
- relevantProps: ["containerRef"],
- },
- ]}
- props={FOCUSLOCK_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/GuildIconTab.tsx b/src/equicordplugins/components.dev/components/tabs/GuildIconTab.tsx
deleted file mode 100644
index b2e9283de..000000000
--- a/src/equicordplugins/components.dev/components/tabs/GuildIconTab.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { GuildIcon, GuildIconSizes, GuildStore, ManaButton, Paragraph, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const GUILDICON_PROPS: PropDef[] = [
- { name: "guildId", type: "string", required: true, description: "The guild's snowflake ID." },
- { name: "guildName", type: "string", required: true, description: "Guild name, used for the acronym fallback when no icon is available." },
- { name: "guildIcon", type: "string | null", required: true, description: "Icon hash from the guild object, or null for acronym fallback." },
- { name: "iconSize", type: "number", required: true, description: "Size in pixels. Common values: 16, 20, 24, 32, 40, 48, 56, 80, 96." },
- { name: "animate", type: "boolean", description: "Enable animated icons (animated GIF guild icons)." },
- { name: "className", type: "string", description: "CSS class for the icon container." },
- { name: "acronymClassName", type: "string", description: "CSS class for the acronym text fallback." },
-];
-
-function SizesDemo() {
- const [animate, setAnimate] = useState(true);
- const guilds = Object.values(GuildStore.getGuilds()).slice(0, 6);
- const guildWithIcon = guilds.find(g => g.icon);
-
- if (!guildWithIcon) {
- return No guilds with icons found. ;
- }
-
- return (
-
-
setAnimate(a => !a)}
- style={{ marginBottom: 12 }}
- />
-
- {GuildIconSizes.map(size => (
-
- ))}
-
-
- );
-}
-
-function AcronymDemo() {
- const guilds = Object.values(GuildStore.getGuilds()).slice(0, 6);
- const guildWithoutIcon = guilds.find(g => !g.icon);
-
- return (
-
- {[32, 48, 80].map(size => (
-
-
-
- {size}px (no icon)
-
-
- ))}
-
- );
-}
-
-function YourGuildsDemo() {
- const [animate, setAnimate] = useState(true);
- const guilds = Object.values(GuildStore.getGuilds()).slice(0, 8);
-
- return (
-
-
setAnimate(a => !a)}
- style={{ marginBottom: 12 }}
- />
-
- {guilds.map(guild => (
-
-
-
- {guild.name.slice(0, 12)}
-
-
- ))}
-
-
- );
-}
-
-export default function GuildIconTab() {
- return (
- ,
- code: ` `,
- relevantProps: ["iconSize", "animate"],
- },
- {
- title: "Acronym Fallback",
- description: "When guildIcon is null, the component renders an acronym based on the guild name.",
- children: ,
- relevantProps: ["guildName", "guildIcon"],
- },
- {
- title: "Your Guilds",
- description: "Live preview using guilds you're currently in.",
- children: ,
- },
- ]}
- props={GUILDICON_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/HeadingTab.tsx b/src/equicordplugins/components.dev/components/tabs/HeadingTab.tsx
deleted file mode 100644
index 973ceaa3f..000000000
--- a/src/equicordplugins/components.dev/components/tabs/HeadingTab.tsx
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { DiscordHeading, DiscordText, HeadingVariants, TextColors, TextVariants } from "..";
-import { DocPage, type PropDef, type PropGroup } from "../DocPage";
-
-const HEADING_PROPS: PropDef[] = [
- { name: "variant", type: "HeadingVariant", required: true, description: 'Heading size and weight, e.g. "heading-xl/bold", "heading-sm/medium".' },
- { name: "color", type: "TextColor", description: "Text color name from Discord's color system." },
- { name: "className", type: "string", description: "Custom CSS class." },
- { name: "style", type: "CSSProperties", description: "Inline styles." },
- { name: "children", type: "ReactNode", description: "Heading content." },
-];
-
-const TEXT_PROPS: PropDef[] = [
- { name: "variant", type: "TextVariant", required: true, description: 'Text size and weight, e.g. "text-md/medium", "text-sm/normal".' },
- { name: "color", type: "TextColor", description: "Text color name from Discord's color system." },
- { name: "tag", type: "string", default: '"div"', description: "HTML tag to render (div, span, p, etc.)." },
- { name: "selectable", type: "boolean", description: "Allow text selection." },
- { name: "lineClamp", type: "number", description: "Number of lines before truncation with ellipsis." },
- { name: "tabularNumbers", type: "boolean", description: "Use tabular (monospace) number spacing for aligned columns." },
- { name: "scaleFontToUserSetting", type: "boolean", description: "Scale font size based on user's accessibility settings." },
- { name: "className", type: "string", description: "Custom CSS class." },
- { name: "style", type: "CSSProperties", description: "Inline styles." },
- { name: "children", type: "ReactNode", description: "Text content." },
-];
-
-const PROP_GROUPS: PropGroup[] = [
- { title: "DiscordHeading", props: HEADING_PROPS },
- { title: "DiscordText", props: TEXT_PROPS },
-];
-
-export default function HeadingTab() {
- return (
-
- {HeadingVariants.map(variant => (
-
- {variant}
-
- ))}
-
- ),
- code: 'Title ',
- relevantProps: ["variant"],
- },
- {
- title: "Text Variants",
- description: "All text size/weight combinations from xxl to xs.",
- children: (
-
- {TextVariants.map(variant => (
-
- {variant}
-
- ))}
-
- ),
- code: 'Body text ',
- },
- {
- title: "Text Colors",
- description: "All available color values for the color prop.",
- children: (
-
- {TextColors.map(color => (
-
- {color}
-
- ))}
-
- ),
- code: 'Branded ',
- relevantProps: ["color"],
- },
- {
- title: "Line Clamp",
- description: "Truncate text after a specified number of lines.",
- children: (
-
-
- This is a long paragraph of text that will be clamped to two lines maximum.
- Any content beyond the second line will be hidden and replaced with an ellipsis.
- This demonstrates the lineClamp prop in action.
-
-
- ),
- code: '\n Long text here...\n ',
- relevantProps: ["lineClamp"],
- },
- {
- title: "Tabular Numbers",
- description: "Monospaced number spacing for aligned numeric columns.",
- children: (
-
- 1,234,567
- 89,012
- 345
-
- ),
- relevantProps: ["tabularNumbers"],
- },
- ]}
- props={PROP_GROUPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/LayerModalTab.tsx b/src/equicordplugins/components.dev/components/tabs/LayerModalTab.tsx
deleted file mode 100644
index 49455793e..000000000
--- a/src/equicordplugins/components.dev/components/tabs/LayerModalTab.tsx
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { openModal } from "@utils/modal";
-import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
-
-import { Heading, ManaButton, Paragraph, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const LayerModal = findComponentByCodeLazy('"data-mana-component":"layer-modal"') as React.ComponentType<{
- transitionState: number;
- animationVariant?: "default" | string;
- returnRef?: React.Ref;
- "aria-label"?: string;
- onClose: () => void;
- children: React.ReactNode;
-}>;
-
-const TransitionState = findByPropsLazy("ENTERING", "ENTERED", "EXITING") as {
- ENTERING: number;
- ENTERED: number;
- EXITING: number;
- EXITED: number;
- HIDDEN: number;
-};
-
-const LAYERMODAL_PROPS: PropDef[] = [
- { name: "transitionState", type: "number", required: true, description: "Animation state. Use TransitionState.ENTERED for visible." },
- { name: "onClose", type: "() => void", required: true, description: "Called when the modal should close." },
- { name: "children", type: "ReactNode", required: true, description: "Modal content." },
- { name: "animationVariant", type: '"default" | string', default: '"default"', description: "Animation style for enter/exit transitions." },
- { name: "returnRef", type: "Ref", internal: true, description: "Ref forwarded to the modal root element." },
- { name: "aria-label", type: "string", description: "Accessibility label for the modal." },
-];
-
-function ModalContentDemo({ onClose }: { onClose: () => void; }) {
- return (
-
-
-
Layer Modal
-
- This is a layer modal opened via openModal. It supports stacked/layered
- modal experiences with built-in animation handling.
-
-
-
-
- );
-}
-
-function InlineDemo() {
- const [visible, setVisible] = useState(false);
-
- return (
-
-
setVisible(!visible)}
- />
- {visible && (
-
-
setVisible(false)}
- aria-label="Inline Demo"
- >
-
-
Inline layer modal content
-
setVisible(false)} style={{ marginTop: 8 }} />
-
-
-
- )}
-
- );
-}
-
-export default function LayerModalTab() {
- return (
- openModal(props => (
-
- ))}
- />
- ),
- code: `openModal(props => (
-
-
-
-))`,
- relevantProps: ["transitionState", "onClose"],
- },
- {
- title: "Inline Preview",
- description: "Rendered inline for preview purposes. Not recommended for production use.",
- children: ,
- relevantProps: ["aria-label", "animationVariant"],
- },
- ]}
- props={LAYERMODAL_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/ListboxTab.tsx b/src/equicordplugins/components.dev/components/tabs/ListboxTab.tsx
deleted file mode 100644
index a76a5af19..000000000
--- a/src/equicordplugins/components.dev/components/tabs/ListboxTab.tsx
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ListboxItem, ManaListbox, useState } from "..";
-import { DocPage, type PropDef, type PropGroup } from "../DocPage";
-
-const LISTBOX_PROPS: PropDef[] = [
- { name: "items", type: "ListboxItem[]", required: true, description: "Array of items to display in the listbox." },
- { name: "selectedItems", type: "ListboxItem[]", description: "Currently selected items (controlled)." },
- { name: "defaultSelectedItems", type: "ListboxItem[]", description: "Initially selected items (uncontrolled)." },
- { name: "onSelectionChange", type: "(items: ListboxItem[]) => void", description: "Called when the selection changes." },
- { name: "selectionMode", type: '"single" | "multiple"', description: "Whether one or many items can be selected." },
- { name: "disabled", type: "boolean", default: "false", description: "Disable the entire listbox." },
- { name: "required", type: "boolean", description: "Mark the listbox as required for form validation." },
- { name: "loading", type: "boolean", default: "false", description: "Show a loading state." },
- { name: "maxVisibleItems", type: "number", description: "Maximum items visible before scrolling." },
- { name: "shouldFocusWrap", type: "boolean", description: "Wrap keyboard focus when reaching the end." },
- { name: "typeahead", type: "boolean", description: "Enable keyboard search by typing item labels." },
- { name: "renderListItem", type: "(item: ListboxItem) => ReactNode", description: "Custom render function for list items." },
- { name: "renderEmptyState", type: "() => ReactNode", description: "Custom render for the empty state." },
-];
-
-const ITEM_PROPS: PropDef[] = [
- { name: "id", type: "string", required: true, description: "Unique identifier for the item." },
- { name: "label", type: "string", required: true, description: "Display label for the item." },
- { name: "disabled", type: "boolean", description: "Disable this specific item." },
-];
-
-const PROP_GROUPS: PropGroup[] = [
- { title: "ManaListbox", props: LISTBOX_PROPS },
- { title: "ListboxItem", props: ITEM_PROPS },
-];
-
-const SAMPLE_ITEMS: ListboxItem[] = [
- { id: "1", label: "Apple" },
- { id: "2", label: "Banana" },
- { id: "3", label: "Cherry" },
- { id: "4", label: "Date" },
- { id: "5", label: "Elderberry" },
-];
-
-const ITEMS_WITH_DISABLED: ListboxItem[] = [
- { id: "1", label: "Available option" },
- { id: "2", label: "Disabled option", disabled: true },
- { id: "3", label: "Another available" },
- { id: "4", label: "Also disabled", disabled: true },
- { id: "5", label: "Last option" },
-];
-
-const MANY_ITEMS: ListboxItem[] = Array.from({ length: 10 }, (_, i) => ({
- id: String(i + 1),
- label: `Item ${i + 1}`,
-}));
-
-function SingleSelectDemo() {
- const [selected, setSelected] = useState([SAMPLE_ITEMS[0]]);
- return (
-
- );
-}
-
-function MultiSelectDemo() {
- const [selected, setSelected] = useState([SAMPLE_ITEMS[0], SAMPLE_ITEMS[2]]);
- return (
-
- );
-}
-
-function DisabledItemsDemo() {
- const [selected, setSelected] = useState([]);
- return (
-
- );
-}
-
-function MaxVisibleDemo() {
- const [selected, setSelected] = useState([]);
- return (
-
- );
-}
-
-export default function ListboxTab() {
- return (
- ,
- code: ` `,
- relevantProps: ["selectionMode", "selectedItems", "onSelectionChange"],
- },
- {
- title: "Multiple Selection",
- description: "Multiple items can be selected simultaneously.",
- children: ,
- code: ` `,
- },
- {
- title: "Disabled Items",
- description: "Individual items can be disabled while the rest remain interactive.",
- children: ,
- },
- {
- title: "Max Visible Items",
- description: "Limits visible items to 5 with scrolling for the rest.",
- children: ,
- relevantProps: ["maxVisibleItems"],
- },
- {
- title: "Disabled State",
- description: "The entire listbox is non-interactive when disabled.",
- children: (
-
- ),
- relevantProps: ["disabled"],
- },
- {
- title: "Loading State",
- description: "Shows a loading indicator while data is being fetched.",
- children: ,
- relevantProps: ["loading"],
- },
- {
- title: "Empty State",
- description: "Default empty appearance when no items are provided.",
- children: ,
- },
- ]}
- props={PROP_GROUPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/MenuTab.tsx b/src/equicordplugins/components.dev/components/tabs/MenuTab.tsx
deleted file mode 100644
index 1e2ec6774..000000000
--- a/src/equicordplugins/components.dev/components/tabs/MenuTab.tsx
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Button, ContextMenuApi, Menu, useState } from "..";
-import { DocPage, type PropDef, type PropGroup } from "../DocPage";
-
-const MENU_PROPS: PropDef[] = [
- { name: "navId", type: "string", required: true, description: "Unique navigation ID for the menu." },
- { name: "onClose", type: "() => void", required: true, description: "Called when the menu should close." },
- { name: "children", type: "ReactNode", required: true, description: "Menu items, groups, and separators." },
-];
-
-const MENUITEM_PROPS: PropDef[] = [
- { name: "id", type: "string", required: true, description: "Unique item identifier." },
- { name: "label", type: "ReactNode | ((props) => ReactNode)", required: true, description: "Display text for the item." },
- { name: "action", type: "(e: MouseEvent) => void", description: "Called when the item is clicked." },
- { name: "icon", type: "ComponentType", description: "Icon component displayed after the label." },
- { name: "iconLeft", type: "ComponentType", description: "Icon component displayed before the label." },
- { name: "iconProps", type: "MenuItemIconProps", description: "Props passed to the icon component." },
- { name: "leadingAccessory", type: "ReactNode", description: "Custom leading accessory element." },
- { name: "trailingIndicator", type: "ReactNode", description: "Trailing indicator element." },
- { name: "hint", type: "ReactNode | ((props) => ReactNode)", description: "Keyboard shortcut hint displayed on the right." },
- { name: "shortcut", type: "ReactNode", description: "Keyboard shortcut display." },
- { name: "subtext", type: "ReactNode", description: "Secondary text below the label." },
- { name: "subtextLineClamp", type: "number", description: "Max lines for subtext before truncation." },
- { name: "color", type: '"default" | "brand" | "danger" | "success" | "premium" | "premium-gradient"', description: "Item color variant." },
- { name: "loading", type: "boolean", description: "Show loading state." },
- { name: "badge", type: "ReactNode", description: "Badge element displayed alongside the label." },
- { name: "disabled", type: "boolean", description: "Disable interaction." },
- { name: "onClose", type: "() => void", description: "Called when the menu should close after this item's action." },
- { name: "onFocus", type: "() => void", description: "Called when the item receives focus." },
- { name: "dontCloseOnAction", type: "boolean", description: "Prevent menu from closing when this item is clicked." },
- { name: "dontCloseOnActionIfHoldingShiftKey", type: "boolean", description: "Prevent close on click if shift key is held." },
- { name: "className", type: "string", description: "Custom CSS class name." },
- { name: "focusedClassName", type: "string", description: "CSS class applied when focused." },
- { name: "children", type: "ReactNode", description: "Nested MenuItem elements create a submenu." },
-];
-
-const CHECKBOX_PROPS: PropDef[] = [
- { name: "id", type: "string", required: true, description: "Unique item identifier." },
- { name: "label", type: "ReactNode | ((props) => ReactNode)", required: true, description: "Display text." },
- { name: "checked", type: "boolean", required: true, description: "Current checked state." },
- { name: "color", type: "MenuItemColor", default: '"default"', description: "Item color variant." },
- { name: "action", type: "(e: MouseEvent) => void", description: "Called when toggled." },
- { name: "disabled", type: "boolean", description: "Disable interaction." },
- { name: "subtext", type: "ReactNode", description: "Secondary text below the label." },
- { name: "subtextLineClamp", type: "number", description: "Max lines for subtext before truncation." },
- { name: "leftIcon", type: "ComponentType", description: "Icon component displayed on the left." },
- { name: "leadingAccessory", type: "ReactNode", description: "Custom leading accessory element." },
- { name: "className", type: "string", description: "Custom CSS class name." },
- { name: "focusedClassName", type: "string", description: "CSS class applied when focused." },
-];
-
-const RADIO_PROPS: PropDef[] = [
- { name: "id", type: "string", required: true, description: "Unique item identifier." },
- { name: "label", type: "ReactNode | ((props) => ReactNode)", required: true, description: "Display text." },
- { name: "group", type: "string", required: true, description: "Radio group name for mutual exclusion." },
- { name: "checked", type: "boolean", required: true, description: "Whether this option is selected." },
- { name: "color", type: "MenuItemColor", default: '"default"', description: "Item color variant." },
- { name: "action", type: "(e: MouseEvent) => void", description: "Called when selected." },
- { name: "disabled", type: "boolean", description: "Disable interaction." },
- { name: "subtext", type: "ReactNode", description: "Secondary text below the label." },
- { name: "subtextLineClamp", type: "number", description: "Max lines for subtext before truncation." },
- { name: "leftIcon", type: "ComponentType", description: "Icon component displayed on the left." },
- { name: "leadingAccessory", type: "ReactNode", description: "Custom leading accessory element." },
-];
-
-const SLIDER_PROPS: PropDef[] = [
- { name: "minValue", type: "number", required: true, description: "Minimum slider value." },
- { name: "maxValue", type: "number", required: true, description: "Maximum slider value." },
- { name: "value", type: "number", required: true, description: "Current slider value." },
- { name: "onChange", type: "(value: number) => void", required: true, description: "Called when the value changes." },
- { name: "renderValue", type: "(value: number) => string", description: "Format the value label display." },
-];
-
-const SWITCH_PROPS: PropDef[] = [
- { name: "id", type: "string", required: true, description: "Unique item identifier." },
- { name: "label", type: "ReactNode", description: "Display text." },
- { name: "checked", type: "boolean", required: true, description: "Current switch state." },
- { name: "action", type: "(e: MouseEvent) => void", required: true, description: "Called when toggled." },
- { name: "color", type: "MenuItemColor", default: '"default"', description: "Item color variant." },
- { name: "disabled", type: "boolean", description: "Disable interaction." },
- { name: "subtext", type: "ReactNode", description: "Secondary text below the label." },
- { name: "subtextLineClamp", type: "number", description: "Max lines for subtext before truncation." },
- { name: "className", type: "string", description: "Custom CSS class name." },
-];
-
-const PROP_GROUPS: PropGroup[] = [
- { title: "Menu.Menu", props: MENU_PROPS },
- { title: "Menu.MenuItem", props: MENUITEM_PROPS },
- { title: "Menu.MenuCheckboxItem", props: CHECKBOX_PROPS },
- { title: "Menu.MenuRadioItem", props: RADIO_PROPS },
- { title: "Menu.MenuSwitchItem", props: SWITCH_PROPS },
- { title: "Menu.MenuSliderControl", props: SLIDER_PROPS },
-];
-
-function DemoMenu({ onClose }: { onClose: () => void; }) {
- const [checkboxValue, setCheckboxValue] = useState(false);
- const [switchValue, setSwitchValue] = useState(true);
- const [radioValue, setRadioValue] = useState("option1");
- const [sliderValue, setSliderValue] = useState(50);
-
- return (
-
- { }} />
- (
-
-
-
- )}
- action={() => { }}
- />
- { }} />
- { }} />
-
-
-
-
-
- { }} />
- { }} />
- { }} />
- { }} />
- { }} />
- { }} />
-
-
-
-
- setCheckboxValue(v => !v)}
- />
- setSwitchValue(v => !v)}
- />
-
-
-
-
- setRadioValue("option1")} />
- setRadioValue("option2")} />
- setRadioValue("option3")} />
-
-
-
-
-
- );
-}
-
-export default function MenuTab() {
- const openMenu = (e: React.MouseEvent) => {
- ContextMenuApi.openContextMenu(e, () => (
-
- ));
- };
-
- return (
-
- Open Menu (Click)
- Open Menu (Right-Click)
-
- ),
- code: `const openMenu = (e: React.MouseEvent) => {
- ContextMenuApi.openContextMenu(e, () => (
-
- { }} />
-
- setOn(!on)} />
-
- ));
-};`,
- },
- {
- title: "MenuItem Colors",
- description: "Items support color variants: default, brand, danger, success, premium, and premium-gradient. These are visible in the full demo above.",
- children: (
-
- Open Menu to See Colors
-
- ),
- relevantProps: ["color"],
- },
- ]}
- props={PROP_GROUPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/ModalTab.tsx b/src/equicordplugins/components.dev/components/tabs/ModalTab.tsx
deleted file mode 100644
index e37884d9c..000000000
--- a/src/equicordplugins/components.dev/components/tabs/ModalTab.tsx
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import {
- closeAllModals,
- ConfirmModal,
- ExpressiveModal,
- ManaButton,
- ManaTextInput,
- Modal,
- openModal,
- Paragraph,
- showToast,
- ToastType,
- useState,
-} from "..";
-import { DocPage, type PropDef, type PropGroup } from "../DocPage";
-
-const MODAL_PROPS: PropDef[] = [
- { name: "title", type: "string", required: true, description: "Modal title displayed in the header." },
- { name: "onClose", type: "() => void", required: true, description: "Called when the modal should close." },
- { name: "subtitle", type: "string", description: "Subtitle text below the title." },
- { name: "size", type: '"sm" | "md"', description: "Modal width size." },
- { name: "transitionState", type: "number", description: "Animation state from openModal render props." },
- { name: "animationVariant", type: '"default" | "fade" | "slide-up"', default: '"default"', description: "Transition animation style." },
- { name: "paddingSize", type: '"sm" | "lg"', default: '"sm"', description: "Internal padding size." },
- { name: "fullScreenOnMobile", type: "boolean", default: "true", description: "Whether to go full screen on mobile." },
- { name: "maxHeight", type: '"default" | "full"', default: '"default"', description: "Maximum height constraint." },
- { name: "dismissable", type: "boolean", default: "true", description: "Whether the modal can be dismissed by clicking outside." },
- { name: "children", type: "ReactNode", description: "Modal body content." },
- { name: "actions", type: "ModalAction[]", description: "Array of action buttons in the footer." },
- { name: "actionBarInput", type: "ReactNode", description: "Input element in the action bar area." },
- { name: "actionBarInputLayout", type: '"default" | "full-width"', default: '"default"', description: "Layout of the action bar input." },
- { name: "notice", type: '{ message: string; type: "info" | "warn" | "critical" | "positive" }', description: "Notice banner shown at the top of the modal." },
- { name: "input", type: "ReactNode", description: "Input controls rendered in the header area." },
- { name: "preview", type: "ReactNode", description: "Preview content above the modal body." },
- { name: "onScroll", type: "(e: UIEvent) => void", description: "Scroll event handler for the modal body." },
- { name: "scrollerRef", type: "Ref", description: "Ref to the scroller element." },
- { name: "role", type: "string", default: '"dialog"', description: "ARIA role for the modal." },
- { name: "aria-label", type: "string", description: "ARIA label for the modal." },
- { name: "className", type: "string", description: "Custom CSS class." },
-];
-
-const CONFIRM_PROPS: PropDef[] = [
- { name: "title", type: "string", required: true, description: "Modal title." },
- { name: "confirmText", type: "string", required: true, description: "Text for the confirm button." },
- { name: "onClose", type: "() => void", required: true, description: "Called when the modal should close." },
- { name: "cancelText", type: "string", description: "Text for the cancel button." },
- { name: "variant", type: '"critical" | "primary" | "secondary"', description: "Visual style of the confirm button." },
- { name: "onConfirm", type: "() => void | Promise", description: "Called when the confirm button is clicked. Can be async." },
- { name: "onCancel", type: "() => void", description: "Called when the cancel button is clicked." },
- { name: "checkboxProps", type: "{ label, checked, onChange }", description: "Optional checkbox in the modal body." },
- { name: "children", type: "ReactNode", description: "Body content." },
-];
-
-const EXPRESSIVE_PROPS: PropDef[] = [
- { name: "title", type: "string", required: true, description: "Modal title." },
- { name: "onClose", type: "() => void", required: true, description: "Called when the modal should close." },
- { name: "subtitle", type: "string", description: "Subtitle text below the title." },
- { name: "size", type: '"sm" | "md"', default: '"md"', description: "Modal width size." },
- { name: "transitionState", type: "number", description: "Animation state." },
- { name: "gradientColor", type: '"purple" | "blue" | "pink" | "green"', default: '"purple"', description: "Background gradient color." },
- { name: "graphic", type: '{ type: "image"; src: string; aspectRatio?: string }', description: "Image graphic shown above the content." },
- { name: "badge", type: "ReactNode", description: "Badge element shown near the title." },
- { name: "actionBarInput", type: "ReactNode", description: "Input element in the action bar area." },
- { name: "actions", type: "ModalAction[]", description: "Action buttons." },
- { name: "children", type: "ReactNode", description: "Modal body content." },
-];
-
-const ACTION_PROPS: PropDef[] = [
- { name: "text", type: "string", required: true, description: "Button text." },
- { name: "variant", type: '"primary" | "secondary" | "critical-primary" | "critical-secondary"', required: true, description: "Button style variant." },
- { name: "onClick", type: "() => void", required: true, description: "Click handler." },
- { name: "disabled", type: "boolean", description: "Disable the button." },
- { name: "loading", type: "boolean", description: "Show loading spinner." },
-];
-
-const PROP_GROUPS: PropGroup[] = [
- { title: "Modal", props: MODAL_PROPS },
- { title: "ConfirmModal", props: CONFIRM_PROPS },
- { title: "ExpressiveModal", props: EXPRESSIVE_PROPS },
- { title: "ModalAction", props: ACTION_PROPS },
-];
-
-function openBasicModal() {
- openModal(props => (
- { showToast("Confirmed!", ToastType.SUCCESS); props.onClose(); } },
- ]}
- >
- This is the modal body content. Any React components can go here.
-
- ));
-}
-
-function openNoticeModal() {
- openModal(props => (
-
- Modals can display notices at the top for important information.
-
- ));
-}
-
-function ModalWithInputContent({ onClose, transitionState }: { onClose: () => void; transitionState: number; }) {
- const [inputValue, setInputValue] = useState("");
- return (
- { showToast(`Submitted: ${inputValue}`, ToastType.SUCCESS); onClose(); } },
- ]}
- >
-
-
- );
-}
-
-function openConfirmCritical() {
- openModal(props => (
- showToast("Item deleted!", ToastType.SUCCESS)}
- onCancel={() => showToast("Cancelled", ToastType.MESSAGE)}
- onClose={props.onClose}
- >
- This action cannot be undone. The item will be permanently deleted.
-
- ));
-}
-
-function openConfirmPrimary() {
- openModal(props => (
- showToast("Changes saved!", ToastType.SUCCESS)}
- onClose={props.onClose}
- >
- Do you want to save your changes?
-
- ));
-}
-
-function openExpressive() {
- openModal(props => (
-
- ));
-}
-
-export default function ModalTab() {
- return (
- ,
- code: `openModal(props => (
-
- Modal content here
-
-))`,
- relevantProps: ["title", "subtitle", "actions"],
- },
- {
- title: "Modal with Notice",
- description: "A notice banner appears at the top of the modal for important info.",
- children: ,
- relevantProps: ["notice"],
- },
- {
- title: "Modal with Input",
- description: "Modal with form controls in the body area.",
- children: (
- openModal(props => (
-
- ))}
- />
- ),
- },
- {
- title: "ConfirmModal (Critical)",
- description: "Confirmation dialog for destructive actions with danger styling.",
- children: ,
- code: `openModal(props => (
- deleteItem()}
- onClose={props.onClose}
- transitionState={props.transitionState}
- >
- This cannot be undone.
-
-))`,
- relevantProps: ["confirmText", "variant", "onConfirm"],
- },
- {
- title: "ConfirmModal (Primary)",
- description: "Confirmation dialog for non-destructive actions.",
- children: ,
- },
- {
- title: "ExpressiveModal",
- description: "Visual modal for onboarding or promotional experiences.",
- children: ,
- relevantProps: ["subtitle", "gradientColor", "graphic", "badge"],
- },
- {
- title: "Close All Modals",
- description: "Utility to close all open modals at once.",
- children: ,
- code: "closeAllModals();",
- },
- ]}
- props={PROP_GROUPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/NoticeTab.tsx b/src/equicordplugins/components.dev/components/tabs/NoticeTab.tsx
deleted file mode 100644
index dacc6e57e..000000000
--- a/src/equicordplugins/components.dev/components/tabs/NoticeTab.tsx
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Button, Notice, NoticeTypes, Paragraph } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const NOTICE_PROPS: PropDef[] = [
- { name: "children", type: "ReactNode", required: true, description: "Notice content text." },
- { name: "messageType", type: '"info" | "warn" | "danger" | "positive" | "preview"', required: true, description: "Visual severity level of the notice." },
- { name: "action", type: "ReactNode", description: "Action element (typically a button) displayed on the right side." },
- { name: "hidden", type: "boolean", default: "false", description: "Hides the notice without removing it from the DOM." },
- { name: "textColor", type: "string", description: "Custom text color override." },
- { name: "textVariant", type: "string", default: '"text-sm/medium"', description: 'Text size/weight variant, e.g. "text-md/normal".' },
- { name: "icon", type: "ComponentType<{ className?, color? }>", description: "Custom icon component to replace the default." },
- { name: "className", type: "string", description: "Additional CSS class." },
-];
-
-export default function NoticeTab() {
- return (
-
- {NoticeTypes.map(type => (
-
- This is a {type} notice message.
-
- ))}
-
- ),
- code: 'Informational message. ',
- relevantProps: ["messageType"],
- },
- {
- title: "With Action Button",
- description: "Notices can include action buttons for user interaction.",
- children: (
-
- Action}
- >
- Notice with an action button.
-
- Fix Now}
- >
- Warning that requires attention.
-
-
- ),
- code: `Fix Now}
->
- Warning that requires attention.
- `,
- relevantProps: ["action"],
- },
- {
- title: "Hidden State",
- description: "The hidden prop controls visibility without removing from the DOM.",
- children: (
-
-
-
hidden=false:
-
- This notice is visible.
-
-
-
-
hidden=true (invisible below):
-
- This notice is hidden.
-
-
-
- ),
- relevantProps: ["hidden"],
- },
- {
- title: "Text Variants",
- description: "Customize text sizing with the textVariant prop.",
- children: (
-
-
-
Default (text-sm/medium):
-
Default text variant.
-
-
-
text-md/normal:
-
Larger text variant.
-
-
- ),
- relevantProps: ["textVariant"],
- },
- ]}
- props={NOTICE_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/PaginatorTab.tsx b/src/equicordplugins/components.dev/components/tabs/PaginatorTab.tsx
deleted file mode 100644
index 2b994f6d2..000000000
--- a/src/equicordplugins/components.dev/components/tabs/PaginatorTab.tsx
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Paginator, Paragraph, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const PAGINATOR_PROPS: PropDef[] = [
- { name: "currentPage", type: "number", required: true, description: "Currently active page (1-based)." },
- { name: "totalCount", type: "number", required: true, description: "Total number of items across all pages." },
- { name: "pageSize", type: "number", required: true, description: "Number of items per page." },
- { name: "onPageChange", type: "(page: number) => void", description: "Called when the user navigates to a different page." },
- { name: "maxVisiblePages", type: "number", description: "Maximum number of page buttons visible at once." },
- { name: "hideMaxPage", type: "boolean", default: "false", description: "Hide the last page number." },
- { name: "disablePaginationGap", type: "boolean", default: "false", description: "Remove the ellipsis gaps between page numbers." },
- { name: "className", type: "string", description: "Custom CSS class." },
- { name: "renderPageWrapper", type: "(props, defaultRender) => ReactNode", description: "Custom render wrapper for each page button." },
-];
-
-function BasicDemo() {
- const [page, setPage] = useState(1);
- return (
-
- );
-}
-
-function MaxVisibleDemo() {
- const [page3, setPage3] = useState(1);
- const [page7, setPage7] = useState(1);
-
- return (
-
- );
-}
-
-function OptionsDemo() {
- const [page, setPage] = useState(1);
-
- return (
-
-
-
-
disablePaginationGap:
-
-
-
- );
-}
-
-export default function PaginatorTab() {
- return (
- ,
- code: ` `,
- relevantProps: ["currentPage", "totalCount", "pageSize", "onPageChange"],
- },
- {
- title: "Max Visible Pages",
- description: "Control how many page numbers are visible before ellipsis appears.",
- children: ,
- relevantProps: ["maxVisiblePages"],
- },
- {
- title: "Options",
- description: "Hide the last page number or remove ellipsis gaps entirely.",
- children: ,
- relevantProps: ["hideMaxPage", "disablePaginationGap"],
- },
- ]}
- props={PAGINATOR_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/PopoverTab.tsx b/src/equicordplugins/components.dev/components/tabs/PopoverTab.tsx
deleted file mode 100644
index a27d78ec1..000000000
--- a/src/equicordplugins/components.dev/components/tabs/PopoverTab.tsx
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaButton, ManaPopover, PopoverAction, useRef, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const POPOVER_PROPS: PropDef[] = [
- { name: "targetElementRef", type: "RefObject", required: true, description: "Ref to the element the popover is anchored to." },
- { name: "shouldShow", type: "boolean", required: true, description: "Controls popover visibility." },
- { name: "onRequestClose", type: "(reason: string) => void", description: "Called when the popover wants to close (click outside, escape, etc.)." },
- { name: "title", type: "string", description: "Popover title text." },
- { name: "body", type: "string", description: "Popover body text." },
- { name: "size", type: '"sm" | "md" | "lg"', description: "Popover width size." },
- { name: "position", type: '"top" | "bottom" | "left" | "right"', description: "Position relative to the target element." },
- { name: "actions", type: "PopoverAction[]", description: "Action buttons rendered in the popover footer." },
- { name: "textLink", type: "{ text: string; onClick?: () => void }", description: "Text link displayed below the body." },
- { name: "graphic", type: "{ src: string; aspectRatio?: string }", description: "Image graphic shown in the popover." },
- { name: "badge", type: "ReactNode", description: "Badge element displayed near the title." },
- { name: "gradientColor", type: "string", description: "Background gradient color." },
- { name: "scrollBehavior", type: "string", description: "Scroll behavior for popover content." },
- { name: "hasVideo", type: "boolean", description: "Whether the popover contains video content." },
- { name: "popoverRef", type: "Ref", description: "Ref forwarded to the popover container." },
- { name: "caretConfig", type: '{ align?: "start" | "center" | "end" }', description: "Configuration for the caret arrow." },
- { name: "alignmentStrategy", type: '"edge" | "trigger-center"', description: "How the popover aligns to the target element." },
- { name: "align", type: '"left" | "center" | "right"', description: 'Alignment when alignmentStrategy is "edge".' },
-];
-
-function PopoverDemo({ label, title, body, size, actions, position }: {
- label: string;
- title: string;
- body: string;
- size?: "sm" | "md" | "lg";
- actions?: PopoverAction[];
- position?: "top" | "bottom" | "left" | "right";
-}) {
- const wrapperRef = useRef(null);
- const [show, setShow] = useState(false);
-
- return (
- <>
-
- setShow(!show)} />
-
- setShow(false)}
- title={title}
- body={body}
- size={size}
- actions={actions}
- position={position}
- />
- >
- );
-}
-
-export default function PopoverTab() {
- return (
-
- ),
- code: `const ref = useRef(null);
-const [show, setShow] = useState(false);
-
-
- setShow(!show)}>Click me
-
- setShow(false)}
- title="Popover Title"
- body="Body text here."
-/>`,
- relevantProps: ["targetElementRef", "shouldShow", "onRequestClose", "title", "body"],
- },
- {
- title: "Sizes",
- description: "Three size variants: sm, md, and lg.",
- children: (
-
- ),
- relevantProps: ["size"],
- },
- {
- title: "Positions",
- description: "Popover can be positioned on any side of the target element.",
- children: (
-
- ),
- relevantProps: ["position"],
- },
- {
- title: "With Actions",
- description: "Popover with action buttons in the footer.",
- children: (
-
- ),
- relevantProps: ["actions"],
- },
- ]}
- props={POPOVER_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/ProgressBarTab.tsx b/src/equicordplugins/components.dev/components/tabs/ProgressBarTab.tsx
deleted file mode 100644
index bc288f701..000000000
--- a/src/equicordplugins/components.dev/components/tabs/ProgressBarTab.tsx
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Paragraph, ProgressBar, useEffect, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const PROGRESSBAR_PROPS: PropDef[] = [
- { name: "progress", type: "number", required: true, description: "Current progress value." },
- { name: "minimum", type: "number", default: "0", description: "Minimum range value." },
- { name: "maximum", type: "number", default: "100", description: "Maximum range value." },
- { name: "variant", type: '"blue" | "orange" | "unset"', default: '"blue"', description: 'Color variant. Use "unset" with override for custom colors.' },
- { name: "override", type: "{ default?: { background, gradientStart, gradientEnd } }", description: 'Custom colors when variant is "unset".' },
- { name: "weight", type: '"light" | "medium"', default: '"light"', description: "Visual weight of the progress bar." },
- { name: "glowing", type: "boolean", default: "true", description: "Whether the progress bar has a glow effect." },
- { name: "labelledBy", type: "string", internal: true, description: "ID of the labelling element for accessibility." },
-];
-
-function AnimatedDemo() {
- const [progress, setProgress] = useState(0);
-
- useEffect(() => {
- const interval = setInterval(() => {
- setProgress(prev => (prev >= 100 ? 0 : prev + 5));
- }, 200);
- return () => clearInterval(interval);
- }, []);
-
- return (
-
-
Progress: {progress}%
-
-
- );
-}
-
-export default function ProgressBarTab() {
- return (
-
-
-
-
- ),
- code: ' ',
- relevantProps: ["variant"],
- },
- {
- title: "Progress Values",
- description: "Various progress levels from 0% to 100%.",
- children: (
-
- {[0, 25, 50, 75, 100].map(v => (
-
- ))}
-
- ),
- relevantProps: ["progress"],
- },
- {
- title: "Animated",
- description: "Progress bar that increments automatically.",
- children: ,
- },
- {
- title: "Weight",
- description: "Light (default) and medium weight variants.",
- children: (
-
- ),
- code: ' ',
- relevantProps: ["weight"],
- },
- {
- title: "Glowing",
- description: "Glow effect is enabled by default. Set glowing={false} to disable.",
- children: (
-
- ),
- code: " ",
- relevantProps: ["glowing"],
- },
- {
- title: "Custom Range",
- description: "Using minimum=0 and maximum=200 with progress=150 (75% filled).",
- children: ,
- code: ' ',
- relevantProps: ["minimum", "maximum"],
- },
- {
- title: "Custom Override",
- description: 'Using variant="unset" with custom gradient colors.',
- children: (
-
- ),
- code: ` `,
- relevantProps: ["override"],
- },
- ]}
- props={PROGRESSBAR_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/RadioGroupTab.tsx b/src/equicordplugins/components.dev/components/tabs/RadioGroupTab.tsx
deleted file mode 100644
index 900e1a56c..000000000
--- a/src/equicordplugins/components.dev/components/tabs/RadioGroupTab.tsx
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaBaseRadioGroup, StandaloneRadioIndicator } from "@equicordplugins/components.dev";
-
-import { RadioOption, useState } from "..";
-import { DocPage, type PropDef, type PropGroup } from "../DocPage";
-import { EquicordIcon } from "../icons/EquicordIcon";
-
-const RADIOGROUP_PROPS: PropDef[] = [
- { name: "options", type: "RadioOption[]", required: true, description: "Array of radio options to display." },
- { name: "value", type: "string | number | null", description: "Currently selected value." },
- { name: "onChange", type: "(value: string | number) => void", description: "Called when the selection changes." },
- { name: "disabled", type: "boolean", default: "false", description: "Disable the entire radio group." },
- { name: "orientation", type: '"vertical" | "horizontal"', description: "Layout orientation of the radio items." },
- { name: "radioPosition", type: '"left" | "right"', default: '"left"', description: "Position of the radio indicator relative to the label." },
- { name: "withTransparentBackground", type: "boolean", description: "Use transparent background for radio items." },
- { name: "label", type: "string", description: "Field label text for the group." },
- { name: "description", type: "string", description: "Field description text." },
- { name: "required", type: "boolean", description: "Mark the field as required." },
- { name: "errorMessage", type: "string", description: "Error message displayed below the group." },
- { name: "aria-labelledby", type: "string", description: "ID of an external labelling element for accessibility." },
- { name: "className", type: "string", description: "Custom CSS class name." },
-];
-
-const OPTION_PROPS: PropDef[] = [
- { name: "value", type: "string | number", required: true, description: "The value for this option." },
- { name: "name", type: "string", required: true, description: "Display label text." },
- { name: "description", type: "string", description: "Description text shown below the label." },
- { name: "disabled", type: "boolean", description: "Disable this individual option." },
- { name: "icon", type: "ComponentType", description: "Icon component displayed alongside the radio option." },
- { name: "color", type: "string", description: "Custom color for the option highlight." },
-];
-
-const STANDALONE_PROPS: PropDef[] = [
- { name: "isSelected", type: "boolean", required: true, description: "Whether the indicator shows as selected." },
- { name: "disabled", type: "boolean", description: "Disable the indicator." },
-];
-
-const PROP_GROUPS: PropGroup[] = [
- { title: "ManaBaseRadioGroup", props: RADIOGROUP_PROPS },
- { title: "RadioOption", props: OPTION_PROPS },
- { title: "StandaloneRadioIndicator", props: STANDALONE_PROPS },
-];
-
-const BASIC_OPTIONS: RadioOption[] = [
- { value: "option1", name: "Option 1" },
- { value: "option2", name: "Option 2" },
- { value: "option3", name: "Option 3" },
-];
-
-const DESC_OPTIONS: RadioOption[] = [
- { value: "low", name: "Low Quality", description: "Faster loading, uses less data" },
- { value: "medium", name: "Medium Quality", description: "Balanced quality and performance" },
- { value: "high", name: "High Quality", description: "Best quality, uses more data" },
-];
-
-const ICON_OPTIONS: RadioOption[] = [
- { value: "item1", name: "Item with icon", description: "This option has an icon", icon: EquicordIcon },
- { value: "item2", name: "Another with icon", icon: EquicordIcon },
- { value: "item3", name: "Third with icon", icon: EquicordIcon },
-];
-
-const MIXED_OPTIONS: RadioOption[] = [
- { value: "enabled", name: "Enabled option" },
- { value: "disabled", name: "Disabled option", disabled: true },
- { value: "another", name: "Another enabled" },
-];
-
-function BasicDemo() {
- const [value, setValue] = useState("option1");
- return ;
-}
-
-function DescDemo() {
- const [value, setValue] = useState("medium");
- return ;
-}
-
-function IconDemo() {
- const [value, setValue] = useState("item1");
- return ;
-}
-
-function DisabledItemDemo() {
- const [value, setValue] = useState("enabled");
- return ;
-}
-
-function UnselectedDemo() {
- const [value, setValue] = useState(undefined);
- return ;
-}
-
-function StandaloneDemo() {
- const [selected, setSelected] = useState(false);
- return (
- setSelected(!selected)} style={{ cursor: "pointer", display: "inline-block" }}>
-
-
- );
-}
-
-export default function RadioGroupTab() {
- return (
- ,
- code: ` `,
- relevantProps: ["options", "value", "onChange"],
- },
- {
- title: "With Descriptions",
- description: "Options with descriptive text using the description field.",
- children: ,
- },
- {
- title: "With Leading Icons",
- description: "Each option can have an icon component before the radio indicator.",
- children: ,
- },
- {
- title: "Disabled Option",
- description: "Individual options can be disabled while others remain interactive.",
- children: ,
- },
- {
- title: "No Initial Selection",
- description: "Radio group with no option initially selected.",
- children: ,
- },
- {
- title: "Entire Group Disabled",
- description: "The entire group is non-interactive.",
- children: ,
- relevantProps: ["disabled"],
- },
- {
- title: "Standalone Radio Indicator",
- description: "An animated radio circle component for custom radio UIs. Click to toggle.",
- children: ,
- code: " ",
- },
- ]}
- props={PROP_GROUPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/RichTooltipTab.tsx b/src/equicordplugins/components.dev/components/tabs/RichTooltipTab.tsx
deleted file mode 100644
index 95ed33b63..000000000
--- a/src/equicordplugins/components.dev/components/tabs/RichTooltipTab.tsx
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaButton, ManaRichTooltip } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const RICHTOOLTIP_PROPS: PropDef[] = [
- { name: "body", type: "string", required: true, description: "Tooltip body text." },
- { name: "children", type: "ReactNode | ((props) => ReactNode)", required: true, description: "Trigger element or render function." },
- { name: "title", type: "string", description: "Bold title text above the body." },
- { name: "position", type: '"top" | "bottom" | "left" | "right"', description: "Position relative to the trigger." },
- { name: "align", type: '"start" | "center" | "end"', description: "Alignment along the position axis." },
- { name: "spacing", type: "number", description: "Distance in pixels from the trigger element." },
- { name: "asContainer", type: "boolean", description: "Wrap children in a container element for hover detection." },
- { name: "element", type: '"span" | "div"', description: "HTML element type for the container when asContainer is true." },
- { name: "asset", type: "ReactNode | { src: string; alt?: string }", description: "Image or element displayed in the tooltip." },
- { name: "assetSize", type: "number", description: "Size of the asset in pixels." },
- { name: "targetElementRef", type: "RefObject", description: "Ref to an external trigger element instead of wrapping children." },
- { name: "anchorRef", type: "RefObject", description: "Ref to an anchor element for positioning." },
- { name: "positionKey", type: "string", internal: true, description: "Unique key for position caching." },
- { name: "caretConfig", type: '{ align?: "start" | "center" | "end" }', description: "Configuration for the caret arrow." },
- { name: "layerContext", type: "any", internal: true, description: "Layer context for stacking." },
- { name: "ariaHidden", type: "boolean", default: "false", description: "Hide the tooltip from screen readers." },
- { name: "shouldShow", type: "boolean", default: "true", description: "Externally control whether the tooltip is shown." },
- { name: "delay", type: "number", description: "Delay in milliseconds before the tooltip appears." },
- { name: "forceOpen", type: "boolean", default: "false", description: "Force the tooltip to stay open." },
- { name: "overflowOnly", type: "boolean", default: "false", description: "Only show when the trigger text is overflowing." },
- { name: "hideOnClick", type: "boolean", default: "true", description: "Hide when the trigger is clicked." },
- { name: "onTooltipShow", type: "() => void", description: "Callback when the tooltip becomes visible." },
- { name: "onTooltipHide", type: "() => void", description: "Callback when the tooltip is hidden." },
-];
-
-export default function RichTooltipTab() {
- return (
-
-
-
-
-
-
-
-
- ),
- code: `
- Hover me
- `,
- relevantProps: ["title", "body", "asContainer"],
- },
- {
- title: "Positions",
- description: "Tooltip can appear on any side of the trigger element.",
- children: (
-
- {(["top", "bottom", "left", "right"] as const).map(pos => (
-
-
-
- ))}
-
- ),
- relevantProps: ["position"],
- },
- {
- title: "Alignment",
- description: "Align the tooltip along the position axis.",
- children: (
-
- {(["start", "center", "end"] as const).map(align => (
-
-
-
- ))}
-
- ),
- relevantProps: ["align"],
- },
- {
- title: "Custom Spacing",
- description: "Control the distance between tooltip and trigger.",
- children: (
-
-
-
-
-
-
-
-
- ),
- relevantProps: ["spacing"],
- },
- {
- title: "Container Element",
- description: "Choose the wrapper element type for the trigger.",
- children: (
-
-
-
-
-
-
-
-
- ),
- relevantProps: ["element"],
- },
- ]}
- props={RICHTOOLTIP_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/ScrollerTab.tsx b/src/equicordplugins/components.dev/components/tabs/ScrollerTab.tsx
deleted file mode 100644
index be3dadba9..000000000
--- a/src/equicordplugins/components.dev/components/tabs/ScrollerTab.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaButton, Paragraph, ScrollerAuto, ScrollerNone, ScrollerThin, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const SCROLLER_PROPS: PropDef[] = [
- { name: "children", type: "ReactNode", required: true, description: "Content to render inside the scrollable area." },
- { name: "orientation", type: '"vertical" | "horizontal"', default: '"vertical"', description: "Scroll direction." },
- { name: "paddingFix", type: "boolean", default: "true", description: "Apply padding fix for scroll containers." },
- { name: "fade", type: "boolean", default: "false", description: "Add a fade effect at the edges to indicate more content." },
- { name: "dir", type: '"ltr" | "rtl"', default: '"ltr"', description: "Text direction for horizontal scrolling." },
- { name: "onScroll", type: "(e: UIEvent) => void", description: "Scroll event handler." },
- { name: "className", type: "string", description: "Custom CSS class." },
- { name: "style", type: "CSSProperties", description: "Inline styles." },
-];
-
-const SAMPLE_ITEMS = Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`);
-
-function ScrollerDemo({ Component, label }: { Component: React.ComponentType; label: string; }) {
- const [orientation, setOrientation] = useState<"vertical" | "horizontal">("vertical");
- const [fade, setFade] = useState(true);
-
- const scrollerStyle = orientation === "vertical"
- ? { height: 200, width: "100%", border: "1px solid var(--background-modifier-accent)", borderRadius: 8 }
- : { height: 60, width: "100%", border: "1px solid var(--background-modifier-accent)", borderRadius: 8 };
-
- const itemStyle = orientation === "vertical"
- ? { padding: "8px 12px", borderBottom: "1px solid var(--background-modifier-accent)" }
- : { padding: "8px 16px", display: "inline-block", whiteSpace: "nowrap" as const };
-
- return (
-
-
- setOrientation(o => o === "vertical" ? "horizontal" : "vertical")}
- />
- setFade(f => !f)}
- />
-
-
- {SAMPLE_ITEMS.map(item => (
-
- ))}
-
-
- );
-}
-
-export default function ScrollerTab() {
- return (
- ,
- code: `
- {items.map(item => {item.label}
)}
- `,
- relevantProps: ["orientation", "fade"],
- },
- {
- title: "ScrollerAuto",
- description: "Standard scrollbar that appears automatically when content overflows.",
- children: ,
- },
- {
- title: "ScrollerNone",
- description: "No visible scrollbar. Content is still scrollable via mouse wheel or touch.",
- children: ,
- },
- ]}
- props={SCROLLER_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/SearchBarTab.tsx b/src/equicordplugins/components.dev/components/tabs/SearchBarTab.tsx
deleted file mode 100644
index 10a702d55..000000000
--- a/src/equicordplugins/components.dev/components/tabs/SearchBarTab.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { SearchBar, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const SEARCHBAR_PROPS: PropDef[] = [
- { name: "query", type: "string", required: true, description: "Current search query value." },
- { name: "onChange", type: "(value: string) => void", required: true, description: "Called when the query text changes." },
- { name: "onClear", type: "() => void", description: "Called when the clear button is clicked." },
- { name: "placeholder", type: "string", description: "Placeholder text when empty." },
- { name: "size", type: '"sm" | "md"', description: "Input size variant." },
- { name: "autoFocus", type: "boolean", description: "Focus the input on mount." },
- { name: "disabled", type: "boolean", default: "false", description: "Disable the search bar." },
- { name: "onKeyDown", type: "(e: KeyboardEvent) => void", description: "Keyboard event handler." },
- { name: "onBlur", type: "() => void", description: "Called when the input loses focus." },
- { name: "onFocus", type: "() => void", description: "Called when the input gains focus." },
- { name: "autoComplete", type: "string", description: "HTML autocomplete attribute value." },
- { name: "inputProps", type: "Record", description: "Additional props passed to the underlying input element." },
- { name: "className", type: "string", description: "Custom CSS class." },
- { name: "aria-label", type: "string", description: "Accessibility label." },
-];
-
-function BasicDemo() {
- const [query, setQuery] = useState("");
- return (
- setQuery("")}
- placeholder="Search..."
- />
- );
-}
-
-function SizesDemo() {
- const [query, setQuery] = useState("");
- return (
-
- setQuery("")} placeholder="Small size" size="sm" />
- setQuery("")} placeholder="Medium size (default)" size="md" />
-
- );
-}
-
-function StatesDemo() {
- const [prefilled, setPrefilled] = useState("prefilled");
- return (
-
- { }} placeholder="Disabled" disabled />
- setPrefilled("")} placeholder="Prefilled" />
-
- );
-}
-
-export default function SearchBarTab() {
- return (
- ,
- code: ` setQuery("")}
- placeholder="Search..."
-/>`,
- relevantProps: ["query", "onChange", "onClear", "placeholder"],
- },
- {
- title: "Sizes",
- description: "Available in sm and md (default) sizes.",
- children: ,
- relevantProps: ["size"],
- },
- {
- title: "States",
- description: "Disabled and prefilled states.",
- children: ,
- relevantProps: ["disabled"],
- },
- ]}
- props={SEARCHBAR_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/SelectTab.tsx b/src/equicordplugins/components.dev/components/tabs/SelectTab.tsx
deleted file mode 100644
index b4cf83680..000000000
--- a/src/equicordplugins/components.dev/components/tabs/SelectTab.tsx
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaSelect, ManaSelectOption, useState } from "..";
-import { DocPage, type PropDef, type PropGroup } from "../DocPage";
-
-const SELECT_PROPS: PropDef[] = [
- { name: "options", type: "ManaSelectOption[]", required: true, description: "Array of selectable options." },
- { name: "value", type: "string | string[] | null", description: "Currently selected value(s)." },
- { name: "onSelectionChange", type: "(value: string | string[] | null) => void", description: "Called when the selection changes. Note: NOT onChange." },
- { name: "selectionMode", type: '"single" | "multiple"', description: "Single or multi-select mode." },
- { name: "placeholder", type: "string", description: "Placeholder text when nothing is selected." },
- { name: "disabled", type: "boolean", default: "false", description: "Disable the select." },
- { name: "readOnly", type: "boolean", description: "Make the select read-only." },
- { name: "clearable", type: "boolean", description: "Allow clearing the selection." },
- { name: "fullWidth", type: "boolean", description: "Expand to fill available width." },
- { name: "autoFocus", type: "boolean", description: "Focus on mount." },
- { name: "closeOnSelect", type: "boolean", description: "Close the dropdown after selecting." },
- { name: "shouldFocusWrap", type: "boolean", description: "Wrap keyboard focus at list ends." },
- { name: "maxOptionsVisible", type: "number", description: "Maximum options visible before scrolling." },
- { name: "wrapTags", type: "boolean", description: "Wrap selected tags to multiple lines in multi-select." },
- { name: "formatOption", type: "(option: ManaSelectOption) => ReactNode", description: "Custom render for each option." },
- { name: "label", type: "string", description: "Label text for the select." },
- { name: "required", type: "boolean", description: "Mark as required for form validation." },
-];
-
-const OPTION_PROPS: PropDef[] = [
- { name: "id", type: "string", required: true, description: "Unique option identifier." },
- { name: "value", type: "string", required: true, description: "Option value." },
- { name: "label", type: "string", required: true, description: "Display label." },
-];
-
-const PROP_GROUPS: PropGroup[] = [
- { title: "ManaSelect", props: SELECT_PROPS },
- { title: "ManaSelectOption", props: OPTION_PROPS },
-];
-
-const SAMPLE_OPTIONS: ManaSelectOption[] = [
- { id: "1", value: "option1", label: "Option 1" },
- { id: "2", value: "option2", label: "Option 2" },
- { id: "3", value: "option3", label: "Option 3" },
- { id: "4", value: "option4", label: "Option 4" },
-];
-
-function SingleDemo() {
- const [value, setValue] = useState("option1");
- return (
- setValue(v as string)}
- selectionMode="single"
- />
- );
-}
-
-function MultiDemo() {
- const [value, setValue] = useState(["option1", "option2"]);
- return (
- setValue(v as string[])}
- selectionMode="multiple"
- />
- );
-}
-
-function PlaceholderDemo() {
- const [value, setValue] = useState("");
- return (
- setValue(v as string)}
- placeholder="Select an option..."
- />
- );
-}
-
-function ClearableDemo() {
- const [value, setValue] = useState("option1");
- return (
- setValue(v as string)}
- clearable
- />
- );
-}
-
-export default function SelectTab() {
- return (
- ,
- code: ` setValue(v as string)}
- selectionMode="single"
-/>`,
- relevantProps: ["options", "value", "onSelectionChange", "selectionMode"],
- },
- {
- title: "Multiple Selection",
- description: "Multi-select with tag pills for each selected option.",
- children: ,
- },
- {
- title: "With Placeholder",
- description: "Shows placeholder text when no option is selected.",
- children: ,
- relevantProps: ["placeholder"],
- },
- {
- title: "Clearable",
- description: "Adds a clear button to reset the selection.",
- children: ,
- relevantProps: ["clearable"],
- },
- {
- title: "Full Width",
- description: "Expands to fill the available width.",
- children: (
-
- ),
- relevantProps: ["fullWidth"],
- },
- {
- title: "Disabled",
- description: "Non-interactive disabled state.",
- children: (
-
- ),
- relevantProps: ["disabled"],
- },
- ]}
- props={PROP_GROUPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/SkeletonTab.tsx b/src/equicordplugins/components.dev/components/tabs/SkeletonTab.tsx
deleted file mode 100644
index af6327d78..000000000
--- a/src/equicordplugins/components.dev/components/tabs/SkeletonTab.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Skeleton } from "@equicordplugins/components.dev";
-
-import { ManaButton, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const SKELETON_PROPS: PropDef[] = [
- { name: "withHeader", type: "boolean", default: "true", description: "Show a header placeholder row." },
- { name: "size", type: "number", default: "15", description: "Number of skeleton rows to display." },
-];
-
-function SkeletonDemo() {
- const [withHeader, setWithHeader] = useState(true);
- const [size, setSize] = useState(5);
-
- return (
-
-
- setWithHeader(!withHeader)} />
- setSize(Math.max(1, size - 1))} />
- setSize(Math.min(20, size + 1))} />
-
-
-
-
-
- );
-}
-
-export default function SkeletonTab() {
- return (
- ,
- code: " ",
- relevantProps: ["withHeader", "size"],
- },
- {
- title: "Header Only",
- children: (
-
-
-
- ),
- },
- {
- title: "No Header",
- children: (
-
-
-
- ),
- },
- ]}
- props={SKELETON_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/SliderTab.tsx b/src/equicordplugins/components.dev/components/tabs/SliderTab.tsx
deleted file mode 100644
index 4f2b1024c..000000000
--- a/src/equicordplugins/components.dev/components/tabs/SliderTab.tsx
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Paragraph, Slider, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const SLIDER_PROPS: PropDef[] = [
- { name: "initialValue", type: "number", description: "Initial slider value (uncontrolled)." },
- { name: "value", type: "number", description: "Current slider value (controlled)." },
- { name: "minValue", type: "number", description: "Minimum range value." },
- { name: "maxValue", type: "number", description: "Maximum range value." },
- { name: "onValueChange", type: "(value: number) => void", description: "Called when the value changes (on release)." },
- { name: "asValueChanges", type: "(value: number) => void", description: "Called continuously as the value changes (while dragging)." },
- { name: "onValueRender", type: "(value: number) => string | null", description: "Custom tooltip label for the current value." },
- { name: "markers", type: "number[]", description: "Array of values to show as tick marks." },
- { name: "stickToMarkers", type: "boolean", description: "Snap the slider value to the nearest marker." },
- { name: "equidistant", type: "boolean", description: "Space markers equally regardless of value." },
- { name: "onMarkerRender", type: "(value: number) => string | ReactNode", description: "Custom label for each marker tick." },
- { name: "keyboardStep", type: "number", description: "Step size for keyboard arrow key increments." },
- { name: "disabled", type: "boolean", default: "false", description: "Disable interaction." },
- { name: "mini", type: "boolean", description: "Use compact visual style." },
- { name: "hideBubble", type: "boolean", description: "Hide the value tooltip bubble." },
- { name: "orientation", type: '"horizontal" | "vertical"', default: '"horizontal"', description: "Slider orientation." },
- { name: "className", type: "string", description: "Custom CSS class." },
-];
-
-function BasicDemo() {
- const [value, setValue] = useState(50);
- return (
-
- );
-}
-
-function MarkersDemo() {
- const [value, setValue] = useState(50);
- return (
-
-
Value: {value}
-
`${v}%`}
- />
-
- );
-}
-
-function MiniDemo() {
- const [value, setValue] = useState(30);
- return (
-
- );
-}
-
-export default function SliderTab() {
- return (
- ,
- code: ` `,
- relevantProps: ["initialValue", "minValue", "maxValue", "onValueChange"],
- },
- {
- title: "With Markers",
- description: "Tick marks at specified values with custom labels.",
- children: ,
- code: ` \`\${v}%\`}
-/>`,
- relevantProps: ["markers", "onMarkerRender"],
- },
- {
- title: "Stick to Markers",
- description: "Value snaps to the nearest marker position.",
- children: (
- `${v}%`}
- />
- ),
- relevantProps: ["stickToMarkers"],
- },
- {
- title: "Mini",
- description: "Compact visual style for tight layouts.",
- children: ,
- relevantProps: ["mini"],
- },
- {
- title: "Disabled",
- description: "Non-interactive disabled state.",
- children: ,
- relevantProps: ["disabled"],
- },
- {
- title: "Custom Range",
- description: "Slider with negative to positive range.",
- children: (
- v.toString()}
- />
- ),
- },
- ]}
- props={SLIDER_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/SpinnerTab.tsx b/src/equicordplugins/components.dev/components/tabs/SpinnerTab.tsx
deleted file mode 100644
index e1bb67949..000000000
--- a/src/equicordplugins/components.dev/components/tabs/SpinnerTab.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaButton, Paragraph, Spinner, SpinnerTypes, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const SPINNER_PROPS: PropDef[] = [
- { name: "type", type: "SpinnerType", description: 'Spinner variant. One of: "wanderingCubes", "chasingDots", "pulsingEllipsis", "spinningCircle", "spinningCircleSimple", "lowMotion".' },
- { name: "animated", type: "boolean", default: "true", description: "Enable or pause the animation." },
- { name: "className", type: "string", description: "CSS class for the container." },
- { name: "itemClassName", type: "string", description: "CSS class for inner animation items." },
- { name: "aria-label", type: "string", description: "Accessibility label." },
-];
-
-function AnimationToggleDemo() {
- const [animated, setAnimated] = useState(true);
- return (
-
-
setAnimated(!animated)}
- style={{ marginBottom: 16 }}
- />
-
-
-
- animated={animated.toString()}
-
-
-
- );
-}
-
-export default function SpinnerTab() {
- return (
-
- {SpinnerTypes.map(type => (
-
- ))}
-
- ),
- code: ' ',
- relevantProps: ["type"],
- },
- {
- title: "Animation Toggle",
- description: "Spinners can be paused with animated=false.",
- children: ,
- relevantProps: ["animated"],
- },
- {
- title: "Low Motion",
- description: "The lowMotion type is used when the user prefers reduced motion. The component automatically switches to this variant.",
- children: (
-
-
-
- ),
- },
- ]}
- props={SPINNER_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/SwitchTab.tsx b/src/equicordplugins/components.dev/components/tabs/SwitchTab.tsx
deleted file mode 100644
index fa2f59a04..000000000
--- a/src/equicordplugins/components.dev/components/tabs/SwitchTab.tsx
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaSwitch } from "@equicordplugins/components.dev";
-import { findComponentByCodeLazy } from "@webpack";
-
-import { useState } from "..";
-import { DocPage, type PropDef, type PropGroup } from "../DocPage";
-
-interface SwitchWithLabelProps {
- checked: boolean;
- onChange?: (checked: boolean) => void;
- disabled?: boolean;
- label?: string;
- description?: string;
-}
-
-const SwitchWithLabel = findComponentByCodeLazy('"data-toggleable-component":"switch"') as React.ComponentType;
-
-const SWITCH_PROPS: PropDef[] = [
- { name: "checked", type: "boolean", required: true, description: "Current toggle state." },
- { name: "onChange", type: "(checked: boolean) => void", description: "Called when the switch is toggled." },
- { name: "disabled", type: "boolean", default: "false", description: "Disable interaction." },
- { name: "id", type: "string", description: "HTML id attribute." },
- { name: "hasIcon", type: "boolean", description: "Show a checkmark/x icon inside the toggle." },
- { name: "describedBy", type: "string", internal: true, description: "ID of an element describing this switch." },
- { name: "labelledBy", type: "string", internal: true, description: "ID of an element labelling this switch." },
- { name: "innerRef", type: "Ref", internal: true, description: "Ref to the underlying input element." },
-];
-
-const SWITCH_WITH_LABEL_PROPS: PropDef[] = [
- { name: "checked", type: "boolean", required: true, description: "Current toggle state." },
- { name: "onChange", type: "(checked: boolean) => void", description: "Called when the switch is toggled." },
- { name: "label", type: "string", description: "Label text displayed next to the switch." },
- { name: "description", type: "string", description: "Description text below the label." },
- { name: "disabled", type: "boolean", default: "false", description: "Disable interaction." },
-];
-
-const PROP_GROUPS: PropGroup[] = [
- { title: "ManaSwitch", props: SWITCH_PROPS },
- { title: "SwitchWithLabel", props: SWITCH_WITH_LABEL_PROPS },
-];
-
-function BasicDemo() {
- const [on, setOn] = useState(true);
- const [off, setOff] = useState(false);
-
- return (
-
-
- On:
-
-
-
- Off:
-
-
-
- Disabled On:
-
-
-
- Disabled Off:
-
-
-
- );
-}
-
-function LabelDemo() {
- const [on, setOn] = useState(true);
- const [off, setOff] = useState(false);
-
- return (
-
-
-
-
- );
-}
-
-function DescriptionDemo() {
- const [checked, setChecked] = useState(true);
- return (
-
- );
-}
-
-export default function SwitchTab() {
- return (
- ,
- code: " ",
- relevantProps: ["checked", "onChange", "disabled"],
- },
- {
- title: "Switch with Label",
- description: "SwitchWithLabel renders a label next to the toggle.",
- children: ,
- code: ` `,
- },
- {
- title: "With Description",
- description: "Label with description text below.",
- children: ,
- code: ` `,
- },
- {
- title: "Disabled States",
- description: "Both checked and unchecked disabled states.",
- children: (
-
-
-
-
- ),
- },
- ]}
- props={PROP_GROUPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/TabBarTab.tsx b/src/equicordplugins/components.dev/components/tabs/TabBarTab.tsx
deleted file mode 100644
index 56f6031b5..000000000
--- a/src/equicordplugins/components.dev/components/tabs/TabBarTab.tsx
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Paragraph, TabBar, useState } from "..";
-import { DocPage, type PropDef, type PropGroup } from "../DocPage";
-
-const TABBAR_PROPS: PropDef[] = [
- { name: "type", type: '"side" | "top" | "top-pill"', description: "Tab bar visual style." },
- { name: "look", type: '"brand" | "grey"', description: "Color scheme." },
- { name: "selectedItem", type: "string", description: "ID of the currently selected tab." },
- { name: "onItemSelect", type: "(id: string) => void", description: "Called when a tab is selected." },
- { name: "orientation", type: '"horizontal" | "vertical"', description: "Layout direction." },
- { name: "className", type: "string", description: "Custom CSS class." },
- { name: "style", type: "CSSProperties", description: "Inline styles." },
- { name: "aria-label", type: "string", description: "Accessibility label." },
-];
-
-const ITEM_PROPS: PropDef[] = [
- { name: "id", type: "string", required: true, description: "Unique tab identifier." },
- { name: "children", type: "ReactNode", required: true, description: "Tab label content." },
- { name: "disabled", type: "boolean", description: "Disable the tab." },
- { name: "color", type: "string", description: "Custom tab color (hex or CSS color)." },
- { name: "variant", type: '"destructive"', description: "Danger styling for actions like logout." },
- { name: "disableItemStyles", type: "boolean", description: "Remove default tab styles." },
- { name: "onClick", type: "MouseEventHandler", description: "Custom click handler." },
-];
-
-const PROP_GROUPS: PropGroup[] = [
- { title: "TabBar", props: TABBAR_PROPS },
- { title: "TabBar.Item", props: ITEM_PROPS },
-];
-
-function SideDemo() {
- const [tab, setTab] = useState("tab1");
- return (
-
-
Selected: {tab}
-
- First Tab
- Second Tab
- Third Tab
-
-
- );
-}
-
-function TopDemo() {
- const [tab, setTab] = useState("tab1");
- return (
-
- Overview
- Settings
- Members
-
- );
-}
-
-function TopPillDemo() {
- const [tab, setTab] = useState("tab1");
- return (
-
- All
- Online
- Pending
- Blocked
-
- );
-}
-
-function BrandDemo() {
- const [tab, setTab] = useState("tab1");
- return (
-
- Home
- Explore
- Library
-
- );
-}
-
-function HeaderSeparatorDemo() {
- const [tab, setTab] = useState("tab1");
- return (
-
- User Settings
- My Account
- Privacy
-
- App Settings
- Appearance
- Notifications
-
- );
-}
-
-function FeaturesDemo() {
- const [tab, setTab] = useState("tab1");
- const [colorTab, setColorTab] = useState("tab1");
-
- return (
-
-
-
Disabled items:
-
- Active
- Disabled
- Another Active
-
-
-
-
Custom colors:
-
- Green
- Yellow
- Red
-
-
-
-
Destructive variant:
-
- Settings
- Log Out
-
-
-
- );
-}
-
-export default function TabBarTab() {
- return (
- ,
- code: `
- First Tab
- Second Tab
- `,
- relevantProps: ["type", "look", "selectedItem", "onItemSelect"],
- },
- {
- title: "Top",
- description: "Horizontal tabs with underline indicator.",
- children: ,
- },
- {
- title: "Top Pill",
- description: "Pill-style horizontal tabs.",
- children: ,
- },
- {
- title: "Brand Look",
- description: "Brand-colored tab styling.",
- children: ,
- },
- {
- title: "Headers and Separators",
- description: "TabBar.Header and TabBar.Separator for organizing groups of tabs.",
- children: ,
- },
- {
- title: "Disabled, Colors, Destructive",
- description: "Items can be disabled, colored, or styled as destructive.",
- children: ,
- relevantProps: ["disabled", "color", "variant"],
- },
- ]}
- props={PROP_GROUPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/TextAreaTab.tsx b/src/equicordplugins/components.dev/components/tabs/TextAreaTab.tsx
deleted file mode 100644
index 954bdcefa..000000000
--- a/src/equicordplugins/components.dev/components/tabs/TextAreaTab.tsx
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaTextArea, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const TEXTAREA_PROPS: PropDef[] = [
- { name: "value", type: "string", description: "Current textarea value (controlled)." },
- { name: "defaultValue", type: "string", description: "Initial value (uncontrolled)." },
- { name: "onChange", type: "(value: string, name?: string) => void", description: "Called when the text changes." },
- { name: "placeholder", type: "string", description: "Placeholder text when empty." },
- { name: "name", type: "string", description: "HTML name attribute for form submission." },
- { name: "rows", type: "number", description: "Fixed number of visible text rows." },
- { name: "autosize", type: "boolean", description: "Automatically grow height to fit content." },
- { name: "autoFocus", type: "boolean", description: "Focus on mount." },
- { name: "maxLength", type: "number", description: "Maximum character limit." },
- { name: "minLength", type: "number", description: "Minimum character requirement." },
- { name: "showCharacterCount", type: "boolean", description: "Display current character count." },
- { name: "showRemainingCharacterCount", type: "boolean", description: "Display remaining characters instead of current count." },
- { name: "error", type: "string | boolean", description: "Error state. String shows error message, boolean shows red border." },
- { name: "disabled", type: "boolean", default: "false", description: "Disable the textarea." },
- { name: "readOnly", type: "boolean", description: "Make the textarea read-only." },
- { name: "fullWidth", type: "boolean", description: "Expand to full available width." },
- { name: "inputRef", type: "Ref", internal: true, description: "Ref to the underlying textarea element." },
-];
-
-function BasicDemo() {
- const [value, setValue] = useState("Hello world\nThis is a textarea");
- return ;
-}
-
-function AutosizeDemo() {
- const [value, setValue] = useState("This textarea will grow as you type more content...");
- return ;
-}
-
-function CharCountDemo() {
- const [value, setValue] = useState("Count characters");
- return ;
-}
-
-export default function TextAreaTab() {
- return (
- ,
- code: " ",
- relevantProps: ["value", "onChange"],
- },
- {
- title: "With Placeholder",
- children: (
- { }} placeholder="Enter your message..." />
- ),
- relevantProps: ["placeholder"],
- },
- {
- title: "Autosize",
- description: "Automatically grows to fit content as you type.",
- children: ,
- relevantProps: ["autosize"],
- },
- {
- title: "Fixed Rows",
- description: "Fixed height with 5 visible rows.",
- children: (
- { }} rows={5} />
- ),
- relevantProps: ["rows"],
- },
- {
- title: "Character Count",
- description: "Shows character count with a max length of 200.",
- children: ,
- relevantProps: ["showCharacterCount", "maxLength"],
- },
- {
- title: "States",
- description: "Disabled and read-only states.",
- children: (
-
-
-
-
- ),
- relevantProps: ["disabled", "readOnly"],
- },
- ]}
- props={TEXTAREA_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/TextButtonTab.tsx b/src/equicordplugins/components.dev/components/tabs/TextButtonTab.tsx
deleted file mode 100644
index aa6f25796..000000000
--- a/src/equicordplugins/components.dev/components/tabs/TextButtonTab.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaTextButton, ManaTextButtonTextVariants, ManaTextButtonVariants } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const TEXTBUTTON_PROPS: PropDef[] = [
- { name: "text", type: "string", required: true, description: "Button label text." },
- { name: "variant", type: '"primary" | "secondary" | "always-white" | "critical"', description: "Color variant." },
- { name: "textVariant", type: "string", description: 'Typography variant, e.g. "text-sm/medium", "text-lg/medium".' },
- { name: "lineClamp", type: "number", description: "Max lines before truncation with ellipsis." },
- { name: "disabled", type: "boolean", default: "false", description: "Disable the button." },
- { name: "onClick", type: "(e: MouseEvent) => void", description: "Click handler." },
- { name: "role", type: "string", description: "ARIA role attribute." },
- { name: "type", type: '"button" | "submit" | "reset"', description: "HTML button type." },
- { name: "buttonRef", type: "Ref", internal: true, description: "Ref to the underlying button element." },
- { name: "className", type: "string", description: "Custom CSS class." },
- { name: "style", type: "CSSProperties", description: "Inline styles." },
-];
-
-export default function TextButtonTab() {
- return (
-
- {ManaTextButtonVariants.map(variant => (
-
- ))}
-
- ),
- code: ' ',
- relevantProps: ["variant"],
- },
- {
- title: "Text Variants",
- description: "Different typography sizes and weights.",
- children: (
-
- {ManaTextButtonTextVariants.map(textVariant => (
-
- ))}
-
- ),
- relevantProps: ["textVariant"],
- },
- {
- title: "States",
- description: "Normal and disabled states.",
- children: (
-
-
-
-
- ),
- relevantProps: ["disabled"],
- },
- {
- title: "Line Clamp",
- description: "Truncate long text to a single line.",
- children: (
-
-
-
- ),
- relevantProps: ["lineClamp"],
- },
- ]}
- props={TEXTBUTTON_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/TextInputTab.tsx b/src/equicordplugins/components.dev/components/tabs/TextInputTab.tsx
deleted file mode 100644
index 478b27795..000000000
--- a/src/equicordplugins/components.dev/components/tabs/TextInputTab.tsx
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaTextInput, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const TEXTINPUT_PROPS: PropDef[] = [
- { name: "value", type: "string", description: "Current input value (controlled)." },
- { name: "defaultValue", type: "string", description: "Initial value (uncontrolled)." },
- { name: "onChange", type: "(value: string, name?: string) => void", description: "Called when the input value changes." },
- { name: "placeholder", type: "string", description: "Placeholder text when empty." },
- { name: "name", type: "string", description: "HTML name attribute for form submission." },
- { name: "type", type: '"text" | "password" | "email" | "number" | "search" | "tel" | "url"', default: '"text"', description: "Input type." },
- { name: "size", type: '"sm" | "md"', default: '"md"', description: "Input size variant." },
- { name: "clearable", type: "boolean | { show: boolean }", description: "Show a clear button when the input has a value." },
- { name: "showCharacterCount", type: "boolean", description: "Display current character count." },
- { name: "maxLength", type: "number", description: "Maximum character limit." },
- { name: "minLength", type: "number", description: "Minimum character requirement." },
- { name: "error", type: "string | boolean", description: "Error state. String shows error message, boolean shows red border." },
- { name: "disabled", type: "boolean", default: "false", description: "Disable the input." },
- { name: "readOnly", type: "boolean", description: "Make the input read-only." },
- { name: "fullWidth", type: "boolean", description: "Expand to full available width." },
- { name: "leading", type: "TextInputLeadingAccessory", description: "Leading accessory (icon, button, tags, or image)." },
- { name: "trailing", type: "TextInputTrailingAccessory", description: "Trailing accessory (icon or button)." },
- { name: "inputRef", type: "Ref", internal: true, description: "Ref to the underlying input element." },
-];
-
-function BasicDemo() {
- const [value, setValue] = useState("Hello world");
- return ;
-}
-
-function SizesDemo() {
- const [sm, setSm] = useState("Small");
- const [md, setMd] = useState("Medium");
- return (
-
-
-
-
- );
-}
-
-function ClearableDemo() {
- const [value, setValue] = useState("Clear me");
- return ;
-}
-
-function CharCountDemo() {
- const [value, setValue] = useState("Count chars");
- return ;
-}
-
-function ErrorDemo() {
- const [value, setValue] = useState("Invalid input");
- return ;
-}
-
-export default function TextInputTab() {
- return (
- ,
- code: " ",
- relevantProps: ["value", "onChange"],
- },
- {
- title: "Sizes",
- description: "Available in sm and md (default) sizes.",
- children: ,
- relevantProps: ["size"],
- },
- {
- title: "With Placeholder",
- children: (
- { }} placeholder="Enter text here..." />
- ),
- relevantProps: ["placeholder"],
- },
- {
- title: "Clearable",
- description: "Shows a clear button when the input has a value.",
- children: ,
- relevantProps: ["clearable"],
- },
- {
- title: "Character Count",
- description: "Displays character count with a 50-character max.",
- children: ,
- relevantProps: ["showCharacterCount", "maxLength"],
- },
- {
- title: "Error State",
- description: "Red border indicating invalid input.",
- children: ,
- relevantProps: ["error"],
- },
- {
- title: "States",
- description: "Disabled and read-only states.",
- children: (
-
-
-
-
- ),
- relevantProps: ["disabled", "readOnly"],
- },
- ]}
- props={TEXTINPUT_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/TimestampTab.tsx b/src/equicordplugins/components.dev/components/tabs/TimestampTab.tsx
deleted file mode 100644
index 5804f7e15..000000000
--- a/src/equicordplugins/components.dev/components/tabs/TimestampTab.tsx
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Paragraph, Timestamp, TimestampDisplayFormats, TooltipPositions } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const TIMESTAMP_PROPS: PropDef[] = [
- { name: "timestamp", type: "Date | Moment", required: true, description: "The date or moment object to display." },
- { name: "timestampFormat", type: "TimestampDisplayFormat", description: 'Moment.js format string. One of: "LT", "LTS", "L", "LL", "LLL", "LLLL", "l", "ll", "lll", "llll".' },
- { name: "compact", type: "boolean", default: "false", description: "Use a shorter display style." },
- { name: "cozyAlt", type: "boolean", default: "false", description: "Use the cozy alternative layout." },
- { name: "isInline", type: "boolean", default: "false", description: "Render the timestamp inline." },
- { name: "isVisibleOnlyOnHover", type: "boolean", default: "false", description: "Hide the timestamp until the parent is hovered." },
- { name: "isEdited", type: "boolean", default: "false", description: 'Show an "(edited)" indicator after the timestamp.' },
- { name: "tooltipPosition", type: '"top" | "bottom" | "left" | "right"', description: "Position of the full-date tooltip." },
- { name: "id", type: "string", description: "HTML id attribute." },
- { name: "className", type: "string", description: "Additional CSS class." },
- { name: "children", type: "ReactNode", description: "Custom content to render instead of the formatted timestamp." },
-];
-
-export default function TimestampTab() {
- const now = new Date();
-
- return (
-
- {TimestampDisplayFormats.map(({ format, description }) => (
-
-
-
- {format}: {description}
-
-
- ))}
-
- ),
- code: ' ',
- relevantProps: ["timestamp", "timestampFormat"],
- },
- {
- title: "Compact Mode",
- description: "Compact mode shows a shorter version of the timestamp.",
- children: (
-
-
-
-
- compact=false (default)
-
-
-
-
- ),
- relevantProps: ["compact"],
- },
- {
- title: "Display Variants",
- description: "Inline and cozy alternative display modes.",
- children: (
-
-
-
-
- isInline=false (default)
-
-
-
-
-
- ),
- relevantProps: ["isInline", "cozyAlt"],
- },
- {
- title: "Edited Indicator",
- description: 'Shows an "(edited)" indicator after the timestamp.',
- children: (
-
-
-
-
- isEdited=false (default)
-
-
-
-
- ),
- relevantProps: ["isEdited"],
- },
- {
- title: "Visibility on Hover",
- description: "Timestamp can be hidden until the parent element is hovered.",
- children: (
-
-
-
- Hover me:
-
-
- isVisibleOnlyOnHover=true
-
-
-
- ),
- relevantProps: ["isVisibleOnlyOnHover"],
- },
- {
- title: "Tooltip Positions",
- description: "The tooltip showing the full date can be positioned on any side.",
- children: (
-
- {TooltipPositions.map(position => (
-
-
-
- tooltipPosition="{position}"
-
-
- ))}
-
- ),
- relevantProps: ["tooltipPosition"],
- },
- ]}
- props={TIMESTAMP_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/ToastTab.tsx b/src/equicordplugins/components.dev/components/tabs/ToastTab.tsx
deleted file mode 100644
index 8c187fe3e..000000000
--- a/src/equicordplugins/components.dev/components/tabs/ToastTab.tsx
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaButton, Paragraph, showToast, Toasts, ToastType, type ToastTypeValue } from "..";
-import { DocPage, type PropGroup } from "../DocPage";
-
-const TOAST_TYPES: { type: ToastTypeValue; label: string; description: string; }[] = [
- { type: ToastType.MESSAGE, label: "MESSAGE", description: "Default message toast." },
- { type: ToastType.SUCCESS, label: "SUCCESS", description: "Green success toast." },
- { type: ToastType.FAILURE, label: "FAILURE", description: "Red failure/error toast." },
- { type: ToastType.CLIP, label: "CLIP", description: "Clip/copy toast." },
- { type: ToastType.LINK, label: "LINK", description: "Link copied toast." },
- { type: ToastType.FORWARD, label: "FORWARD", description: "Forward action toast." },
- { type: ToastType.BOOKMARK, label: "BOOKMARK", description: "Bookmark action toast." },
- { type: ToastType.CLOCK, label: "CLOCK", description: "Clock/timer toast." },
-];
-
-const PROP_GROUPS: PropGroup[] = [
- {
- title: "showToast(message, type)",
- props: [
- { name: "message", type: "string", required: true, description: "Toast message text." },
- { name: "type", type: "ToastTypeValue", default: '"message"', description: "Toast type from ToastType." },
- ],
- },
- {
- title: "Toasts.create(message, type, options)",
- props: [
- { name: "message", type: "string", required: true, description: "Toast message text." },
- { name: "type", type: "ToastTypeValue", required: true, description: "Toast type from ToastType." },
- { name: "options.duration", type: "number", description: "Display time in milliseconds." },
- { name: "options.position", type: "0 | 1", description: "Toast position. 0 = TOP, 1 = BOTTOM." },
- { name: "options.component", type: "ReactNode", description: "Custom React content for CUSTOM type toasts." },
- ],
- },
- {
- title: "ToastType",
- props: [
- { name: "MESSAGE", type: '"message"', description: "Default message style." },
- { name: "SUCCESS", type: '"success"', description: "Green checkmark icon." },
- { name: "FAILURE", type: '"failure"', description: "Red X icon." },
- { name: "CUSTOM", type: '"custom"', description: "Custom component content." },
- { name: "CLIP", type: '"clip"', description: "Clip/scissors icon." },
- { name: "LINK", type: '"link"', description: "Link icon." },
- { name: "FORWARD", type: '"forward"', description: "Forward arrow icon." },
- { name: "BOOKMARK", type: '"bookmark"', description: "Bookmark icon." },
- { name: "CLOCK", type: '"clock"', description: "Clock icon." },
- ],
- },
-];
-
-export default function ToastTab() {
- return (
-
- {TOAST_TYPES.map(({ type, label, description }) => (
-
-
showToast(`This is a ${label} toast!`, type)}
- />
-
- {description}
-
-
- ))}
-
- ),
- code: 'showToast("Copied to clipboard!", ToastType.SUCCESS);',
- },
- {
- title: "Simple Usage",
- description: "showToast is the quickest way to show a toast. It creates and shows a toast in one call.",
- children: (
- showToast("Hello from showToast!", ToastType.SUCCESS)}
- />
- ),
- code: 'showToast("Hello from showToast!", ToastType.SUCCESS);',
- },
- {
- title: "Advanced Usage",
- description: "Use Toasts.create to build a toast with custom duration, position, or component content, then Toasts.show to display it.",
- children: (
-
- {
- const toast = Toasts.create("This lasts 5 seconds", ToastType.SUCCESS, { duration: 5000 });
- Toasts.show(toast);
- }}
- />
- {
- const toast = Toasts.create("Bottom toast", ToastType.MESSAGE, { position: Toasts.Position.BOTTOM });
- Toasts.show(toast);
- }}
- />
- {
- const toast = Toasts.create("Custom", ToastType.CUSTOM, {
- component: Custom JSX content! ,
- });
- Toasts.show(toast);
- }}
- />
-
- ),
- code: `const toast = Toasts.create("Done!", ToastType.SUCCESS, {
- duration: 5000,
- position: Toasts.Position.BOTTOM,
-});
-Toasts.show(toast);`,
- },
- {
- title: "Pop Toast",
- description: "Toasts.pop removes the most recent toast from the stack.",
- children: (
- Toasts.pop()}
- />
- ),
- code: "Toasts.pop();",
- },
- ]}
- props={PROP_GROUPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/TooltipTab.tsx b/src/equicordplugins/components.dev/components/tabs/TooltipTab.tsx
deleted file mode 100644
index 42a8f50df..000000000
--- a/src/equicordplugins/components.dev/components/tabs/TooltipTab.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { ManaButton, ManaTooltip, Paragraph, TooltipColors, TooltipPositions } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const TOOLTIP_PROPS: PropDef[] = [
- { name: "text", type: "string | (() => ReactNode)", required: true, description: "Tooltip content. Can be a string or a render function for rich content." },
- { name: "children", type: "(props) => ReactNode", required: true, description: "Render function that receives props to spread on the trigger element." },
- { name: "position", type: '"top" | "bottom" | "left" | "right"', default: '"top"', description: "Which side of the trigger the tooltip appears on." },
- { name: "align", type: '"start" | "center" | "end"', default: '"center"', description: "Alignment along the tooltip edge." },
- { name: "color", type: '"primary" | "grey" | "brand" | "green" | "red"', default: '"primary"', description: "Tooltip background color." },
- { name: "spacing", type: "number", default: "8", description: "Gap in pixels between the trigger and tooltip." },
- { name: "delay", type: "number", description: "Delay in milliseconds before the tooltip appears." },
- { name: "hideOnClick", type: "boolean", default: "true", description: "Hide the tooltip when the trigger is clicked." },
- { name: "forceOpen", type: "boolean", description: "Force the tooltip to stay open." },
- { name: "shouldShow", type: "boolean", description: "Externally control whether the tooltip is shown." },
- { name: "allowOverflow", type: "boolean", description: "Allow the tooltip to overflow its container." },
- { name: "overflowOnly", type: "boolean", description: "Only show the tooltip when the trigger text is overflowing." },
- { name: "tooltipClassName", type: "string", description: "CSS class for the tooltip container." },
- { name: "tooltipStyle", type: "CSSProperties", description: "Inline styles for the tooltip container." },
- { name: "tooltipContentClassName", type: "string", description: "CSS class for the tooltip content." },
- { name: "tooltipPointerClassName", type: "string", description: "CSS class for the tooltip arrow pointer." },
- { name: "positionKeyStemOverride", type: "string", internal: true, description: "Override the position key stem used for animation keying." },
- { name: "clickableOnMobile", type: "boolean", description: "Make the tooltip trigger clickable on mobile devices." },
- { name: "disableTooltipPointerEvents", type: "boolean", description: "Disable pointer events on the tooltip overlay." },
- { name: "targetElementRef", type: "RefObject", description: "Ref to an external element to position the tooltip against." },
- { name: "onTooltipShow", type: "() => void", description: "Callback when the tooltip becomes visible." },
- { name: "onTooltipHide", type: "() => void", description: "Callback when the tooltip is hidden." },
- { name: "onAnimationRest", type: "() => void", description: "Callback when the tooltip show/hide animation completes." },
- { name: "aria-label", type: "string | false", description: "Accessibility label. Set to false to disable." },
-];
-
-export default function TooltipTab() {
- return (
-
- {TooltipPositions.map(position => (
-
- {props => (
-
- )}
-
- ))}
-
- ),
- code: `
- {props => }
- `,
- relevantProps: ["position"],
- },
- {
- title: "Colors",
- description: "Five background color variants.",
- children: (
-
- {TooltipColors.map(color => (
-
- {props => (
-
- )}
-
- ))}
-
- ),
- code: '\n {props => }\n ',
- relevantProps: ["color"],
- },
- {
- title: "Delay",
- description: "Configure how long to wait before showing the tooltip.",
- children: (
-
-
- {props => (
-
- )}
-
-
- {props => (
-
- )}
-
-
- {props => (
-
- )}
-
-
- ),
- relevantProps: ["delay"],
- },
- {
- title: "Hide on Click",
- description: "By default tooltips hide when the trigger is clicked. Set hideOnClick=false to keep them visible.",
- children: (
-
-
- {props => (
-
- )}
-
-
- {props => (
-
- )}
-
-
- ),
- relevantProps: ["hideOnClick"],
- },
- {
- title: "Rich Content",
- description: "The text prop accepts a function that returns JSX for rich tooltip content.",
- children: (
-
-
(
-
-
Rich Tooltip
-
With multiple lines of content.
-
- )}>
- {props => (
-
- )}
-
-
- ),
- code: ` (
-
-
Title
-
Description text
-
-)}>
- {props => }
- `,
- relevantProps: ["text"],
- },
- ]}
- props={TOOLTIP_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/TypographyTab.tsx b/src/equicordplugins/components.dev/components/tabs/TypographyTab.tsx
deleted file mode 100644
index 2a7acead9..000000000
--- a/src/equicordplugins/components.dev/components/tabs/TypographyTab.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { CodeColors, FontSizeMap, Paragraph, TextColors, TextSizes, TextWeights } from "..";
-import { DocPage, type PropGroup } from "../DocPage";
-
-const PROP_GROUPS: PropGroup[] = [
- {
- title: "Text Colors",
- props: TextColors.map(color => ({
- name: color,
- type: "CSS variable",
- description: `var(--${color})`,
- })),
- },
- {
- title: "Text Sizes",
- props: TextSizes.map(({ name, value, pixels }) => ({
- name,
- type: "font-size",
- description: `${value} (${pixels}).`,
- })),
- },
- {
- title: "Text Weights",
- props: TextWeights.map(({ name, value }) => ({
- name,
- type: "font-weight",
- description: `font-weight: ${value}.`,
- })),
- },
- {
- title: "Code Colors",
- props: CodeColors.map(color => ({
- name: color,
- type: "CSS variable",
- description: `var(--${color})`,
- })),
- },
-];
-
-export default function TypographyTab() {
- return (
-
- {TextColors.map(color => (
-
-
- {color}
-
-
- var(--{color})
-
-
- ))}
-
- ),
- code: 'Muted text ',
- },
- {
- title: "Text Sizes",
- description: "Font sizes from xxs (10px) to xxl (32px).",
- children: (
-
- {TextSizes.map(({ name, value, pixels }) => (
-
-
- {name}
-
-
- {value} ({pixels})
-
-
- ))}
-
- ),
- },
- {
- title: "Text Weights",
- description: "Font weights from thin (100) to extrabold (800).",
- children: (
-
- {TextWeights.map(({ name, value }) => (
-
-
- {name}
-
-
- font-weight: {value}
-
-
- ))}
-
- ),
- },
- {
- title: "Code Colors",
- description: "Syntax highlighting colors for code blocks.",
- children: (
-
- {CodeColors.map(color => (
-
-
- {color}
-
-
- var(--{color})
-
-
- ))}
-
- ),
- },
- {
- title: "Usage with Components",
- description: "These values are used with Paragraph, DiscordHeading, and DiscordText. See those tabs for component-specific documentation.",
- children: (
-
-
text-default: Primary readable text.
-
text-muted: Secondary, less prominent text.
-
text-link: Clickable link text.
-
text-brand: Brand-colored text.
-
- ),
- code: `Muted text
-Brand text
-Bold heading `,
- },
- ]}
- props={PROP_GROUPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/components/tabs/UserSummaryItemTab.tsx b/src/equicordplugins/components.dev/components/tabs/UserSummaryItemTab.tsx
deleted file mode 100644
index 597ec004d..000000000
--- a/src/equicordplugins/components.dev/components/tabs/UserSummaryItemTab.tsx
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import { Paragraph, UserStore, UserSummaryItem, useState } from "..";
-import { DocPage, type PropDef } from "../DocPage";
-
-const USER_SUMMARY_PROPS: PropDef[] = [
- { name: "users", type: "(User | null)[]", required: true, description: "Array of User objects to display as avatars. Null entries render as empty slots." },
- { name: "max", type: "number", default: "10", description: "Maximum number of avatars to show before the overflow indicator." },
- { name: "count", type: "number", description: 'Override the count used in the "+N" overflow display.' },
- { name: "size", type: "16 | 24 | 32 | 56", default: "24", description: "Avatar size in pixels." },
- { name: "guildId", type: "string", description: "Guild context for server-specific avatars." },
- { name: "showUserPopout", type: "boolean", default: "false", description: "Show user popout when an avatar is clicked." },
- { name: "showDefaultAvatarsForNullUsers", type: "boolean", description: "Render default avatars for null entries in the users array." },
- { name: "renderUser", type: "(user, isLast, index) => ReactNode", description: "Custom render function for each user avatar." },
- { name: "renderMoreUsers", type: "(text, count) => ReactNode", description: 'Custom render function for the "+N" overflow indicator.' },
- { name: "renderIcon", type: "boolean", description: "Whether to render an icon." },
- { name: "renderLeadingIcon", type: "(className) => ReactNode", description: "Render a leading icon before the user avatars." },
- { name: "dimEmptyUsers", type: "boolean", description: "Dim null user slots." },
- { name: "hideMoreUsers", type: "boolean", default: "false", description: 'Hide the "+N" overflow count.' },
- { name: "useFallbackUserForPopout", type: "boolean", description: "Use fallback user data for popout when user data is unavailable." },
- { name: "extraDetail", type: "ReactNode", description: "Additional content rendered after the avatars." },
- { name: "className", type: "string", description: "CSS class for the container." },
-];
-
-function MaxUsersDemo() {
- const currentUser = UserStore.getCurrentUser();
- const users = currentUser ? Array(5).fill(currentUser) : [];
-
- return (
-
- {[2, 3, 5].map(max => (
-
- ))}
-
- );
-}
-
-function SizesDemo() {
- const currentUser = UserStore.getCurrentUser();
- const users = currentUser ? Array(5).fill(currentUser) : [];
-
- return (
-
- {([16, 24, 32, 56] as const).map(size => (
-
- ))}
-
- );
-}
-
-function OverrideCountDemo() {
- const currentUser = UserStore.getCurrentUser();
- const users = currentUser ? Array(3).fill(currentUser) : [];
- const [count, setCount] = useState(42);
-
- return (
-
- );
-}
-
-export default function UserSummaryItemTab() {
- const currentUser = UserStore.getCurrentUser();
- const users = currentUser ? Array(5).fill(currentUser) : [];
-
- return (
-
- ),
- code: `const users = [user1, user2, user3, user4, user5];
- `,
- relevantProps: ["users", "max"],
- },
- {
- title: "Sizes",
- description: "Four avatar sizes: 16, 24, 32, and 56 pixels.",
- children: ,
- code: " ",
- relevantProps: ["size"],
- },
- {
- title: "Max Users",
- description: "Control how many avatars are visible before the overflow count.",
- children: ,
- relevantProps: ["max"],
- },
- {
- title: "Override Count",
- description: 'The count prop overrides the number shown in the "+N" indicator, useful when the total is different from users.length.',
- children: ,
- relevantProps: ["count"],
- },
- {
- title: "User Popout",
- description: "Enable user popout on avatar click with showUserPopout.",
- children: (
-
- ),
- code: " ",
- relevantProps: ["showUserPopout"],
- },
- {
- title: "Hide Overflow",
- description: 'Hide the "+N" overflow indicator entirely.',
- children: (
-
-
-
hideMoreUsers=false:
-
-
-
-
hideMoreUsers=true:
-
-
-
- ),
- relevantProps: ["hideMoreUsers"],
- },
- ]}
- props={USER_SUMMARY_PROPS}
- />
- );
-}
diff --git a/src/equicordplugins/components.dev/constants.ts b/src/equicordplugins/components.dev/constants.ts
deleted file mode 100644
index faad5dda5..000000000
--- a/src/equicordplugins/components.dev/constants.ts
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export const ManaButtonVariants = ["primary", "secondary", "critical-primary", "critical-secondary", "active", "overlay-primary", "overlay-secondary", "expressive"] as const;
-export type ManaButtonVariant = typeof ManaButtonVariants[number];
-
-export const ManaButtonSizes = ["xs", "sm", "md"] as const;
-export type ManaButtonSize = typeof ManaButtonSizes[number];
-
-export const ManaTextButtonVariants = ["primary", "secondary", "always-white", "critical"] as const;
-export type ManaTextButtonVariant = typeof ManaTextButtonVariants[number];
-
-export const AvatarSizes = ["SIZE_16", "SIZE_20", "SIZE_24", "SIZE_32", "SIZE_40", "SIZE_44", "SIZE_48", "SIZE_56", "SIZE_72", "SIZE_80", "SIZE_96", "SIZE_120", "SIZE_152"] as const;
-export type AvatarSize = typeof AvatarSizes[number];
-
-export const AvatarStatuses = ["online", "idle", "dnd", "offline", "streaming"] as const;
-export type AvatarStatus = typeof AvatarStatuses[number];
-
-export const GuildIconSizes = [16, 20, 24, 32, 40, 48, 56, 80, 96] as const;
-export type GuildIconSize = typeof GuildIconSizes[number];
-
-export const CardVariants = ["primary", "warning", "danger", "success", "brand"] as const;
-export type CardVariant = typeof CardVariants[number];
-
-export const SpinnerTypes = ["wanderingCubes", "chasingDots", "pulsingEllipsis", "spinningCircle", "spinningCircleSimple", "lowMotion"] as const;
-export type SpinnerType = typeof SpinnerTypes[number];
-
-export const TooltipPositions = ["top", "bottom", "left", "right"] as const;
-export type TooltipPosition = typeof TooltipPositions[number];
-
-export const TooltipAligns = ["start", "center", "end"] as const;
-export type TooltipAlign = typeof TooltipAligns[number];
-
-export const TooltipColors = ["primary", "grey", "brand", "green", "red"] as const;
-export type TooltipColor = typeof TooltipColors[number];
-
-export const TextInputSizes = ["sm", "md"] as const;
-export type TextInputSize = typeof TextInputSizes[number];
-
-export const TimestampFormats = [
- { format: "R", label: "Relative", example: "2 hours ago" },
- { format: "t", label: "Short Time", example: "9:30 PM" },
- { format: "T", label: "Long Time", example: "9:30:00 PM" },
- { format: "d", label: "Short Date", example: "01/20/2024" },
- { format: "D", label: "Long Date", example: "January 20, 2024" },
- { format: "f", label: "Short DateTime", example: "January 20, 2024 9:30 PM" },
- { format: "F", label: "Long DateTime", example: "Saturday, January 20, 2024 9:30 PM" },
-] as const;
-
-export const ModalSizes = [
- { size: "small", width: "440px" },
- { size: "medium", width: "600px" },
- { size: "large", width: "720px" },
- { size: "dynamic", width: "fit-content" },
-] as const;
-export type ModalSize = typeof ModalSizes[number]["size"];
-
-export const TextColors = [
- "text-default", "text-muted", "text-subtle", "text-strong", "text-normal",
- "text-link", "text-brand", "text-disabled", "text-invert",
- "text-feedback-critical", "text-feedback-warning", "text-feedback-info", "text-feedback-positive",
- "text-status-online", "text-status-idle", "text-status-dnd", "text-status-offline",
- "text-overlay-dark", "text-overlay-light",
-] as const;
-export type TextColorType = typeof TextColors[number];
-
-export const TextSizes = [
- { name: "xxs", value: "0.625rem", pixels: "10px" },
- { name: "xs", value: "0.75rem", pixels: "12px" },
- { name: "sm", value: "0.875rem", pixels: "14px" },
- { name: "md", value: "1rem", pixels: "16px" },
- { name: "lg", value: "1.25rem", pixels: "20px" },
- { name: "xl", value: "1.5rem", pixels: "24px" },
- { name: "xxl", value: "2rem", pixels: "32px" },
-] as const;
-export type TextSizeType = typeof TextSizes[number]["name"];
-
-export const TextWeights = [
- { name: "thin", value: "100" },
- { name: "extralight", value: "200" },
- { name: "light", value: "300" },
- { name: "normal", value: "400" },
- { name: "medium", value: "500" },
- { name: "semibold", value: "600" },
- { name: "bold", value: "700" },
- { name: "extrabold", value: "800" },
-] as const;
-export type TextWeightType = typeof TextWeights[number]["name"];
-
-export const TextVariants = [
- "text-xxl/bold", "text-xxl/semibold", "text-xxl/medium", "text-xxl/normal",
- "text-xl/bold", "text-xl/semibold", "text-xl/medium", "text-xl/normal",
- "text-lg/bold", "text-lg/semibold", "text-lg/medium", "text-lg/normal",
- "text-md/bold", "text-md/semibold", "text-md/medium", "text-md/normal",
- "text-sm/bold", "text-sm/semibold", "text-sm/medium", "text-sm/normal",
- "text-xs/bold", "text-xs/semibold", "text-xs/medium", "text-xs/normal",
-] as const;
-export type TextVariantType = typeof TextVariants[number];
-
-export const HeadingVariants = [
- "heading-xxl/extrabold", "heading-xxl/bold", "heading-xxl/semibold", "heading-xxl/medium", "heading-xxl/normal",
- "heading-xl/extrabold", "heading-xl/bold", "heading-xl/semibold", "heading-xl/medium",
- "heading-lg/extrabold", "heading-lg/bold", "heading-lg/semibold", "heading-lg/medium",
- "heading-md/bold", "heading-md/semibold", "heading-md/medium", "heading-md/normal",
- "heading-sm/bold", "heading-sm/semibold", "heading-sm/medium",
-] as const;
-export type HeadingVariantType = typeof HeadingVariants[number];
-
-export const CodeColors = [
- "text-code", "text-code-keyword", "text-code-string", "text-code-comment",
- "text-code-builtin", "text-code-variable", "text-code-tag", "text-code-title",
- "text-code-section", "text-code-bullet", "text-code-addition", "text-code-deletion",
-] as const;
-export type CodeColorType = typeof CodeColors[number];
-
-export const NoticeTypes = ["info", "warn", "danger", "positive", "preview"] as const;
-export type NoticeTypeValue = typeof NoticeTypes[number];
-
-export const PresetColors = [
- 0x5865F2, 0x3BA55C, 0xFAA61A, 0xED4245, 0xEB459E,
- 0x9B59B6, 0x3498DB, 0x1ABC9C, 0xE67E22, 0x2ECC71,
-] as const;
-
-export const FontSizeMap: Record = {
- xxs: "0.625rem",
- xs: "0.75rem",
- sm: "0.875rem",
- md: "1rem",
- lg: "1.25rem",
- xl: "1.5rem",
- xxl: "2rem",
-};
-
-export const ManaTextButtonTextVariants = [
- "text-xs/normal", "text-sm/normal", "text-sm/medium",
- "text-md/normal", "text-md/medium", "text-lg/medium",
-] as const;
-export type ManaTextButtonTextVariant = typeof ManaTextButtonTextVariants[number];
-
-export const TimestampDisplayFormats = [
- { format: "LT", description: "Time (e.g., 8:30 PM)" },
- { format: "LTS", description: "Time with seconds (e.g., 8:30:25 PM)" },
- { format: "L", description: "Date (e.g., 09/04/1986)" },
- { format: "LL", description: "Date with month name (e.g., September 4, 1986)" },
- { format: "LLL", description: "Date and time (e.g., September 4, 1986 8:30 PM)" },
- { format: "LLLL", description: "Full date and time (e.g., Thursday, September 4, 1986 8:30 PM)" },
- { format: "l", description: "Short date (e.g., 9/4/1986)" },
- { format: "ll", description: "Short date with month (e.g., Sep 4, 1986)" },
- { format: "lll", description: "Short date and time (e.g., Sep 4, 1986 8:30 PM)" },
- { format: "llll", description: "Short full date and time (e.g., Thu, Sep 4, 1986 8:30 PM)" },
-] as const;
-export type TimestampDisplayFormat = typeof TimestampDisplayFormats[number]["format"];
-
-export const CheckboxLabelTypes = ["primary", "secondary"] as const;
-export type CheckboxLabelType = typeof CheckboxLabelTypes[number];
-
-export const CheckboxUsageVariants = ["single", "indicator"] as const;
-export type CheckboxUsageVariant = typeof CheckboxUsageVariants[number];
-
-export const PopoverSizes = ["sm", "md", "lg"] as const;
-export type PopoverSize = typeof PopoverSizes[number];
-
-export const SliderOrientations = ["horizontal", "vertical"] as const;
-export type SliderOrientation = typeof SliderOrientations[number];
-
-export const ToastType = {
- MESSAGE: "message",
- SUCCESS: "success",
- FAILURE: "failure",
- CUSTOM: "custom",
- CLIP: "clip",
- LINK: "link",
- FORWARD: "forward",
- BOOKMARK: "bookmark",
- CLOCK: "clock",
-} as const;
-
-export const ToastPosition = {
- TOP: 0,
- BOTTOM: 1,
-} as const;
diff --git a/src/equicordplugins/components.dev/index.tsx b/src/equicordplugins/components.dev/index.tsx
deleted file mode 100644
index 2c6633786..000000000
--- a/src/equicordplugins/components.dev/index.tsx
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import "./styles.css";
-
-import { ComponentsIcon } from "@components/Icons";
-import SettingsPlugin from "@plugins/_core/settings";
-import { Devs } from "@utils/constants";
-import { removeFromArray } from "@utils/misc";
-import definePlugin, { StartAt } from "@utils/types";
-import { SettingsRouter } from "@webpack/common";
-
-import { ChipProps, ColorPickerProps, ManaBaseRadioGroupProps, ManaCalendarProps, ManaComboboxProps, ManaDatePickerProps, ManaSwitchProps, SimpleErrorBoundaryProps, SkeletonProps, StandaloneRadioIndicatorProps } from "./components";
-import ComponentsTab from "./components/ComponentsTab";
-
-export let Skeleton: React.ComponentType;
-export let Chip: React.ComponentType;
-export let StandaloneRadioIndicator: React.ComponentType;
-export let ManaCombobox: React.ComponentType;
-export let ManaBaseRadioGroup: React.ComponentType;
-export let ManaDatePicker: React.ComponentType;
-export let ManaCalendar: React.ComponentType;
-export let ManaSwitch: React.ComponentType;
-export let SimpleErrorBoundary: React.ComponentType;
-
-export let ColorPicker: React.ComponentType = () => null;
-export function setColorPicker(component: React.ComponentType) {
- ColorPicker = component;
-}
-
-export default definePlugin({
- name: "Components",
- description: "Adds a new tab to settings to browse Discord components.",
- tags: ["Appearance", "Customisation", "Console", "Developers", "Organisation"],
- authors: [Devs.prism],
- dependencies: ["Settings"],
- patches: [
- {
- find: /withHeader:\i=!0,size:/,
- replacement: {
- match: /(?=function (\i)\(\i\)\{.{0,50}withHeader:\i=!0)/,
- replace: "$self.Skeleton=$1;"
- }
- },
- {
- find: '="grayLight"}',
- replacement: {
- match: /(?=function (\i)\(\i\)\{.{0,25}="grayLight"\})/,
- replace: "$self.Chip=$1;"
- }
- },
- {
- find: ".standaloneRadioIndicator,",
- replacement: {
- match: /(?=function (\i)\(\i\)\{.{0,15}disabled:\i,isSelected:\i\})/,
- replace: "$self.StandaloneRadioIndicator=$1;"
- }
- },
- {
- find: "#{intl::AUTOCOMPLETE_NO_RESULTS_BODY}",
- replacement: {
- match: /(?<=data-listbox-item-id".*?itemToString:\i\}\);)(?=function (\i)\(\i\)\{)/,
- replace: "$self.ManaCombobox=$1;"
- }
- },
- {
- find: '"data-mana-component":"BaseRadioGroup"',
- replacement: {
- match: /(?=function (\i)\(\i\)\{.{0,400}"data-mana-component":"BaseRadioGroup")/,
- replace: "$self.ManaBaseRadioGroup=$1;"
- }
- },
- {
- find: '"data-mana-component":"date-picker"',
- replacement: {
- match: /(?=function (\i)\(\i\)\{.{0,60},placeholderValue:\i)/,
- replace: "$self.ManaDatePicker=$1;"
- }
- },
- {
- find: '"data-mana-component":"calendar"',
- replacement: {
- match: /(?=function (\i)\(\i\)\{.{0,400}"data-mana-component":"calendar")/,
- replace: "$self.ManaCalendar=$1;"
- }
- },
- {
- find: '"data-mana-component":"switch"',
- replacement: {
- match: /(?=function (\i)\(\i\)\{.{0,50}focusProps:\i,hasIcon:)/,
- replace: "$self.ManaSwitch=$1;"
- }
- },
- {
- find: '"data-mana-component":"switch"',
- replacement: {
- match: /(?=function (\i)\(\i\)\{.{0,50}focusProps:\i,hasIcon:)/,
- replace: "$self.ManaSwitch=$1;"
- }
- },
- {
- find: "#{intl::zksHZO::raw}",
- replacement: {
- match: /(?<=class (\i).{0,90}getDerivedStateFromError.*?this.props.children\}\})/,
- replace: "$self.SimpleErrorBoundary=$1;"
- }
- },
- {
- find: "#{intl::USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR}),focusProps:",
- replacement: {
- match: /(?=function (\i)\(\i\)\{let\{onChange:\i,onClose:\i,[^}]+?showEyeDropper:)/,
- replace: "$self.setColorPicker($1);"
- }
- },
- ],
- set Skeleton(value: any) {
- Skeleton = value;
- },
- set Chip(value: any) {
- Chip = value;
- },
- set StandaloneRadioIndicator(value: any) {
- StandaloneRadioIndicator = value;
- },
- set ManaCombobox(value: any) {
- ManaCombobox = value;
- },
- set ManaBaseRadioGroup(value: any) {
- ManaBaseRadioGroup = value;
- },
- set ManaDatePicker(value: any) {
- ManaDatePicker = value;
- },
- set ManaCalendar(value: any) {
- ManaCalendar = value;
- },
- set ManaSwitch(value: any) {
- ManaSwitch = value;
- },
- set SimpleErrorBoundary(value: any) {
- SimpleErrorBoundary = value;
- },
- setColorPicker,
- startAt: StartAt.WebpackReady,
- toolboxActions: {
- "Open Components Tab"() {
- SettingsRouter.openUserSettings("equicord_components_panel");
- },
- },
- start() {
- SettingsPlugin.customEntries.push({
- key: "equicord_components",
- title: "Components",
- Component: ComponentsTab,
- Icon: ComponentsIcon
- });
- },
- stop() {
- removeFromArray(SettingsPlugin.customEntries, e => e.key === "equicord_components");
- },
-});
diff --git a/src/equicordplugins/components.dev/styles.css b/src/equicordplugins/components.dev/styles.css
deleted file mode 100644
index a9d47b6f7..000000000
--- a/src/equicordplugins/components.dev/styles.css
+++ /dev/null
@@ -1,314 +0,0 @@
-/* ── Search & Tab Navigation ── */
-
-.vc-compfinder-search {
- margin-bottom: 40px;
-}
-
-.vc-compfinder-tabbar {
- margin-bottom: 16px;
- flex-wrap: wrap !important;
- gap: 8px 16px;
-}
-
-.vc-compfinder-tabbar > div {
- flex-wrap: wrap !important;
- gap: 8px 16px;
-}
-
-.vc-compfinder-tab {
- padding: 8px 12px;
- margin: 0 !important;
-}
-
-.vc-compfinder-content {
- padding-top: 16px;
-}
-
-/* ── Shared Utility Layouts ── */
-
-.vc-compfinder-section {
- display: flex;
- flex-direction: column;
- gap: 8px;
-}
-
-.vc-compfinder-section-block > :nth-child(n+3) {
- margin-top: 8px;
-}
-
-.vc-compfinder-grid {
- display: flex;
- flex-wrap: wrap;
- gap: 8px;
- align-items: center;
-}
-
-.vc-compfinder-grid-vertical {
- display: flex;
- flex-direction: column;
- gap: 8px;
-}
-
-.vc-compfinder-switch-item {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 8px 12px;
- background: rgb(0 0 0 / 15%);
- border-radius: 4px;
-}
-
-.vc-compfinder-demo-button {
- padding: 8px 16px;
- background: rgb(0 0 0 / 15%);
- border: 1px solid rgb(255 255 255 / 6%);
- border-radius: 4px;
- color: var(--text-default);
- cursor: pointer;
-}
-
-.vc-compfinder-demo-button:hover {
- background: rgb(0 0 0 / 25%);
-}
-
-/* ── Modal Demo Helpers ── */
-
-.vc-compfinder-modal-header {
- display: flex;
- align-items: flex-start;
- position: relative;
-}
-
-.vc-compfinder-modal-header-content {
- display: flex;
- flex-direction: column;
- gap: 4px;
- flex: 1;
-}
-
-.vc-compfinder-modal-close {
- position: absolute;
- top: 0;
- right: 0;
-}
-
-.vc-compfinder-modal-content {
- padding-bottom: var(--space-16);
-}
-
-.vc-compfinder-modal-footer {
- display: flex;
- flex-direction: row-reverse;
- gap: 8px;
-}
-
-.vc-alert-danger-btn {
- color: var(--white-500);
- background-color: var(--button-danger-background);
-}
-
-/* ── DocPage Layout ── */
-
-.vc-compfinder-doc-page {
- display: flex;
- flex-direction: column;
- gap: 16px;
-}
-
-.vc-compfinder-doc-page > .vc-divider {
- margin: 8px 0;
-}
-
-.vc-compfinder-doc-title {
- margin-bottom: -8px;
-}
-
-.vc-compfinder-doc-section {
- display: flex;
- flex-direction: column;
- gap: 12px;
-}
-
-.vc-compfinder-doc-section [id] {
- scroll-margin-top: 16px;
-}
-
-.vc-compfinder-doc-demo {
- padding: 16px;
-}
-
-.vc-compfinder-doc-relevant-props {
- margin-top: 8px;
-}
-
-.vc-compfinder-doc-prop-group {
- margin-bottom: 16px;
-}
-
-.vc-compfinder-doc-example {
- display: flex;
- flex-direction: column;
- gap: 4px;
-}
-
-.vc-compfinder-doc-example + .vc-compfinder-doc-example {
- margin-top: 12px;
-}
-
-/* ── Import Block ── */
-
-.vc-compfinder-import-block {
- display: flex;
- flex-direction: column;
- gap: 6px;
-}
-
-.vc-compfinder-import-label {
- text-transform: uppercase;
- letter-spacing: 0.05em;
-}
-
-/* ── Table of Contents ── */
-
-.vc-compfinder-toc {
- display: flex;
- flex-direction: column;
- gap: 6px;
-}
-
-.vc-compfinder-toc-label {
- text-transform: uppercase;
- letter-spacing: 0.05em;
-}
-
-.vc-compfinder-toc-links {
- display: flex;
- flex-wrap: wrap;
- gap: 2px 12px;
-}
-
-.vc-compfinder-toc-link {
- color: var(--text-link);
- font-size: 0.8125rem;
- text-decoration: none;
- cursor: pointer;
- line-height: 1.6;
-}
-
-.vc-compfinder-toc-link:hover {
- text-decoration: underline;
-}
-
-/* ── Props Table ── */
-
-.vc-compfinder-table-wrapper {
- overflow-x: auto;
-}
-
-.vc-compfinder-table {
- width: 100%;
- border-collapse: collapse;
- font-size: 0.75rem;
-}
-
-.vc-compfinder-table th {
- text-align: left;
- padding: 8px 12px;
- font-size: 0.625rem;
- font-weight: 700;
- text-transform: uppercase;
- letter-spacing: 0.05em;
- color: var(--text-muted);
- background: rgb(0 0 0 / 20%);
- border-bottom: 1px solid rgb(255 255 255 / 6%);
- vertical-align: middle;
-}
-
-.vc-compfinder-table td {
- padding: 8px 12px;
- color: var(--text-default);
- vertical-align: middle;
-}
-
-.vc-compfinder-table tbody tr:nth-child(odd) {
- background: rgb(0 0 0 / 8%);
-}
-
-.vc-compfinder-table tbody tr:nth-child(even) {
- background: rgb(0 0 0 / 15%);
-}
-
-.vc-compfinder-table code.inline {
- padding: 1px 4px !important;
- font-size: 0.625rem !important;
- line-height: 1.3;
- white-space: nowrap;
-}
-
-.vc-compfinder-doc-page code.inline {
- padding: 2px 5px;
- font-size: 0.75rem;
-}
-
-.vc-compfinder-doc-page pre code {
- font-size: 0.75rem !important;
-}
-
-.vc-compfinder-table td:nth-child(2) {
- white-space: nowrap;
-}
-
-.vc-compfinder-table-field {
- font-weight: 600;
- font-size: 0.75rem;
- color: var(--text-default);
- font-family: var(--font-code);
- white-space: nowrap;
-}
-
-.vc-compfinder-table-row-required td:first-child {
- border-left: 3px solid var(--status-positive);
- padding-left: 9px;
-}
-
-.vc-compfinder-table-row-internal td:first-child {
- border-left: 3px solid var(--status-warning);
- padding-left: 9px;
-}
-
-.vc-compfinder-table-legend {
- display: flex;
- gap: 16px;
- margin-top: 8px;
-}
-
-.vc-compfinder-table-legend-item {
- display: flex;
- align-items: center;
- gap: 6px;
- font-size: 0.6875rem;
- color: var(--text-muted);
-}
-
-.vc-compfinder-table-legend-bar {
- width: 3px;
- height: 12px;
- border-radius: 1px;
-}
-
-.vc-compfinder-table-legend-required {
- background: var(--status-positive);
-}
-
-.vc-compfinder-table-legend-internal {
- background: var(--status-warning);
-}
-
-.vc-compfinder-table-dash {
- color: var(--text-faint);
-}
-
-.vc-compfinder-table-desc {
- color: var(--text-muted);
- line-height: 1.4;
-}
\ No newline at end of file
diff --git a/src/equicordplugins/components.dev/types/accordion.d.ts b/src/equicordplugins/components.dev/types/accordion.d.ts
deleted file mode 100644
index 6a8690965..000000000
--- a/src/equicordplugins/components.dev/types/accordion.d.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface AccordionProps {
- icon?: React.ReactNode;
- title: string;
- subtitle?: string;
- children: React.ReactNode;
- className?: string;
- isExpanded?: boolean;
- onExpandedChange?: (expanded: boolean) => void;
- defaultExpanded?: boolean;
- onOpen?: () => void;
- maxHeight?: number | string;
-}
diff --git a/src/equicordplugins/components.dev/types/alert.d.ts b/src/equicordplugins/components.dev/types/alert.d.ts
deleted file mode 100644
index ee7d04dd6..000000000
--- a/src/equicordplugins/components.dev/types/alert.d.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface AlertOptions {
- title: string;
- body: React.ReactNode;
- confirmText?: string;
- cancelText?: string;
- confirmVariant?: "primary" | "critical-primary" | "expressive";
- onConfirm?: () => void;
- onCancel?: () => void;
- onCloseCallback?: () => void;
- contextKey?: string;
-}
-
-export interface AlertsType {
- show: (options: AlertOptions) => void;
- close: () => void;
- confirm: (options: AlertOptions) => Promise;
-}
diff --git a/src/equicordplugins/components.dev/types/anchor.d.ts b/src/equicordplugins/components.dev/types/anchor.d.ts
deleted file mode 100644
index 17d29c018..000000000
--- a/src/equicordplugins/components.dev/types/anchor.d.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface AnchorProps extends React.AnchorHTMLAttributes {
- href?: string;
- onClick?: React.MouseEventHandler;
- className?: string;
- children?: React.ReactNode;
- rel?: string;
- target?: string;
- useDefaultUnderlineStyles?: boolean;
- title?: string;
- style?: React.CSSProperties;
- focusProps?: Record;
- ref?: React.Ref;
-}
diff --git a/src/equicordplugins/components.dev/types/avatar.d.ts b/src/equicordplugins/components.dev/types/avatar.d.ts
deleted file mode 100644
index 50fdc530a..000000000
--- a/src/equicordplugins/components.dev/types/avatar.d.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { AvatarSize, AvatarStatus } from "../constants";
-
-export type { AvatarSize, AvatarStatus };
-
-export interface AvatarSizeConfig {
- size: number;
- status: number;
- stroke: number;
- offset: number;
-}
-
-export interface AvatarProps {
- src?: string;
- size?: AvatarSize;
- status?: AvatarStatus;
- statusColor?: string;
- statusBackdropColor?: string;
- isMobile?: boolean;
- isVR?: boolean;
- isTyping?: boolean;
- isSpeaking?: boolean;
- isLatched?: boolean;
- voiceDb?: number;
- speakingStylesConfig?: Record;
- statusTooltip?: boolean;
- statusTooltipDelay?: number;
- typingIndicatorRef?: React.Ref;
- avatarContentRef?: React.Ref;
- CutoutIcon?: React.ComponentType;
- avatarTooltipAsset?: React.ReactNode;
- avatarTooltipText?: string;
- avatarTooltipTitle?: string;
- avatarDecoration?: string;
- "aria-hidden"?: boolean;
- "aria-label"?: string;
- imageClassName?: string;
- className?: string;
- onClick?: React.MouseEventHandler;
- onMouseDown?: React.MouseEventHandler;
- onKeyDown?: React.KeyboardEventHandler;
- onContextMenu?: React.MouseEventHandler;
- onMouseEnter?: React.MouseEventHandler;
- onMouseLeave?: React.MouseEventHandler;
- tabIndex?: number;
- ref?: React.Ref;
-}
diff --git a/src/equicordplugins/components.dev/types/badge.d.ts b/src/equicordplugins/components.dev/types/badge.d.ts
deleted file mode 100644
index 3f58a57d2..000000000
--- a/src/equicordplugins/components.dev/types/badge.d.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface BadgeShapesType {
- ROUND: string;
- ROUND_LEFT: string;
- ROUND_RIGHT: string;
- SQUARE: string;
-}
-
-export interface NumberBadgeProps extends Omit, "children"> {
- count: number;
- color?: string;
- disableColor?: boolean;
- shape?: string;
- className?: string;
- style?: React.CSSProperties;
- renderBadgeCount?: (count: number) => string;
-}
-
-export interface TextBadgeProps extends Omit, "children"> {
- text: string;
- color?: string;
- disableColor?: boolean;
- shape?: string;
- className?: string;
- style?: React.CSSProperties;
-}
-
-export interface IconBadgeProps {
- icon: React.ComponentType<{ className?: string; color?: string; }>;
- color?: string;
- disableColor?: boolean;
- shape?: string;
- className?: string;
- style?: React.CSSProperties;
-}
-
-export interface CircleBadgeProps extends Omit, "children"> {
- color?: string;
- disableColor?: boolean;
- shape?: string;
- className?: string;
- style?: React.CSSProperties;
-}
-
-export interface PremiumBadgeProps extends Omit, "children"> {
- text: string;
- className?: string;
- color?: string;
- disableColor?: boolean;
- shape?: string;
- style?: React.CSSProperties;
-}
diff --git a/src/equicordplugins/components.dev/types/button.d.ts b/src/equicordplugins/components.dev/types/button.d.ts
deleted file mode 100644
index c8a4caf27..000000000
--- a/src/equicordplugins/components.dev/types/button.d.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { ManaButtonSize, ManaButtonVariant, ManaTextButtonVariant } from "../constants";
-
-export type { ManaButtonSize, ManaButtonVariant, ManaTextButtonVariant };
-
-export type ManaButtonIconType =
- | React.ComponentType
- | { type: "icon"; asset: React.ComponentType; }
- | { type: "rive"; asset: React.ComponentType; riveProps?: Record; }
- | { type: "sticker"; asset: any; component: React.ComponentType; };
-
-export interface ManaButtonProps {
- text?: string;
- variant?: ManaButtonVariant;
- size?: ManaButtonSize;
- disabled?: boolean;
- loading?: boolean;
- loadingStartedLabel?: string;
- loadingFinishedLabel?: string;
- fullWidth?: boolean;
- rounded?: boolean;
- icon?: ManaButtonIconType;
- iconPosition?: "start" | "end";
- iconOpticalOffsetMargin?: number;
- minWidth?: number | string;
- role?: string;
- type?: "button" | "submit" | "reset";
- rel?: string;
- onClick?: (e: React.MouseEvent) => void;
- onDoubleClick?: (e: React.MouseEvent) => void;
- onMouseEnter?: (e: React.MouseEvent) => void;
- onMouseLeave?: (e: React.MouseEvent) => void;
- onMouseUp?: (e: React.MouseEvent) => void;
- onMouseDown?: (e: React.MouseEvent) => void;
- onKeyDown?: (e: React.KeyboardEvent) => void;
- focusProps?: Record;
- buttonRef?: React.Ref;
- className?: string;
- style?: React.CSSProperties;
-}
-
-export interface ManaTextButtonProps {
- text: string;
- variant?: ManaTextButtonVariant;
- textVariant?: string;
- lineClamp?: number;
- role?: string;
- type?: "button" | "submit" | "reset";
- onClick?: (e: React.MouseEvent) => void;
- disabled?: boolean;
- focusProps?: Record;
- buttonRef?: React.Ref;
- className?: string;
- style?: React.CSSProperties;
-}
diff --git a/src/equicordplugins/components.dev/types/calendar.d.ts b/src/equicordplugins/components.dev/types/calendar.d.ts
deleted file mode 100644
index 1de325466..000000000
--- a/src/equicordplugins/components.dev/types/calendar.d.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface ManaCalendarProps {
- value?: any;
- onChange?: (value: any) => void;
- minValue?: any;
- maxValue?: any;
- disabled?: boolean;
- readOnly?: boolean;
- className?: string;
- "aria-label"?: string;
-}
-
-export interface ManaDatePickerProps {
- value?: any;
- onChange?: (value: any) => void;
- minValue?: any;
- maxValue?: any;
- placeholderValue?: any;
- granularity?: "day" | "hour" | "minute" | "second";
- hourCycle?: 12 | 24;
- hideTimeZone?: boolean;
- disabled?: boolean;
- required?: boolean;
- label?: string;
- hideLabel?: boolean;
- badge?: React.ReactNode;
- icon?: React.ReactNode;
- description?: string;
- helperText?: string;
- errorMessage?: string;
- successMessage?: string;
- id?: string;
- layout?: string;
- layoutConfig?: Record;
-}
diff --git a/src/equicordplugins/components.dev/types/checkbox.d.ts b/src/equicordplugins/components.dev/types/checkbox.d.ts
deleted file mode 100644
index 5b891e55a..000000000
--- a/src/equicordplugins/components.dev/types/checkbox.d.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { CheckboxLabelType, CheckboxUsageVariant } from "../constants";
-
-export type { CheckboxLabelType, CheckboxUsageVariant };
-
-export interface ManaCheckboxProps {
- checked: boolean;
- onChange?: (checked: boolean) => void;
- disabled?: boolean;
- displayOnly?: boolean;
- label?: string;
- description?: string;
- leadingIcon?: React.ComponentType;
- labelType?: CheckboxLabelType;
- usageVariant?: CheckboxUsageVariant;
- value?: string | number;
- labeledBy?: string;
-}
-
-export interface CheckboxGroupOption {
- value: string | number;
- label: string;
- description?: string;
- disabled?: boolean;
- leadingIcon?: React.ComponentType;
-}
-
-export interface ManaCheckboxGroupProps {
- options: CheckboxGroupOption[];
- selectedValues: (string | number)[];
- onChange?: (values: (string | number)[]) => void;
- disabled?: boolean;
- label?: string;
- hideLabel?: boolean;
- badge?: React.ReactNode;
- icon?: React.ReactNode;
- required?: boolean;
- description?: string;
- helperText?: string;
- errorMessage?: string;
- successMessage?: string;
- id?: string;
- layout?: string;
- layoutConfig?: Record;
-}
diff --git a/src/equicordplugins/components.dev/types/chip.d.ts b/src/equicordplugins/components.dev/types/chip.d.ts
deleted file mode 100644
index 7f931d72f..000000000
--- a/src/equicordplugins/components.dev/types/chip.d.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export type ChipVariant =
- | "blurpleLight" | "blurpleMedium" | "blurpleDark"
- | "purpleLight" | "purpleMedium" | "purpleDark"
- | "greenLight" | "greenMedium" | "greenDark"
- | "orangeLight" | "orangeMedium" | "orangeDark"
- | "yellowLight" | "yellowMedium" | "yellowDark"
- | "pinkLight" | "pinkMedium" | "pinkDark"
- | "redLight" | "redMedium" | "redDark"
- | "grayLight" | "grayMedium" | "grayDark";
-
-export interface ChipProps {
- text: string;
- variant?: ChipVariant;
-}
diff --git a/src/equicordplugins/components.dev/types/clickable.d.ts b/src/equicordplugins/components.dev/types/clickable.d.ts
deleted file mode 100644
index c6ab2b8eb..000000000
--- a/src/equicordplugins/components.dev/types/clickable.d.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface ClickableProps extends React.HTMLAttributes {
- tag?: keyof React.JSX.IntrinsicElements;
- focusProps?: Record;
- innerRef?: React.Ref;
- onClick?: React.MouseEventHandler;
- role?: string;
- tabIndex?: number;
- ignoreKeyPress?: boolean;
- className?: string;
- children?: React.ReactNode;
- href?: string;
- onKeyPress?: React.KeyboardEventHandler;
-}
diff --git a/src/equicordplugins/components.dev/types/colorpicker.d.ts b/src/equicordplugins/components.dev/types/colorpicker.d.ts
deleted file mode 100644
index 3fa8f5c8f..000000000
--- a/src/equicordplugins/components.dev/types/colorpicker.d.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface ColorPickerProps {
- color: number;
- onChange: (color: number) => void;
- onClose?: () => void;
- suggestedColors?: string[];
- disabled?: boolean;
- label?: React.ReactNode;
- colorPickerMiddle?: React.ReactNode;
- colorPickerFooter?: React.ReactNode;
- showEyeDropper?: boolean;
-}
-
-export interface ColorSwatchProps {
- color?: number;
- isDefault?: boolean;
- isCustom?: boolean;
- isSelected?: boolean;
- disabled?: boolean;
- style?: React.CSSProperties;
- onClick?: (colorOrGradient: number | { start: number; end: number; }) => void;
- isGradient?: boolean;
- "aria-label"?: string;
- gradientStart?: number;
- gradientEnd?: number;
- gradientDegrees?: number;
-}
-
-export interface DefaultColorButtonProps {
- color: number;
- onChange: (color: number) => void;
- value: number;
- disabled?: boolean;
- allowBlackCustomColor?: boolean;
-}
-
-export interface CustomColorButtonProps {
- customColor?: number;
- value: number;
- disabled?: boolean;
- "aria-label"?: string;
- presets: number[];
-}
-
-export interface GradientColor {
- start: number;
- end: number;
- name?: string;
-}
-
-export interface ColorPickerWithSwatchesProps {
- className?: string;
- defaultColor: number;
- customColor?: number;
- colors: number[] | GradientColor[];
- value: number;
- secondaryValue?: number;
- disabled?: boolean;
- onChange: (color: number, secondaryColor?: number) => void;
- renderDefaultButton?: (props: DefaultColorButtonProps) => React.ReactNode;
- renderCustomButton?: (props: CustomColorButtonProps) => React.ReactNode;
- colorContainerClassName?: string;
- isGradient?: boolean;
- renderGradientCustomButton?: (props: {
- value: number;
- startColor: number;
- endColor: number;
- disabled?: boolean;
- }) => React.ReactNode;
- gradientDegrees?: number;
- allowBlackCustomColor?: boolean;
-}
diff --git a/src/equicordplugins/components.dev/types/errorboundary.d.ts b/src/equicordplugins/components.dev/types/errorboundary.d.ts
deleted file mode 100644
index 3a205d708..000000000
--- a/src/equicordplugins/components.dev/types/errorboundary.d.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { ComponentType, ErrorInfo, ReactNode } from "react";
-
-export interface ErrorBoundaryFallbackProps {
- error: Error;
- resetErrorBoundary: (...args: any[]) => void;
-}
-
-export interface ErrorBoundaryProps {
- children: ReactNode;
- fallback?: ReactNode;
- fallbackRender?: (props: ErrorBoundaryFallbackProps) => ReactNode;
- FallbackComponent?: ComponentType;
- onError?: (error: Error, info: ErrorInfo) => void;
- onReset?: (details: { reason: "imperative-api" | "keys"; args?: any[]; prev?: any[]; next?: any[]; }) => void;
- resetKeys?: any[];
-}
-
-export interface SimpleErrorBoundaryProps {
- children: ReactNode;
- fallback: ReactNode;
-}
-
-export interface LocalErrorBoundaryProps {
- children: ReactNode;
-}
diff --git a/src/equicordplugins/components.dev/types/focuslock.d.ts b/src/equicordplugins/components.dev/types/focuslock.d.ts
deleted file mode 100644
index b1d476187..000000000
--- a/src/equicordplugins/components.dev/types/focuslock.d.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface FocusLockProps {
- containerRef: React.RefObject;
- keyboardModeEnabled?: boolean;
- children?: React.ReactNode;
-}
diff --git a/src/equicordplugins/components.dev/types/guildicon.d.ts b/src/equicordplugins/components.dev/types/guildicon.d.ts
deleted file mode 100644
index 2439f187c..000000000
--- a/src/equicordplugins/components.dev/types/guildicon.d.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface GuildIconProps {
- guildId: string;
- guildName: string;
- guildIcon: string | null;
- iconSize: number;
- className?: string;
- acronymClassName?: string;
- animate?: boolean;
-}
diff --git a/src/equicordplugins/components.dev/types/heading.d.ts b/src/equicordplugins/components.dev/types/heading.d.ts
deleted file mode 100644
index cd30c5a82..000000000
--- a/src/equicordplugins/components.dev/types/heading.d.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { HeadingVariantType, TextColorType, TextVariantType } from "../constants";
-
-export type HeadingVariant = HeadingVariantType;
-export type TextVariant = TextVariantType;
-export type TextColor = TextColorType | "currentColor" | "none" | "always-white";
-
-export interface DiscordHeadingProps {
- variant: HeadingVariant;
- className?: string;
- color?: TextColor;
- style?: React.CSSProperties;
- children?: React.ReactNode;
-}
-
-export interface DiscordTextProps {
- variant: TextVariant;
- color?: TextColor;
- tag?: string;
- selectable?: boolean;
- lineClamp?: number;
- tabularNumbers?: boolean;
- scaleFontToUserSetting?: boolean;
- className?: string;
- style?: React.CSSProperties;
- children?: React.ReactNode;
-}
diff --git a/src/equicordplugins/components.dev/types/index.d.ts b/src/equicordplugins/components.dev/types/index.d.ts
deleted file mode 100644
index 792bf25f5..000000000
--- a/src/equicordplugins/components.dev/types/index.d.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export * from "../constants";
-export * from "./accordion";
-export * from "./alert";
-export * from "./anchor";
-export * from "./avatar";
-export * from "./badge";
-export * from "./button";
-export * from "./calendar";
-export * from "./checkbox";
-export * from "./chip";
-export * from "./clickable";
-export * from "./colorpicker";
-export * from "./errorboundary";
-export * from "./focuslock";
-export * from "./guildicon.d";
-export * from "./heading";
-export * from "./input";
-export * from "./menu";
-export * from "./modal";
-export * from "./notice";
-export * from "./paginator";
-export * from "./progress";
-export * from "./radio";
-export * from "./scroller";
-export * from "./select";
-export * from "./skeleton";
-export * from "./slider";
-export * from "./spinner";
-export * from "./switch";
-export * from "./tabbar";
-export * from "./timestamp";
-export * from "./toast";
-export * from "./tooltip";
-export * from "./usersummary";
diff --git a/src/equicordplugins/components.dev/types/input.d.ts b/src/equicordplugins/components.dev/types/input.d.ts
deleted file mode 100644
index f438e1ebf..000000000
--- a/src/equicordplugins/components.dev/types/input.d.ts
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { TextInputSize } from "../constants";
-
-export type { TextInputSize };
-
-export type TextInputLeadingAccessory =
- | string
- | React.ComponentType
- | { icon: React.ComponentType; tooltip?: string; }
- | { button: React.ReactNode; }
- | { type: "tags"; tags: string[]; onRemove?: (tag: string) => void; }
- | { type: "image"; src: string; };
-
-export type TextInputTrailingAccessory =
- | React.ComponentType
- | { icon: React.ComponentType; tooltip?: string; }
- | { button: React.ReactNode; };
-
-export interface ManaTextInputProps {
- value?: string;
- defaultValue?: string;
- onChange?: (value: string, name?: string) => void;
- onClear?: (e: React.MouseEvent) => void;
- onFocus?: (e: React.FocusEvent) => void;
- onBlur?: (e: React.FocusEvent) => void;
- placeholder?: string;
- name?: string;
- type?: "text" | "password" | "email" | "number" | "search" | "tel" | "url";
- disabled?: boolean;
- readOnly?: boolean;
- editable?: boolean;
- size?: TextInputSize;
- error?: string | boolean;
- clearable?: boolean | { show: boolean; };
- showCharacterCount?: boolean;
- maxLength?: number;
- minLength?: number;
- fullWidth?: boolean;
- leading?: TextInputLeadingAccessory;
- trailing?: TextInputTrailingAccessory;
- validateOn?: "change" | "blur";
- defaultDirty?: boolean;
- focusProps?: Record;
- inputRef?: React.Ref;
- label?: string;
- hideLabel?: boolean;
- badge?: React.ReactNode;
- icon?: React.ReactNode;
- required?: boolean;
- description?: string;
- helperText?: string;
- errorMessage?: string;
- successMessage?: string;
- id?: string;
- layout?: string;
- layoutConfig?: Record;
- "aria-label"?: string;
- "aria-labelledby"?: string;
- "aria-describedby"?: string;
-}
-
-export interface ManaTextAreaProps {
- value?: string;
- defaultValue?: string;
- onChange?: (value: string, name?: string) => void;
- onFocus?: (e: React.FocusEvent) => void;
- onBlur?: (e: React.FocusEvent) => void;
- placeholder?: string;
- name?: string;
- disabled?: boolean;
- readOnly?: boolean;
- rows?: number;
- autoFocus?: boolean;
- autosize?: boolean;
- maxLength?: number;
- minLength?: number;
- showCharacterCount?: boolean;
- showRemainingCharacterCount?: boolean;
- error?: string | boolean;
- defaultDirty?: boolean;
- fullWidth?: boolean;
- focusProps?: Record;
- inputRef?: React.Ref;
- label?: string;
- hideLabel?: boolean;
- badge?: React.ReactNode;
- icon?: React.ReactNode;
- required?: boolean;
- description?: string;
- helperText?: string;
- errorMessage?: string;
- successMessage?: string;
- id?: string;
- layout?: string;
- layoutConfig?: Record;
- "aria-label"?: string;
- "aria-labelledby"?: string;
- "aria-describedby"?: string;
-}
-
-export interface SearchBarProps {
- query: string;
- onChange: (value: string) => void;
- onClear?: () => void;
- placeholder?: string;
- size?: TextInputSize;
- autoFocus?: boolean;
- disabled?: boolean;
- onKeyDown?: (e: React.KeyboardEvent) => void;
- onBlur?: () => void;
- onFocus?: () => void;
- autoComplete?: string;
- inputProps?: Record;
- ref?: React.Ref;
- "aria-label"?: string;
-}
diff --git a/src/equicordplugins/components.dev/types/menu.d.ts b/src/equicordplugins/components.dev/types/menu.d.ts
deleted file mode 100644
index 8f0e62e1a..000000000
--- a/src/equicordplugins/components.dev/types/menu.d.ts
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { ComponentType, CSSProperties, MouseEvent, ReactNode, Ref, UIEvent } from "react";
-
-export type MenuItemColor = "default" | "brand" | "danger" | "premium" | "premium-gradient" | "success";
-
-export type MenuIconSize = "sm" | "md" | "lg";
-
-export interface MenuProps {
- navId: string;
- onClose: () => void;
- onSelect?: () => void;
- onInteraction?: (data: { type: number; }) => void;
- variant?: "flexible" | "fixed";
- hideScroller?: boolean;
- className?: string;
- style?: CSSProperties;
- "aria-label"?: string;
- children: ReactNode;
-}
-
-export interface MenuItemIconProps {
- color?: string;
- className?: string;
-}
-
-export interface MenuItemProps {
- id: string;
- label: ReactNode | ((props: MenuItemProps) => ReactNode);
- color?: MenuItemColor;
- icon?: ComponentType;
- iconLeft?: ComponentType;
- iconLeftSize?: MenuIconSize;
- iconProps?: MenuItemIconProps;
- leadingAccessory?: ReactNode;
- trailingIndicator?: ReactNode;
- hint?: ReactNode | ((props: MenuItemProps) => ReactNode);
- shortcut?: ReactNode;
- subtext?: ReactNode;
- subtextLineClamp?: number;
- hasSubmenu?: boolean;
- loading?: boolean;
- badge?: ReactNode;
- disabled?: boolean;
- action?: (e: MouseEvent) => void;
- onClose?: () => void;
- onFocus?: () => void;
- dontCloseOnAction?: boolean;
- dontCloseOnActionIfHoldingShiftKey?: boolean;
- className?: string;
- focusedClassName?: string;
- subMenuIconClassName?: string;
- render?: (props: MenuItemProps) => ReactNode;
- navigable?: boolean;
- onChildrenScroll?: () => void;
- childRowHeight?: number;
- listClassName?: string;
- subMenuClassName?: string;
- children?: ReactNode;
-}
-
-export interface MenuCheckboxItemProps {
- id: string;
- label: ReactNode | ((props: MenuCheckboxItemProps) => ReactNode);
- color?: MenuItemColor;
- checked: boolean;
- action?: (e: MouseEvent) => void;
- disabled?: boolean;
- subtext?: ReactNode;
- subtextLineClamp?: number;
- leftIcon?: ComponentType;
- leadingAccessory?: ReactNode;
- className?: string;
- focusedClassName?: string;
-}
-
-export interface MenuRadioItemProps {
- id: string;
- group: string;
- label: ReactNode | ((props: MenuRadioItemProps) => ReactNode);
- color?: MenuItemColor;
- checked: boolean;
- action?: (e: MouseEvent) => void;
- disabled?: boolean;
- subtext?: ReactNode;
- subtextLineClamp?: number;
- leftIcon?: ComponentType;
- leadingAccessory?: ReactNode;
-}
-
-export interface MenuSwitchItemProps {
- id: string;
- label?: ReactNode;
- color?: MenuItemColor;
- checked: boolean;
- action: (e: MouseEvent) => void;
- disabled?: boolean;
- subtext?: ReactNode;
- subtextLineClamp?: number;
- className?: string;
-}
-
-export interface MenuGroupProps {
- label?: ReactNode;
- color?: MenuItemColor;
- className?: string;
- children: ReactNode;
-}
-
-export interface MenuCustomItemRenderProps {
- color: MenuItemColor;
- disabled: boolean;
- isFocused: boolean;
-}
-
-export interface MenuCustomItemProps {
- id: string;
- color?: MenuItemColor;
- disabled?: boolean;
- keepItemStyles?: boolean;
- action?: (e: MouseEvent) => void;
- dontCloseOnAction?: boolean;
- dontCloseOnActionIfHoldingShiftKey?: boolean;
- navigable?: boolean;
- children: (props: MenuCustomItemRenderProps) => ReactNode;
-}
-
-export interface MenuControlItemControlProps {
- onClose: () => void;
- disabled?: boolean;
- isFocused: boolean;
- onInteraction: (type?: number) => void;
-}
-
-export interface MenuControlItemProps {
- id: string;
- label?: ReactNode;
- color?: MenuItemColor;
- control: (props: MenuControlItemControlProps, ref: Ref) => ReactNode;
- disabled?: boolean;
- showDefaultFocus?: boolean;
-}
-
-export interface MenuCompositeControlItemProps {
- id: string;
- color?: MenuItemColor;
- disabled?: boolean;
- showDefaultFocus?: boolean;
- interactive?: boolean;
- children: ReactNode;
-}
-
-export interface MenuControlRef {
- focus: () => void;
- blur: () => void;
- activate: () => boolean;
-}
-
-export interface MenuSliderControlProps {
- value: number;
- minValue?: number;
- maxValue?: number;
- onChange: (value: number) => void;
- onInteraction?: (type?: number) => void;
- renderValue?: (value: number) => string;
- "aria-label"?: string;
-}
-
-export interface MenuSearchControlProps {
- query: string;
- onChange: (query: string) => void;
- disabled?: boolean;
- placeholder?: string;
- onInteraction?: (type?: number) => void;
- "aria-label"?: string;
-}
-
-export interface MenuType {
- Menu: ComponentType;
- MenuItem: ComponentType;
- MenuCheckboxItem: ComponentType;
- MenuRadioItem: ComponentType;
- MenuSwitchItem: ComponentType;
- MenuGroup: ComponentType;
- MenuSeparator: ComponentType>;
- MenuControlItem: ComponentType;
- MenuSliderControl: ComponentType;
- MenuSearchControl: ComponentType;
-}
-
-export interface ContextMenuOpenOptions {
- enableSpellCheck?: boolean;
-}
-
-export interface ContextMenuApiType {
- openContextMenu: (
- event: UIEvent,
- render: (props: { onClose: () => void; }) => ReactNode,
- options?: ContextMenuOpenOptions
- ) => void;
- openContextMenuLazy: (
- event: UIEvent,
- renderLazy: () => Promise<(props: { onClose: () => void; }) => ReactNode>,
- options?: ContextMenuOpenOptions
- ) => void;
- closeContextMenu: (callback?: () => void) => void;
-}
diff --git a/src/equicordplugins/components.dev/types/modal.d.ts b/src/equicordplugins/components.dev/types/modal.d.ts
deleted file mode 100644
index bcf51f6f3..000000000
--- a/src/equicordplugins/components.dev/types/modal.d.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export type NativeModalSize = "sm" | "md";
-
-export type ModalActionVariant = "primary" | "secondary" | "critical-primary" | "critical-secondary";
-
-export interface ModalAction {
- text: string;
- variant: ModalActionVariant;
- onClick: () => void;
- disabled?: boolean;
- loading?: boolean;
-}
-
-export interface ModalNotice {
- message: string;
- type: "info" | "warn" | "critical" | "positive";
-}
-
-export type ModalAnimationVariant = "default" | "fade" | "slide-up";
-
-export type ModalMaxHeight = "default" | "full";
-
-export interface ModalProps {
- title: string;
- subtitle?: string;
- size?: NativeModalSize;
- transitionState?: number;
- animationVariant?: ModalAnimationVariant;
- paddingSize?: "sm" | "lg";
- fullScreenOnMobile?: boolean;
- maxHeight?: ModalMaxHeight;
- dismissable?: boolean;
- children?: React.ReactNode;
- actions?: ModalAction[];
- actionBarInput?: React.ReactNode;
- actionBarInputLayout?: "default" | "full-width";
- input?: React.ReactNode;
- preview?: React.ReactNode;
- listProps?: Record;
- notice?: ModalNotice;
- onClose: () => void;
- onScroll?: (e: React.UIEvent) => void;
- scrollerRef?: React.Ref;
- returnRef?: React.Ref;
- role?: string;
- "aria-label"?: string;
- className?: string;
-}
-
-export interface ConfirmModalProps extends Omit {
- transitionState?: number;
- confirmText: string;
- cancelText?: string;
- onConfirm?: (setError?: (error: string) => void) => void | Promise;
- onCancel?: () => void;
- onCloseCallback?: () => void;
- variant?: "critical" | "primary" | "secondary";
- checkboxProps?: {
- label: string;
- checked: boolean;
- onChange: (checked: boolean) => void;
- };
-}
-
-export type ExpressiveGradientColor = "purple" | "blue" | "pink" | "green";
-
-export interface ModalGraphic {
- type: "image";
- src: string;
- aspectRatio?: string;
-}
-
-export interface ExpressiveModalProps {
- title: string;
- subtitle?: string;
- size?: NativeModalSize;
- transitionState?: number;
- gradientColor?: ExpressiveGradientColor;
- graphic?: ModalGraphic;
- badge?: React.ReactNode;
- actionBarInput?: React.ReactNode;
- actions?: ModalAction[];
- children?: React.ReactNode;
- onClose: () => void;
-}
-
-export interface OpenModalOptions {
- modalKey?: string;
- dismissable?: boolean;
- instant?: boolean;
- onCloseRequest?: () => void;
- onCloseCallback?: () => void;
- backdropStyle?: "default" | "dark" | "transparent";
- stackingBehavior?: "stack" | "replace";
- stackNextByDefault?: boolean;
- allowsNavigation?: boolean;
-}
-
-export type ModalRenderFn = (props: { onClose: () => void; transitionState: number }) => React.ReactNode;
-
-export interface ModalAPI {
- openModal: (render: ModalRenderFn, options?: OpenModalOptions) => string;
- openModalLazy: (renderFactory: () => Promise<{ default: React.ComponentType }>, options?: OpenModalOptions) => Promise;
- closeModal: (modalKey: string) => void;
- closeAllModals: () => void;
- hasModalOpen: (modalKey: string) => boolean;
- hasAnyModalOpen: () => boolean;
-}
-
-export interface ModalComponents {
- Modal: React.ComponentType;
- ConfirmModal: React.ComponentType;
- ExpressiveModal: React.ComponentType;
-}
diff --git a/src/equicordplugins/components.dev/types/notice.d.ts b/src/equicordplugins/components.dev/types/notice.d.ts
deleted file mode 100644
index 5d6ced3d9..000000000
--- a/src/equicordplugins/components.dev/types/notice.d.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { NoticeTypeValue } from "../constants";
-
-export type NoticeType = NoticeTypeValue;
-
-export interface NoticeProps {
- children: React.ReactNode;
- messageType: NoticeType;
- action?: React.ReactNode;
- className?: string;
- textColor?: string;
- textVariant?: string;
- icon?: React.ComponentType<{ className?: string; color?: string; }>;
- hidden?: boolean;
-}
diff --git a/src/equicordplugins/components.dev/types/paginator.d.ts b/src/equicordplugins/components.dev/types/paginator.d.ts
deleted file mode 100644
index 8a2694519..000000000
--- a/src/equicordplugins/components.dev/types/paginator.d.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface PaginatorPageWrapperProps {
- key: string;
- targetPage: number;
- selected: boolean;
- navigateToPage: () => void;
-}
-
-export interface PaginatorProps {
- currentPage: number;
- totalCount: number;
- pageSize: number;
- maxVisiblePages?: number;
- disablePaginationGap?: boolean;
- onPageChange?: (page: number) => void;
- hideMaxPage?: boolean;
- className?: string;
- renderPageWrapper?: (props: PaginatorPageWrapperProps, defaultRender: React.ReactNode) => React.ReactNode;
-}
diff --git a/src/equicordplugins/components.dev/types/progress.d.ts b/src/equicordplugins/components.dev/types/progress.d.ts
deleted file mode 100644
index 89cee00cc..000000000
--- a/src/equicordplugins/components.dev/types/progress.d.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export type ProgressBarVariant = "blue" | "orange" | "unset";
-
-export interface ProgressBarOverride {
- background?: string;
- gradientStart?: string;
- gradientEnd?: string;
-}
-
-export type ProgressBarWeight = "light" | "medium";
-
-export interface ProgressBarProps {
- progress: number;
- minimum?: number;
- maximum?: number;
- weight?: ProgressBarWeight;
- variant?: ProgressBarVariant;
- override?: {
- default?: ProgressBarOverride;
- [key: string]: ProgressBarOverride | undefined;
- };
- glowing?: boolean;
- labelledBy?: string;
-}
diff --git a/src/equicordplugins/components.dev/types/radio.d.ts b/src/equicordplugins/components.dev/types/radio.d.ts
deleted file mode 100644
index d4f4133c6..000000000
--- a/src/equicordplugins/components.dev/types/radio.d.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface RadioOption {
- value: string | number;
- name: string;
- description?: string;
- disabled?: boolean;
- icon?: React.ComponentType<{ className?: string; size?: string; color?: string; }>;
- color?: string;
- radioItemIconClassName?: string;
- radioBarClassName?: string;
-}
-
-export type RadioPosition = "left" | "right";
-
-export interface ManaBaseRadioGroupProps {
- options: RadioOption[];
- value?: string | number | null;
- onChange?: (value: string | number) => void;
- disabled?: boolean;
- size?: string;
- orientation?: "vertical" | "horizontal";
- radioPosition?: RadioPosition;
- withTransparentBackground?: boolean;
- label?: string;
- description?: string;
- required?: boolean;
- errorMessage?: string;
- "aria-labelledby"?: string;
- className?: string;
- itemInfoClassName?: string;
- itemTitleClassName?: string;
- radioItemClassName?: string;
- collapsibleClassName?: string;
-}
-
-export interface StandaloneRadioIndicatorProps {
- isSelected: boolean;
- disabled?: boolean;
-}
diff --git a/src/equicordplugins/components.dev/types/scroller.d.ts b/src/equicordplugins/components.dev/types/scroller.d.ts
deleted file mode 100644
index 9ed39c1ef..000000000
--- a/src/equicordplugins/components.dev/types/scroller.d.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface ScrollerProps extends Omit, "dir"> {
- className?: string;
- style?: React.CSSProperties;
- children?: React.ReactNode;
- orientation?: "vertical" | "horizontal";
- paddingFix?: boolean;
- fade?: boolean;
- dir?: "ltr" | "rtl";
- onScroll?: (e: React.UIEvent) => void;
-}
-
-export interface ListScrollerProps {
- className?: string;
- style?: React.CSSProperties;
- dir?: "ltr" | "rtl";
- fade?: boolean;
- customTheme?: boolean;
- onScroll?: (e: React.UIEvent) => void;
- onResize?: ((entries: ResizeObserverEntry[]) => void) | null;
- onContentResize?: ((entries: ResizeObserverEntry[]) => void) | null;
- sections: number[];
- sectionHeight: number;
- rowHeight: number;
- footerHeight?: number;
- sidebarHeight?: number;
- listHeaderHeight?: number;
- renderSection?: (section: { type: string; section: number; }) => React.ReactNode;
- renderRow: (row: { type: string; section: number; row: number; }) => React.ReactNode;
- renderFooter?: (footer: { type: string; section: number; }) => React.ReactNode;
- renderSidebar?: (isListVisible: boolean, isSidebarVisible: boolean) => React.ReactNode;
- renderListHeader?: () => React.ReactNode;
- stickyListHeader?: boolean;
- wrapSection?: (section: number, children: React.ReactNode[]) => React.ReactNode;
- paddingTop?: number;
- paddingBottom?: number;
- chunkSize?: number;
- innerId?: string;
- innerRole?: string;
- innerAriaLabel?: string;
-}
diff --git a/src/equicordplugins/components.dev/types/select.d.ts b/src/equicordplugins/components.dev/types/select.d.ts
deleted file mode 100644
index d99e2b3da..000000000
--- a/src/equicordplugins/components.dev/types/select.d.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface ManaSelectOption {
- id: string;
- value: string;
- label: string;
-}
-
-export interface ManaSelectProps {
- options: ManaSelectOption[];
- value?: string | string[] | null;
- onSelectionChange?: (value: string | string[] | null) => void;
- selectionMode?: "single" | "multiple";
- placeholder?: string;
- disabled?: boolean;
- readOnly?: boolean;
- clearable?: boolean;
- fullWidth?: boolean;
- autoFocus?: boolean;
- closeOnSelect?: boolean;
- shouldFocusWrap?: boolean;
- maxOptionsVisible?: number;
- wrapTags?: boolean;
- formatOption?: (option: ManaSelectOption) => React.ReactNode;
- name?: string;
- form?: string;
- autoComplete?: string;
- label?: string;
- required?: boolean;
-}
-
-export interface ManaComboboxProps {
- placeholder?: string;
- value?: T | T[];
- onChange?: (value: T | T[]) => void;
- multiSelect?: boolean;
- autoFocus?: boolean;
- maxVisibleItems?: number;
- itemToString?: (item: T) => string;
- emptyStateText?: string;
- emptyStateHeader?: string;
- onQueryChange?: (query: string) => void;
- "aria-label"?: string;
- className?: string;
- listClassName?: string;
- children: (query: string) => React.ReactNode[];
-}
-
-export interface ListboxItem {
- id: string;
- label: string;
- disabled?: boolean;
-}
-
-export interface ManaListboxProps {
- items: ListboxItem[];
- selectedItems?: ListboxItem[];
- defaultSelectedItems?: ListboxItem[];
- onSelectionChange?: (items: ListboxItem[]) => void;
- selectionMode?: "single" | "multiple";
- disabled?: boolean;
- required?: boolean;
- loading?: boolean;
- maxVisibleItems?: number;
- shouldFocusWrap?: boolean;
- typeahead?: boolean;
- renderListItem?: (item: ListboxItem) => React.ReactNode;
- renderEmptyState?: () => React.ReactNode;
-}
diff --git a/src/equicordplugins/components.dev/types/skeleton.d.ts b/src/equicordplugins/components.dev/types/skeleton.d.ts
deleted file mode 100644
index e68a44df3..000000000
--- a/src/equicordplugins/components.dev/types/skeleton.d.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface SkeletonProps {
- withHeader?: boolean;
- size?: number;
-}
diff --git a/src/equicordplugins/components.dev/types/slider.d.ts b/src/equicordplugins/components.dev/types/slider.d.ts
deleted file mode 100644
index 9d0271b50..000000000
--- a/src/equicordplugins/components.dev/types/slider.d.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { SliderOrientation } from "../constants";
-
-export type { SliderOrientation };
-
-export interface SliderProps {
- initialValue?: number;
- value?: number;
- minValue?: number;
- maxValue?: number;
- onValueChange?: (value: number) => void;
- asValueChanges?: (value: number) => void;
- onValueRender?: (value: number) => string | null;
- markers?: number[];
- stickToMarkers?: boolean;
- equidistant?: boolean;
- onMarkerRender?: (value: number) => string | React.ReactNode | null;
- renderMarker?: (value: number) => React.ReactNode;
- getAriaValueText?: (value: number) => string;
- keyboardStep?: number;
- handleSize?: number;
- disabled?: boolean;
- mini?: boolean;
- hideBubble?: boolean;
- defaultValue?: number;
- orientation?: SliderOrientation;
- markerPosition?: 0 | 1;
- barStyles?: React.CSSProperties;
- fillStyles?: React.CSSProperties;
- grabberStyles?: React.CSSProperties;
- barClassName?: string;
- grabberClassName?: string;
- className?: string;
- "aria-hidden"?: boolean;
- "aria-label"?: string;
- "aria-labelledby"?: string;
- "aria-describedby"?: string;
- label?: string;
- hideLabel?: boolean;
- required?: boolean;
- description?: string;
- helperText?: string;
- errorMessage?: string;
- successMessage?: string;
-}
diff --git a/src/equicordplugins/components.dev/types/spinner.d.ts b/src/equicordplugins/components.dev/types/spinner.d.ts
deleted file mode 100644
index 3352257f5..000000000
--- a/src/equicordplugins/components.dev/types/spinner.d.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { SpinnerType } from "../constants";
-
-export type { SpinnerType };
-
-export interface SpinnerTypeEnum {
- WANDERING_CUBES: "wanderingCubes";
- CHASING_DOTS: "chasingDots";
- PULSING_ELLIPSIS: "pulsingEllipsis";
- SPINNING_CIRCLE: "spinningCircle";
- SPINNING_CIRCLE_SIMPLE: "spinningCircleSimple";
- LOW_MOTION: "lowMotion";
-}
-
-export interface SpinnerProps {
- type?: SpinnerType;
- animated?: boolean;
- className?: string;
- itemClassName?: string;
- "aria-label"?: string;
-}
-
-export interface SpinnerComponent extends React.FC {
- Type: SpinnerTypeEnum;
-}
diff --git a/src/equicordplugins/components.dev/types/switch.d.ts b/src/equicordplugins/components.dev/types/switch.d.ts
deleted file mode 100644
index 68e98d488..000000000
--- a/src/equicordplugins/components.dev/types/switch.d.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface ManaSwitchProps {
- checked: boolean;
- onChange?: (checked: boolean) => void;
- disabled?: boolean;
- id?: string;
- hasIcon?: boolean;
- focusProps?: Record;
- describedBy?: string;
- labelledBy?: string;
- innerRef?: React.Ref;
-}
diff --git a/src/equicordplugins/components.dev/types/tabbar.d.ts b/src/equicordplugins/components.dev/types/tabbar.d.ts
deleted file mode 100644
index 78baba9d7..000000000
--- a/src/equicordplugins/components.dev/types/tabbar.d.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export interface TabBarProps {
- className?: string;
- children?: React.ReactNode;
- type?: "side" | "top" | "top-pill";
- look?: "brand" | "grey";
- style?: React.CSSProperties;
- selectedItem?: string;
- onItemSelect?: (id: string) => void;
- orientation?: "horizontal" | "vertical";
- "aria-label"?: string;
-}
-
-export interface TabBarItemProps {
- id: string;
- className?: string;
- children?: React.ReactNode;
- selectedItem?: string;
- onItemSelect?: (id: string) => void;
- itemType?: "side" | "top" | "top-pill";
- look?: "brand" | "grey";
- color?: string;
- variant?: "destructive";
- disabled?: boolean;
- disableItemStyles?: boolean;
- onClick?: React.MouseEventHandler;
- onContextMenu?: React.MouseEventHandler;
- clickableRef?: React.Ref;
- clickableInnerRef?: React.Ref;
- "aria-label"?: string;
-}
-
-export interface TabBarHeaderProps {
- className?: string;
- children?: React.ReactNode;
- onClick?: React.MouseEventHandler;
- "aria-expanded"?: boolean;
- "aria-controls"?: string;
-}
-
-export interface TabBarSeparatorProps {
- style?: React.CSSProperties;
-}
-
-export type TabBarComponent = React.ComponentType & {
- Item: React.ComponentType;
- Header: React.ComponentType;
- Separator: React.ComponentType;
- Panel: React.ComponentType<{ children?: React.ReactNode; }>;
-};
diff --git a/src/equicordplugins/components.dev/types/timestamp.d.ts b/src/equicordplugins/components.dev/types/timestamp.d.ts
deleted file mode 100644
index 8a0de3ef8..000000000
--- a/src/equicordplugins/components.dev/types/timestamp.d.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { Moment } from "moment";
-
-import type { TimestampDisplayFormat, TooltipPosition } from "../constants";
-
-export type TimestampFormat = TimestampDisplayFormat;
-
-export type { TooltipPosition };
-
-export interface TimestampProps {
- timestamp: Date | Moment;
- timestampFormat?: TimestampFormat;
- compact?: boolean;
- cozyAlt?: boolean;
- isInline?: boolean;
- isVisibleOnlyOnHover?: boolean;
- isEdited?: boolean;
- application?: any;
- id?: string;
- className?: string;
- children?: React.ReactNode;
- tooltipPosition?: TooltipPosition;
-}
diff --git a/src/equicordplugins/components.dev/types/toast.d.ts b/src/equicordplugins/components.dev/types/toast.d.ts
deleted file mode 100644
index 27527ca90..000000000
--- a/src/equicordplugins/components.dev/types/toast.d.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-export type ToastTypeValue = "message" | "success" | "failure" | "custom" | "clip" | "link" | "forward" | "bookmark" | "clock";
-
-export type ToastPositionValue = 0 | 1;
-
-export interface ToastOptions {
- duration?: number;
- position?: ToastPositionValue;
- component?: React.ReactNode;
- appContext?: number;
-}
-
-export interface ToastData {
- message: string;
- type: ToastTypeValue;
- id: string;
- options?: ToastOptions;
-}
-
-export interface ToastsModule {
- Type: Record;
- Position: Record;
- genId: () => string;
- show: (data: ToastData) => void;
- pop: () => void;
- create: (message: string, type: ToastTypeValue, options?: ToastOptions) => ToastData;
-}
diff --git a/src/equicordplugins/components.dev/types/tooltip.d.ts b/src/equicordplugins/components.dev/types/tooltip.d.ts
deleted file mode 100644
index 27c1dfe9b..000000000
--- a/src/equicordplugins/components.dev/types/tooltip.d.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { PopoverSize, TooltipAlign, TooltipColor, TooltipPosition } from "../constants";
-
-export type { PopoverSize, TooltipAlign, TooltipColor, TooltipPosition };
-
-export interface ManaTooltipProps {
- text: string | (() => React.ReactNode);
- position?: TooltipPosition;
- align?: TooltipAlign;
- color?: TooltipColor;
- spacing?: number;
- hideOnClick?: boolean;
- delay?: number;
- forceOpen?: boolean;
- shouldShow?: boolean;
- allowOverflow?: boolean;
- overflowOnly?: boolean;
- clickableOnMobile?: boolean;
- disableTooltipPointerEvents?: boolean;
- targetElementRef?: React.RefObject;
- tooltipClassName?: string;
- tooltipStyle?: React.CSSProperties;
- tooltipContentClassName?: string;
- tooltipPointerClassName?: string;
- positionKeyStemOverride?: string;
- onTooltipShow?: () => void;
- onTooltipHide?: () => void;
- onAnimationRest?: () => void;
- "aria-label"?: string | false;
- children: (props: Record) => React.ReactNode;
-}
-
-export interface ManaRichTooltipProps {
- title?: string;
- body: string;
- asset?: React.ReactNode | { src: string; alt?: string; };
- assetSize?: number;
- asContainer?: boolean;
- element?: "span" | "div";
- position?: TooltipPosition;
- align?: TooltipAlign;
- spacing?: number;
- caretConfig?: { align?: "start" | "center" | "end"; };
- layerContext?: any;
- targetElementRef?: React.RefObject;
- anchorRef?: React.RefObject;
- positionKey?: string;
- ariaHidden?: boolean;
- shouldShow?: boolean;
- delay?: number;
- onTooltipShow?: () => void;
- onTooltipHide?: () => void;
- forceOpen?: boolean;
- overflowOnly?: boolean;
- hideOnClick?: boolean;
- children: React.ReactNode | ((props: Record) => React.ReactNode);
-}
-
-export interface PopoverAction {
- text: string;
- onClick?: () => void;
- variant?: "primary" | "secondary";
-}
-
-export interface ManaPopoverProps {
- title?: string;
- body?: string;
- badge?: React.ReactNode;
- graphic?: { src: string; aspectRatio?: string; };
- size?: PopoverSize;
- actions?: PopoverAction[];
- textLink?: { text: string; onClick?: () => void; };
- gradientColor?: string;
- scrollBehavior?: string;
- hasVideo?: boolean;
- onRequestClose?: (reason: string) => void;
- popoverRef?: React.Ref;
- targetElementRef: React.RefObject;
- shouldShow: boolean;
- position?: TooltipPosition;
- caretConfig?: { align?: "start" | "center" | "end"; };
- alignmentStrategy?: "edge" | "trigger-center";
- align?: "left" | "center" | "right";
-}
diff --git a/src/equicordplugins/components.dev/types/usersummary.d.ts b/src/equicordplugins/components.dev/types/usersummary.d.ts
deleted file mode 100644
index 366e7a564..000000000
--- a/src/equicordplugins/components.dev/types/usersummary.d.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2025 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import type { User } from "@vencord/discord-types";
-
-export type UserSummarySize = 16 | 24 | 32 | 56;
-
-export interface UserSummaryItemProps {
- users: (User | null)[];
- max?: number;
- count?: number;
- size?: UserSummarySize;
- guildId?: string;
- showUserPopout?: boolean;
- showDefaultAvatarsForNullUsers?: boolean;
- renderUser?: (user: User | null, isLast: boolean, index: number) => React.ReactNode;
- renderMoreUsers?: (text: string, count: number) => React.ReactNode;
- renderIcon?: boolean;
- renderLeadingIcon?: (className: string) => React.ReactNode;
- dimEmptyUsers?: boolean;
- hideMoreUsers?: boolean;
- useFallbackUserForPopout?: boolean;
- extraDetail?: React.ReactNode;
- className?: string;
-}