Simple auth schemes

This commit is contained in:
Gregory Schier
2023-03-29 09:03:38 -07:00
parent af9755c513
commit 0f58986b4c
18 changed files with 392 additions and 157 deletions

View File

@@ -8,6 +8,11 @@ import { Portal } from '../Portal';
import { Separator } from './Separator';
import { VStack } from './Stacks';
export type DropdownItemSeparator = {
type: 'separator';
label?: string;
};
export type DropdownItem =
| {
type?: 'default';
@@ -18,10 +23,7 @@ export type DropdownItem =
rightSlot?: ReactNode;
onSelect?: () => void;
}
| {
type: 'separator';
label?: string;
};
| DropdownItemSeparator;
export interface DropdownProps {
children: ReactElement<HTMLAttributes<HTMLButtonElement>>;

View File

@@ -69,7 +69,7 @@ export function Input({
htmlFor={id}
className={classnames(
labelClassName,
'font-semibold text-sm uppercase text-gray-700',
'font-semibold text-xs uppercase text-gray-700',
hideLabel && 'sr-only',
)}
>

View File

@@ -1,30 +1,39 @@
import { useMemo } from 'react';
import type { DropdownProps } from './Dropdown';
import type { DropdownItemSeparator, DropdownProps } from './Dropdown';
import { Dropdown } from './Dropdown';
import { Icon } from './Icon';
export interface RadioDropdownItem<T> {
label: string;
shortLabel?: string;
value: T;
}
export type RadioDropdownItem =
| {
type?: 'default';
label: string;
shortLabel?: string;
value: string | null;
}
| DropdownItemSeparator;
export interface RadioDropdownProps<T = string | null> {
value: T;
onChange: (value: T) => void;
items: RadioDropdownItem<T>[];
export interface RadioDropdownProps {
value: string | null;
onChange: (value: string | null) => void;
items: RadioDropdownItem[];
children: DropdownProps['children'];
}
export function RadioDropdown<T>({ value, items, onChange, children }: RadioDropdownProps<T>) {
export function RadioDropdown({ value, items, onChange, children }: RadioDropdownProps) {
const dropdownItems = useMemo(
() =>
items.map(({ label, shortLabel, value: v }) => ({
label,
shortLabel,
onSelect: () => onChange(v),
leftSlot: <Icon icon={value === v ? 'check' : 'empty'} />,
})),
items.map((item) => {
if (item.type === 'separator') {
return item;
} else {
return {
label: item.label,
shortLabel: item.shortLabel,
onSelect: () => onChange(item.value),
leftSlot: <Icon icon={value === item.value ? 'check' : 'empty'} />,
};
}
}),
[value, items],
);

View File

@@ -54,7 +54,7 @@ export const VStack = forwardRef(function VStack(
});
type BaseStackProps = HTMLAttributes<HTMLElement> & {
as?: ComponentType | 'ul';
as?: ComponentType | 'ul' | 'form';
space?: keyof typeof gapClasses;
alignItems?: 'start' | 'center';
justifyContent?: 'start' | 'center' | 'end';

View File

@@ -82,7 +82,9 @@ export function Tabs({
isActive ? 'bg-gray-100 text-gray-800' : 'text-gray-600 hover:text-gray-900',
);
if ('options' in t) {
const option = t.options.items.find((i) => i.value === t.options?.value);
const option = t.options.items.find(
(i) => 'value' in i && i.value === t.options?.value,
);
return (
<RadioDropdown
key={t.value}
@@ -96,7 +98,9 @@ export function Tabs({
onClick={isActive ? undefined : () => handleTabChange(t.value)}
className={btnClassName}
>
{option?.shortLabel ?? option?.label ?? 'Unknown'}
{option && 'shortLabel' in option
? option.shortLabel
: option?.label ?? 'Unknown'}
<Icon icon="triangleDown" className="-mr-1.5" />
</Button>
</RadioDropdown>