Skip to content

Commit

Permalink
feat: add multi switch component
Browse files Browse the repository at this point in the history
  • Loading branch information
sapkra committed Apr 17, 2024
1 parent 000ea63 commit e53c04d
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 4 deletions.
3 changes: 2 additions & 1 deletion src/components/base/Button.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Button as NextButton } from '@nextui-org/react'
import { Button as NextButton, ButtonGroup as NextButtonGroup } from '@nextui-org/react'
import { withFragment } from '../../withFragment'

export const Button = withFragment(NextButton, 'button');
export const ButtonGroup = withFragment(NextButtonGroup, 'buttonGroup');
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './base';
export * from './chart/Chart';
export * from './color-input/ColorInput';
export * from './multi-switch/MultiSwitch';
export * from './color-selector/ColorSelector';
35 changes: 35 additions & 0 deletions src/components/multi-switch/MultiSwitch.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Meta, StoryObj } from "@storybook/react";
import { MultiSwitch } from "./MultiSwitch";

// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta<typeof MultiSwitch> = {
title: "components/MultiSwitch",
component: MultiSwitch,
tags: ["autodocs"],
};

export default meta;

type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
export const Small: Story = {
args: {
onValueChange: console.log,
size: 'sm',
},
};

export const Medium: Story = {
args: {
onValueChange: console.log,
size: 'md',
},
};

export const Large: Story = {
args: {
onValueChange: console.log,
size: 'lg',
},
};
56 changes: 56 additions & 0 deletions src/components/multi-switch/MultiSwitch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { forwardRef, useEffect, useState } from 'react';
import { Button, ButtonGroup } from '../base';
import { withFragment } from '../../withFragment';
import { IconCheck, IconSlash, IconX } from '@tabler/icons-react';
import { ButtonGroupProps, tv } from '@nextui-org/react';

/**
* Primary UI component for selecting a color
*/

export interface MultiSwitchProps extends Omit<ButtonGroupProps, 'className'> {
defaultValue?: number;
onValueChange: (value: number) => void;
}

const multiSwitch = tv({
slots: {
button: 'min-w-0',
},
variants: {
size: {
sm: {
button: 'px-3'
},
md: {
button: 'px-4'
},
lg: {
button: 'px-5'
}
}
}
});

