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 ( - <> -
- - - - - - - - - - - {props.map(p => ( - - - - - - - ))} - -
FIELDTYPEDEFAULTDESCRIPTION
- {p.name} - {p.type}{p.default ?? -}{p.description}
-
- {showLegend && (hasRequired || hasInternal) && ( -
- {hasRequired && Required} - {hasInternal && Internal} -
- )} - - ); -} - -function TableOfContents({ entries }: { entries: { id: string; label: string; }[]; }) { - return ( -
- - ON THIS PAGE - -
- {entries.map(entry => ( - { - e.preventDefault(); - document.getElementById(entry.id)?.scrollIntoView({ behavior: "smooth", block: "start" }); - }} - > - {entry.label} - - ))} -
-
- ); -} - -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 && } - - - -
-
- - IMPORT - - -
-
- - {items.map(section => { - const relevant = section.relevantProps?.length - ? flat.filter(p => section.relevantProps!.includes(p.name)) - : null; - - return [ - , - , - ]; - })} - - - - - {isGrouped(props) ? ( - props.map(group => ( -
- - {group.title} - - -
- )) - ) : ( - - )} -
- - {examples?.length ? ( - <> - - - {examples.map(ex => ( -
- {ex.label} - -
- ))} -
- - ) : 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: ( - - ), - 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: ( - - ), - relevantProps: ["confirmText", "cancelText", "onConfirm", "onCancel"] - }, - { - title: "Danger Alert", - description: "Uses critical-primary variant for destructive actions.", - children: ( - - ), - 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: ( - - ), - relevantProps: ["confirmVariant"] - }, - { - title: "Promise-based Confirm", - description: "Alerts.confirm() returns a Promise. Resolves true on confirm, false on cancel.", - children: ( - - ), - 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 => ( -
- - - {status} - -
- ))} -
- ) - }, - { - title: "Mobile Status", - description: "Shows the mobile phone icon instead of a status dot when isMobile is true.", - code: '', - relevantProps: ["isMobile", "isVR"], - children: ( -
-
- - Mobile -
-
- - VR -
-
- ) - }, - { - title: "Speaking State", - description: "Animated ring indicator for voice activity.", - code: '', - relevantProps: ["isSpeaking", "isLatched", "voiceDb"], - children: ( -
-
- - Speaking -
-
- ) - }, - { - title: "Typing Indicator", - description: "Shows a typing animation in the status area.", - relevantProps: ["isTyping"], - children: ( -
-
- - Typing -
-
- ) - }, - { - title: "Status Tooltip", - description: "Hover to see the status text tooltip.", - relevantProps: ["statusTooltip", "statusTooltipDelay"], - children: ( -
- {AvatarStatuses.map(status => ( -
- - - {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]) => ( -
- - {label} -
- ))} -
- - No Color -
-
- ), - 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 ( - - ); -} - -function CustomFallback({ error, resetErrorBoundary }: { error: Error; resetErrorBoundary: () => void; }) { - return ( -
- - Custom Fallback UI - - - Error: {error.message} - - -
- ); -} - -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! - -
- } - > - - - - ); -} - -function LocalDemo() { - const [key, setKey] = useState(0); - - return ( -
- - - - -
- ); -} - -export default function ErrorBoundaryTab() { - return ( - , - code: ` ( -
-

Error: {error.message}

- -
- )} - 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); - -
- - - - - -
`, - 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 => ( -
- - - {size}px - -
- ))} -
-
- ); -} - -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 => ( - -
-

Modal content here

-
-
-))`, - 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")} /> - - - - - - { }} /> - { }} /> - - { }} /> - - - - - - ( - `${v}%`} - /> - )} - /> - - ); -} - -export default function MenuTab() { - const openMenu = (e: React.MouseEvent) => { - ContextMenuApi.openContextMenu(e, () => ( - - )); - }; - - return ( - - - - - ), - 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: ( - - ), - 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: - -
-
- hidden=true (invisible below): - -
-
- ), - 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 ( -
- Page {page} of 10 - -
- ); -} - -function MaxVisibleDemo() { - const [page3, setPage3] = useState(1); - const [page7, setPage7] = useState(1); - - return ( -
-
- maxVisiblePages=3: - -
-
- maxVisiblePages=7: - -
-
- ); -} - -function OptionsDemo() { - const [page, setPage] = useState(1); - - return ( -
-
- hideMaxPage: - -
-
- 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(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 ( - -
- Blue: - -
-
- Orange: - -
- - ), - code: '', - relevantProps: ["variant"], - }, - { - title: "Progress Values", - description: "Various progress levels from 0% to 100%.", - children: ( -
- {[0, 25, 50, 75, 100].map(v => ( -
- {v}%: - -
- ))} -
- ), - relevantProps: ["progress"], - }, - { - title: "Animated", - description: "Progress bar that increments automatically.", - children: , - }, - { - title: "Weight", - description: "Light (default) and medium weight variants.", - children: ( -
-
- Light (default): - -
-
- Medium: - -
-
- ), - code: '', - relevantProps: ["weight"], - }, - { - title: "Glowing", - description: "Glow effect is enabled by default. Set glowing={false} to disable.", - children: ( -
-
- Glowing (default): - -
-
- No glow: - -
-
- ), - 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: ` - -`, - 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 => ( -
- {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 ( -
- Value: {value} - -
- ); -} - -function MarkersDemo() { - const [value, setValue] = useState(50); - return ( -
- Value: {value} - `${v}%`} - /> -
- ); -} - -function MiniDemo() { - const [value, setValue] = useState(30); - return ( -
- Value: {value} -
- -
-
- ); -} - -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 => ( -
- - - {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) - -
-
- - - compact=true - -
-
- ), - relevantProps: ["compact"], - }, - { - title: "Display Variants", - description: "Inline and cozy alternative display modes.", - children: ( -
-
- - - isInline=false (default) - -
-
- - - isInline=true - -
-
- - - cozyAlt=true - -
-
- ), - relevantProps: ["isInline", "cozyAlt"], - }, - { - title: "Edited Indicator", - description: 'Shows an "(edited)" indicator after the timestamp.', - children: ( -
-
- - - isEdited=false (default) - -
-
- - - isEdited=true - -
-
- ), - 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 => ( -
- max={max}: - -
- ))} -
- ); -} - -function SizesDemo() { - const currentUser = UserStore.getCurrentUser(); - const users = currentUser ? Array(5).fill(currentUser) : []; - - return ( -
- {([16, 24, 32, 56] as const).map(size => ( -
- {size}: - -
- ))} -
- ); -} - -function OverrideCountDemo() { - const currentUser = UserStore.getCurrentUser(); - const users = currentUser ? Array(3).fill(currentUser) : []; - const [count, setCount] = useState(42); - - return ( -
-
- Default count: - -
-
- count={count}: - -
-
- ); -} - -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; -}