update to js

This commit is contained in:
2025-02-21 19:34:56 -03:00
parent 0187f770c7
commit a557ee6e34
44 changed files with 1015 additions and 2463 deletions

View File

@@ -1,45 +1,23 @@
import type { ReactNode, ComponentPropsWithoutRef, ElementType } from 'react'
import {
createElement,
createContext,
forwardRef,
useContext,
useId,
} from 'react'
import React, { forwardRef, useContext, useId } from 'react'
import { ExclamationCircleIcon } from '@heroicons/react/24/outline'
import { omit } from 'ramda'
import { Loader } from './loader'
import clsx from 'clsx'
interface ControlContextProps {
id?: string
className?: string
[key: string]: unknown
}
const ControlContext = React.createContext({})
const ControlContext = createContext<ControlContextProps>({})
interface ControlProviderProps extends ControlContextProps {
children: ReactNode
}
function ControlProvider({ children, ...props }: ControlProviderProps) {
function ControlProvider({ children, ...props }) {
return (
<ControlContext.Provider value={props}>{children}</ControlContext.Provider>
)
}
function useControl<T extends ControlContextProps>(props?: T) {
function useControl(props) {
const field = useContext(ControlContext)
return { ...field, ...props } as T & ControlContextProps
return { ...field, ...props }
}
interface ControlProps extends ComponentPropsWithoutRef<'div'> {
as?: ElementType
children?: ReactNode
}
export const Control = forwardRef<HTMLElement, ControlProps>(function Control(
export const Control = forwardRef(function Control(
{ as = 'div', children, ...props },
ref,
) {
@@ -48,29 +26,23 @@ export const Control = forwardRef<HTMLElement, ControlProps>(function Control(
return (
<ControlProvider id={props?.id || id} {...props_}>
{createElement(as, { ref, ...props }, children)}
{React.createElement(as, { ref, ...props }, children)}
</ControlProvider>
)
})
interface ButtonProps extends ComponentPropsWithoutRef<'button'> {
as?: ElementType
isLoading?: boolean
children?: ReactNode
}
export function Button({
children,
as = 'button',
className,
isLoading = false,
...props
}: ButtonProps) {
}) {
if (isLoading) {
props['disabled'] = isLoading
}
return createElement(
return React.createElement(
as,
{
className: clsx(
@@ -81,23 +53,20 @@ export function Button({
className,
),
...props,
} as React.HTMLAttributes<HTMLElement>,
},
<>
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center bg-green-secondary rounded-xl">
<Loader className="w-5 text-white" />
</div>
)}
{children}
</>,
)
}
interface LabelProps extends ComponentPropsWithoutRef<'label'> {
children?: ReactNode
}
export function Label({ children, className, ...props }: LabelProps) {
export function Label({ children, className, ...props }) {
const { id, htmlFor, className: _, ...field } = useControl(props)
return (
@@ -114,25 +83,21 @@ export function Label({ children, className, ...props }: LabelProps) {
)
}
interface InputProps extends Omit<ComponentPropsWithoutRef<'input'>, 'size'> {
as?: ElementType
size?: 'base'
children?: ReactNode
}
export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
export const Input = forwardRef(function Input(
{ as = 'input', size = 'base', className, children, ...props },
ref,
) {
const { className: _, ...field } = useControl(props)
const sizes = { base: 'h-12' }
return createElement(
return React.createElement(
as,
{
className: clsx(
'bg-white outline-none px-4 rounded-lg transition',
'border border-green-light dark:border-gray-700 dark:bg-gray-800',
'focus:ring-1 focus:border-green-secondary focus:ring-green-secondary focus:placeholder:text-transparent',
// Tailwind's won't inherit focus behavior; you must define it explicitly for both modes.
'dark:focus:border-green-secondary',
'aria-[invalid=true]:border-red-400 aria-[invalid=true]:ring-red-400',
'dark:aria-[invalid=true]:border-red-500 dark:aria-[invalid=true]:ring-red-500',
@@ -143,41 +108,34 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
),
ref,
...field,
} as React.InputHTMLAttributes<HTMLInputElement>,
},
children,
)
})
interface CheckboxProps extends ComponentPropsWithoutRef<'input'> {
className?: string
}
export const Checkbox = forwardRef(function Checkbox(
{ className, ...props },
ref,
) {
const { className: _, ...field } = useControl(props)
export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
function Checkbox({ className, ...props }, ref) {
const { className: _, ...field } = useControl(props)
return (
<input
type="checkbox"
className={clsx(
'text-green-secondary border border-gray-300',
'focus:ring-2 focus:border-green-secondary focus:ring-green-secondary focus:ring-offset-0 focus:ring-opacity-30',
'dark:border-gray-700 dark:bg-gray-800 focus:dark:border-security dark:checked:bg-green-secondary dark:checked:border-security dark:disabled:bg-gray-700',
'disabled:bg-gray-200 outline-none rounded transition',
className,
)}
ref={ref}
{...field}
/>
)
})
return (
<input
type="checkbox"
className={clsx(
'text-green-secondary border border-gray-300',
'focus:ring-2 focus:border-green-secondary focus:ring-green-secondary focus:ring-offset-0 focus:ring-opacity-30',
'dark:border-gray-700 dark:bg-gray-800 focus:dark:border-security dark:checked:bg-green-secondary dark:checked:border-security dark:disabled:bg-gray-700',
'disabled:bg-gray-200 outline-none rounded transition',
className,
)}
ref={ref}
{...field}
/>
)
},
)
interface ErrorProps {
children?: ReactNode
}
export function Error({ children }: ErrorProps) {
export function Error({ children }) {
return (
<div className="text-sm text-red-500 flex items-start gap-0.5">
<ExclamationCircleIcon className="w-4 mt-[1.5px] flex-shrink-0" />

View File

@@ -0,0 +1,11 @@
import clsx from 'clsx'
import React from 'react'
export function Heading({ as = 'h1', size = 'xl', className, children }) {
const sizes = { lg: 'text-lg lg:text-xl', xl: 'text-xl lg:text-2xl' }
return React.createElement(
as,
{ className: clsx('font-semibold', sizes?.[size], className) },
children,
)
}

View File

@@ -1,6 +1,6 @@
import clsx from 'clsx'
export function Loader({ className, ...props }: { className?: string }) {
export function Loader({ className, ...props }) {
return (
<svg
className={clsx('animate-spin', className)}