export const MultiSwitch = withFragment(forwardRef<HTMLInputElement, MultiSwitchProps>(({
defaultValue,
onValueChange,
size = 'md',
...props
}: MultiSwitchProps, ref) => {
const [value, setValue] = useState(defaultValue ?? 0);
const { button } = multiSwitch({ size });

useEffect(() => onValueChange && onValueChange(value), [value, onValueChange]);

return (
<>
<input ref={ref} value={value} type="number" className="hidden" min={0} max={2} required />
<ButtonGroup size={size} {...props}>
<Button className={button()} onClick={() => setValue(0)} {...value === 0 ? { color: 'danger' } : {}}><IconX size={20} /></Button>
<Button className={button()} onClick={() => setValue(1)} {...value === 1 ? { color: 'default', variant: 'solid' } : {}}><IconSlash size={20} /></Button>
<Button className={button()} onClick={() => setValue(2)} {...value === 2 ? { color: 'success' } : {}}><IconCheck size={20} /></Button>
</ButtonGroup>
</>
);
}), 'multiSwitch');
10 changes: 7 additions & 3 deletions src/context.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { AccordionItemProps, AccordionProps, AutocompleteItemProps, AutocompleteProps, AutocompleteSectionProps, AvatarGroupProps, AvatarProps, BadgeProps, BreadcrumbItemProps, BreadcrumbsProps, ButtonProps, CardProps, CheckboxGroupProps, CheckboxProps, ChipProps, CircularProgressProps, CodeProps, DividerProps, DropdownItemProps, DropdownMenuProps, DropdownProps, DropdownSectionProps, DropdownTriggerProps, HTMLNextUIProps, ImageProps, InputProps, KbdProps, LinkProps, ListboxItemProps, ListboxProps, ListboxSectionProps, ModalBodyProps, ModalContentProps, ModalFooterProps, ModalHeaderProps, ModalProps, NavbarBrandProps, NavbarContentProps, NavbarItemProps, NavbarMenuItemProps, NavbarMenuProps, NavbarMenuToggleProps, NavbarProps, PaginationCursorProps, PaginationItemProps, PaginationProps, PopoverContentProps, PopoverProps, PopoverTriggerProps, ProgressProps, RadioGroupProps, RadioProps, ScrollShadowProps, SelectItemProps, SelectProps, SelectSectionProps, SkeletonProps, SliderProps, SnippetProps, SpacerProps, SpinnerProps, SwitchProps, TabItemProps, TableBodyProps, TableCellProps, TableColumnProps, TableHeaderProps, TableProps, TabsProps, TextAreaProps, TooltipProps, UserProps } from "@nextui-org/react";
import { AccordionItemProps, AccordionProps, AutocompleteItemProps, AutocompleteProps, AutocompleteSectionProps, AvatarGroupProps, AvatarProps, BadgeProps, BreadcrumbItemProps, BreadcrumbsProps, ButtonGroupProps, ButtonProps, CardProps, CheckboxGroupProps, CheckboxProps, ChipProps, CircularProgressProps, CodeProps, DividerProps, DropdownItemProps, DropdownMenuProps, DropdownProps, DropdownSectionProps, DropdownTriggerProps, HTMLNextUIProps, ImageProps, InputProps, KbdProps, LinkProps, ListboxItemProps, ListboxProps, ListboxSectionProps, ModalBodyProps, ModalContentProps, ModalFooterProps, ModalHeaderProps, ModalProps, NavbarBrandProps, NavbarContentProps, NavbarItemProps, NavbarMenuItemProps, NavbarMenuProps, NavbarMenuToggleProps, NavbarProps, PaginationCursorProps, PaginationItemProps, PaginationProps, PopoverContentProps, PopoverProps, PopoverTriggerProps, ProgressProps, RadioGroupProps, RadioProps, ScrollShadowProps, SelectItemProps, SelectProps, SelectSectionProps, SkeletonProps, SliderProps, SnippetProps, SpacerProps, SpinnerProps, SwitchProps, TabItemProps, TableBodyProps, TableCellProps, TableColumnProps, TableHeaderProps, TableProps, TabsProps, TextAreaProps, TooltipProps, UserProps } from "@nextui-org/react";
import { createContext } from "react";
import { RowProps } from '@react-types/table';
import type { Props as ApexChartProps } from "react-apexcharts";
import { ColorInputProps, ColorSelectorProps } from "./components";
import { ChartProps } from "./components/chart/Chart";
import { ChartProps, ColorInputProps, ColorSelectorProps, MultiSwitchProps } from "./components";

// Copied type due to missing export from @nextui-org/react
export type TableRowProps<T = object> = RowProps<T> & Omit<HTMLNextUIProps<"tr">, keyof RowProps<T>>;
Expand All @@ -19,6 +18,7 @@ export interface FragmentUIContext {
autocompleteSection?: Partial<AutocompleteSectionProps>;
badge?: Partial<BadgeProps>;
button?: Partial<ButtonProps>;
buttonGroup?: Partial<ButtonGroupProps>;
breadcrumbs?: Partial<BreadcrumbsProps>;
breadcrumbItem?: Partial<BreadcrumbItemProps>;
card?: Partial<CardProps>;
Expand Down Expand Up @@ -48,6 +48,7 @@ export interface FragmentUIContext {
modalContent?: Partial<ModalContentProps>;
modalFooter?: Partial<ModalFooterProps>;
modalHeader?: Partial<ModalHeaderProps>;
multiSwitch?: Partial<MultiSwitchProps>;
navbar?: Partial<NavbarProps>;
navbarBrand?: Partial<NavbarBrandProps>;
navbarContent?: Partial<NavbarContentProps>;
Expand Down Expand Up @@ -101,6 +102,9 @@ export const defaultContext: FragmentUIContext = {
radius: 'full',
},
},
multiSwitch: {
variant: 'flat',
},
chart: {
area: {
options: {
Expand Down

0 comments on commit e53c04d

Please sign in to comment.