diff --git a/apps/cyberstorm-remix/app/commonComponents/PackageSearch/FilterMenus/CategoryMenu.tsx b/apps/cyberstorm-remix/app/commonComponents/PackageSearch/FilterMenus/CategoryMenu.tsx index 0da133118..249d5171d 100644 --- a/apps/cyberstorm-remix/app/commonComponents/PackageSearch/FilterMenus/CategoryMenu.tsx +++ b/apps/cyberstorm-remix/app/commonComponents/PackageSearch/FilterMenus/CategoryMenu.tsx @@ -4,11 +4,10 @@ import { faSquareXmark, } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import * as Checkbox from "@radix-ui/react-checkbox"; import styles from "./FilterMenu.module.css"; import { CategorySelection, CATEGORY_STATES as STATES } from "../types"; -import { NewIcon } from "@thunderstore/cyberstorm"; +import { CycleButton, NewIcon } from "@thunderstore/cyberstorm"; import { classnames } from "@thunderstore/cyberstorm/src/utils/utils"; interface Props { @@ -42,28 +41,24 @@ export const CategoryMenu = (props: Props) => {
  • ))} diff --git a/apps/cyberstorm-remix/app/commonComponents/PackageSearch/FilterMenus/OthersMenu.tsx b/apps/cyberstorm-remix/app/commonComponents/PackageSearch/FilterMenus/OthersMenu.tsx index a254c6a2c..4537f48d7 100644 --- a/apps/cyberstorm-remix/app/commonComponents/PackageSearch/FilterMenus/OthersMenu.tsx +++ b/apps/cyberstorm-remix/app/commonComponents/PackageSearch/FilterMenus/OthersMenu.tsx @@ -1,9 +1,8 @@ import { faSquare, faSquareCheck } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import * as Checkbox from "@radix-ui/react-checkbox"; import styles from "./FilterMenu.module.css"; -import { NewIcon } from "@thunderstore/cyberstorm"; +import { CycleButton, NewIcon } from "@thunderstore/cyberstorm"; import { classnames } from "@thunderstore/cyberstorm/src/utils/utils"; interface Props { @@ -33,15 +32,16 @@ export const OthersMenu = (props: Props) => { )} > {label} - setChecked(!checked)} - className={styles.checkbox} + setChecked(!checked)} + rootClasses={styles.checkbox} + value={checked ? "on" : "off"} + noState > - + ))} diff --git a/packages/cyberstorm/src/index.ts b/packages/cyberstorm/src/index.ts index cd240ab5b..1b7b1c573 100644 --- a/packages/cyberstorm/src/index.ts +++ b/packages/cyberstorm/src/index.ts @@ -105,6 +105,7 @@ export { CardCommunity } from "./newComponents/Card/CardCommunity/CardCommunity" export { CardPackage } from "./newComponents/Card/CardPackage/CardPackage"; export { Link as NewLink } from "./newComponents/Link/Link/Link"; export { Button as NewButton } from "./newComponents/Button/Button"; +export { CycleButton } from "./newComponents/CycleButton/CycleButton"; export { BreadCrumbs as NewBreadCrumbs } from "./newComponents/BreadCrumbs/BreadCrumbs"; export { TextInput as NewTextInput } from "./newComponents/TextInput/TextInput"; export { diff --git a/packages/cyberstorm/src/newComponents/CycleButton/CycleButton.css b/packages/cyberstorm/src/newComponents/CycleButton/CycleButton.css new file mode 100644 index 000000000..a25d48993 --- /dev/null +++ b/packages/cyberstorm/src/newComponents/CycleButton/CycleButton.css @@ -0,0 +1,6 @@ +@layer components { + .ts-cyclebutton { + display: inline-flex; + align-items: center; + } +} diff --git a/packages/cyberstorm/src/newComponents/CycleButton/CycleButton.tsx b/packages/cyberstorm/src/newComponents/CycleButton/CycleButton.tsx new file mode 100644 index 000000000..5a5a2f568 --- /dev/null +++ b/packages/cyberstorm/src/newComponents/CycleButton/CycleButton.tsx @@ -0,0 +1,85 @@ +import "./CycleButton.css"; +import React, { useState } from "react"; +import { classnames } from "../../utils/utils"; +import { + Actionable, + ActionableButtonProps, +} from "../../primitiveComponents/Actionable/Actionable"; + +interface CycleButtonProps + extends Omit { + noState?: boolean; + value?: string; + onInterract?: () => void; + options?: string[]; + onValueChange?: (value: string) => void; +} + +/** + * Button for cycling through values + * If you want to handle state outside of this component use the "noState" param + * Notes for handling state inside this component: + * - First value of the list will be the initial value + * - You can access the value from onValueChange. It's called each time value changes. + */ +export const CycleButton = React.forwardRef< + HTMLButtonElement, + CycleButtonProps +>((props: CycleButtonProps, forwardedRef) => { + const { + children, + rootClasses, + noState = false, + onInterract, + options, + onValueChange, + ...forwardedProps + } = props; + + if (noState) { + return ( + onInterract() : undefined} + > + {children} + + ); + } + + const initialValue = options && options.length > 0 ? options[0] : ""; + const [currentValue, setCurrentValue] = useState(initialValue); + + return ( + { + if (options && options.length > 0) { + const currentValueIndex = options?.indexOf(currentValue); + if ( + currentValueIndex === -1 || + currentValueIndex === options.length - 1 + ) { + setCurrentValue(options[0]); + } else { + setCurrentValue(options[currentValueIndex + 1]); + } + } + if (onInterract) { + onInterract(); + } + }} + onChange={onValueChange ? () => onValueChange(currentValue) : undefined} + > + {children} + + ); +}); + +CycleButton.displayName = "CycleButton";