mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
- Added @metabuilder/hooks workspace package at root
- Consolidated 30 React hooks from across codebase into single module
- Implemented conditional exports for tree-shaking support
- Added comprehensive package.json with build/lint/typecheck scripts
- Created README.md documenting hook categories and usage patterns
- Updated root package.json workspaces array to include hooks
- Supports multi-version peer dependencies (React 18/19, Redux 8/9)
Usage:
import { useDashboardLogic } from '@metabuilder/hooks'
import { useLoginLogic } from '@metabuilder/hooks/useLoginLogic'
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
95 lines
2.6 KiB
TypeScript
95 lines
2.6 KiB
TypeScript
import React, { forwardRef, createContext, useContext, Children, cloneElement, isValidElement, useId } from 'react'
|
|
|
|
/**
|
|
* RadioGroup context value
|
|
*/
|
|
interface RadioGroupContextValue {
|
|
name?: string
|
|
value?: string
|
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
|
}
|
|
|
|
const RadioGroupContext = createContext<RadioGroupContextValue>({})
|
|
|
|
/**
|
|
* Hook to access RadioGroup context
|
|
*/
|
|
export const useRadioGroup = () => useContext(RadioGroupContext)
|
|
|
|
/**
|
|
* Props for RadioGroup component
|
|
*/
|
|
export interface RadioGroupProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
children?: React.ReactNode
|
|
/** Name attribute for all radio buttons */
|
|
name?: string
|
|
/** Currently selected value */
|
|
value?: string
|
|
/** Default value for uncontrolled usage */
|
|
defaultValue?: string
|
|
/** Called when selection changes */
|
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
|
/** Stack radio buttons horizontally */
|
|
row?: boolean
|
|
}
|
|
|
|
/**
|
|
* RadioGroup - Groups Radio buttons with shared name and selection state
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* <RadioGroup name="size" value={size} onChange={handleChange}>
|
|
* <Radio value="small" label="Small" />
|
|
* <Radio value="medium" label="Medium" />
|
|
* <Radio value="large" label="Large" />
|
|
* </RadioGroup>
|
|
* ```
|
|
*/
|
|
export const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
|
(
|
|
{
|
|
children,
|
|
name: nameProp,
|
|
value,
|
|
defaultValue,
|
|
onChange,
|
|
row = false,
|
|
className = '',
|
|
...props
|
|
},
|
|
ref
|
|
) => {
|
|
const generatedName = useId()
|
|
const name = nameProp ?? generatedName
|
|
|
|
// Enhance child Radio components with group context
|
|
const enhancedChildren = Children.map(children, (child) => {
|
|
if (isValidElement(child)) {
|
|
const childValue = (child.props as Record<string, unknown>).value as string | undefined
|
|
return cloneElement(child as React.ReactElement<Record<string, unknown>>, {
|
|
name,
|
|
checked: value !== undefined ? childValue === value : undefined,
|
|
defaultChecked: defaultValue !== undefined ? childValue === defaultValue : undefined,
|
|
onChange,
|
|
})
|
|
}
|
|
return child
|
|
})
|
|
|
|
return (
|
|
<RadioGroupContext.Provider value={{ name, value, onChange }}>
|
|
<div
|
|
ref={ref}
|
|
role="radiogroup"
|
|
className={`radio-group ${row ? 'radio-group--row' : ''} ${className}`}
|
|
{...props}
|
|
>
|
|
{enhancedChildren}
|
|
</div>
|
|
</RadioGroupContext.Provider>
|
|
)
|
|
}
|
|
)
|
|
|
|
RadioGroup.displayName = 'RadioGroup'
|