chore: remove formik dependency (#44744)

## Problem

Now that all forms have been migrated to `react-hook-form`, we can
remove `formik` as well as some unused deprecated components

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
  * Removed formik dependency from the UI package.
  * Removed Form and InputNumber components and their public re-exports.
  * Removed FormContext and the form hook exports.
* Simplified multiple components (Input, Checkbox, Radio, Select,
Toggle, Listbox) by removing form-context integration.
  * Removed InputNumber styling and theme configuration.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Gildas Garcia authored and GitHub committed 2026-04-10 16:07:08 +01:00
1 parent d48958c5e5
commit 56066fe1aa
16 files changed
+9 -840

No files matched your search

-2
View File
@@ -40,10 +40,8 @@ export * from './src/components/Select'
export * from './src/components/Listbox'
export * from './src/components/Checkbox'
export * from './src/components/Input'
export * from './src/components/InputNumber'
export * from './src/components/Radio'
export * from './src/components/Toggle'
export * from './src/components/Form'
export * from './src/components/ExpandingTextArea'
// layout
-1
View File
@@ -54,7 +54,6 @@
"cmdk": "^1.1.1",
"color": "^4.2.3",
"date-fns": "^2.30.0",
"formik": "^2.2.9",
"framer-motion": "^11.0.3",
"input-otp": "^1.2.3",
"lodash": "catalog:",
@@ -4,7 +4,6 @@ import React from 'react'
import { FormLayout } from '../../lib/Layout/FormLayout/FormLayout'
import styleHandler from '../../lib/theme/styleHandler'
import { useFormContext } from '../Form/FormContext'
import CheckboxStyles from './Checkbox.module.css'
import { CheckboxContext } from './CheckboxContext'
@@ -109,16 +108,12 @@ export function Checkbox({
afterLabel,
beforeLabel,
description,
checked,
value,
onChange,
onBlur,
size = 'medium',
disabled = false,
...props
}: InputProps) {
const { formContextOnChange, values, handleBlur } = useFormContext()
const __styles = styleHandler('checkbox')
return (
@@ -143,12 +138,6 @@ export function Checkbox({
// if that fails, use the id
const markupName = name ? name : markupId
// check if checkbox checked is true or false
// if neither true or false the checkbox will rely on native control
let active = checked ?? undefined
// if (values && !value) value = values[id || name]
let containerClasses = [__styles.container]
function onInputChange(e: React.ChangeEvent<HTMLInputElement>) {
@@ -156,23 +145,10 @@ export function Checkbox({
if (parentCallback) parentCallback(e)
// '`onChange` callback for this component
if (onChange) onChange(e)
// update form
if (formContextOnChange) formContextOnChange(e)
}
if (className) containerClasses.push(className)
if (values && checked === undefined) active = values[id || name]
function handleBlurEvent(e: React.FocusEvent<HTMLInputElement>) {
if (handleBlur) {
setTimeout(() => {
handleBlur(e)
}, 100)
}
if (onBlur) onBlur(e)
}
return (
<div className={containerClasses.join(' ')}>
<input
@@ -181,8 +157,6 @@ export function Checkbox({
type="checkbox"
className={[__styles.base, __styles.size[size]].join(' ')}
onChange={onInputChange}
onBlur={handleBlurEvent}
checked={active}
value={value ? value : markupId}
disabled={disabled}
{...props}
-104
View File
@@ -1,104 +0,0 @@
'use client'
import { FormikConfig, useFormik } from 'formik'
import { useReducer } from 'react'
import { FormContextProvider } from './FormContext'
// interface Props extends FormikProps<any>, Partial FormikConfig<any> {
interface Props extends Omit<FormikConfig<any>, 'validateOnMount' | 'validateOnChange'> {
children: any
handleIsSubmitting?: any
handleIsValidating?: any
name?: string
id?: string
className?: string
style?: React.CSSProperties
}
function errorReducer(state: any, action: any) {
if (!action.error) {
const payload = state
delete payload[action.key]
return payload
}
if (action) {
return {
...state,
[action.key]: action.error,
}
} else {
throw new Error()
}
}
/**
* @deprecated Use `import { Form_shadcn_ } from "ui"` instead
*/
export default function Form({ validate, ...props }: Props) {
const [fieldLevelErrors, dispatchErrors] = useReducer(errorReducer, null)
function handleFieldLevelValidation(key: any, error: string) {
dispatchErrors({ key, error })
}
const formik = useFormik({
validateOnBlur: true,
...props,
validationSchema: props.validationSchema,
initialValues: props.initialValues,
onSubmit: props.onSubmit,
validate:
validate ||
function () {
return fieldLevelErrors
},
})
// console.log('values', formik.values)
// console.log('errors', formik.errors)
// console.log('touched', formik.touched)
return (
<form
id={props.id}
name={props.name}
onSubmit={formik.handleSubmit}
className={props.className}
style={props.style}
method="POST"
>
<FormContextProvider
values={formik.values}
errors={formik.errors}
formContextOnChange={formik.handleChange}
handleBlur={formik.handleBlur}
touched={formik.touched}
fieldLevelValidation={handleFieldLevelValidation}
>
{props.children({
/** map of field names to specific error for that field */
errors: formik.errors, // errors,
// /** map of field names to whether the field has been touched */
touched: formik.touched,
/** whether the form is currently submitting */
isSubmitting: formik.isSubmitting,
/** whether the form is currently validating (prior to submission) */
isValidating: formik.isValidating,
/** Number of times user tried to submit the form */
submitCount: formik.submitCount,
/** Initial values of form */
initialValues: formik.initialValues,
/** Current values of form */
values: formik.values,
/** Resets the form back to initialValues */
handleReset: formik.handleReset,
/** Resets the form with custom values */
resetForm: formik.resetForm,
/** Manually sets a fields value */
setFieldValue: formik.setFieldValue,
})}
</FormContextProvider>
</form>
)
}
@@ -1,51 +0,0 @@
'use client'
import React, { createContext, useContext } from 'react'
interface ContextProps {
formContextOnChange: any
values: any
errors: any
handleBlur: ((e: React.FocusEvent<any, any>) => void) | null
touched: any
fieldLevelValidation: any
}
interface Provider extends ContextProps {
children?: React.ReactNode
}
// Make sure the shape of the default value passed to
// createContext matches the shape that the consumers expect!
const FormContext = createContext<ContextProps>({
formContextOnChange: null,
values: null,
errors: null,
handleBlur: null,
touched: null,
fieldLevelValidation: null,
})
export const FormContextProvider = (props: Provider) => {
const { formContextOnChange, values, errors, handleBlur, touched, fieldLevelValidation } = props
const value = {
formContextOnChange: formContextOnChange,
values: values,
errors: errors,
handleBlur: handleBlur,
touched: touched,
fieldLevelValidation: fieldLevelValidation,
}
return <FormContext.Provider value={value}>{props.children}</FormContext.Provider>
}
// context helper to avoid using a consumer component
export const useFormContext = () => {
const context = useContext(FormContext)
if (context === undefined) {
throw new Error(`useFormContextOnChange must be used within a FormContextProvider.`)
}
return context
}
@@ -1 +0,0 @@
export { default as Form } from './Form'
+1 -79
View File
@@ -1,7 +1,7 @@
'use client'
import { Copy } from 'lucide-react'
import React, { useEffect, useState } from 'react'
import React, { useState } from 'react'
import { HIDDEN_PLACEHOLDER } from '../../lib/constants'
import { FormLayout } from '../../lib/Layout/FormLayout/FormLayout'
@@ -11,7 +11,6 @@ import styleHandler from '../../lib/theme/styleHandler'
import { copyToClipboard } from '../../lib/utils'
import { cn } from '../../lib/utils/cn'
import { Button } from '../Button'
import { useFormContext } from '../Form/FormContext'
export interface Props extends Omit<
React.InputHTMLAttributes<HTMLInputElement>,
@@ -62,8 +61,6 @@ function Input({
beforeLabel,
labelOptional,
layout,
onChange,
onBlur,
onCopy,
placeholder,
type = 'text',
@@ -81,42 +78,6 @@ function Input({
const __styles = styleHandler('input')
const { formContextOnChange, values, errors, handleBlur, touched, fieldLevelValidation } =
useFormContext()
if (values && !value) value = values[id || name]
function handleBlurEvent(e: React.FocusEvent<HTMLInputElement>) {
if (handleBlur) {
setTimeout(() => {
handleBlur(e)
}, 100)
}
if (onBlur) onBlur(e)
}
if (!error) {
if (errors && !error) error = errors[id || name]
error = touched && touched[id] ? error : undefined
}
function onInputChange(e: React.ChangeEvent<HTMLInputElement>) {
// console.log('input event', e)
if (onChange) onChange(e)
// update form
if (formContextOnChange) formContextOnChange(e)
// run field level validation
if (validation) fieldLevelValidation(id, validation(e.target.value))
}
useEffect(() => {
if (validation) fieldLevelValidation(id, validation(value))
}, [])
// useEffect(() => {
// error = touched && touched[id] ? error : undefined
// }, [errors, touched])
function _onCopy(value: any) {
copyToClipboard(value, () => {
setCopyLabel('Copied')
@@ -163,8 +124,6 @@ function Input({
disabled={disabled}
id={id}
name={name}
onChange={onInputChange}
onBlur={handleBlurEvent}
onCopy={onCopy}
placeholder={placeholder}
ref={inputRef}
@@ -235,8 +194,6 @@ function TextArea({
beforeLabel,
labelOptional,
layout,
onChange,
onBlur,
placeholder,
value,
style,
@@ -250,7 +207,6 @@ function TextArea({
actions,
...props
}: TextAreaProps) {
const [charLength, setCharLength] = useState(0)
const [copyLabel, setCopyLabel] = useState('Copy')
function _onCopy(value: any) {
@@ -264,38 +220,6 @@ function TextArea({
})
}
const { formContextOnChange, values, errors, handleBlur, touched, fieldLevelValidation } =
useFormContext()
if (values && !value) value = values[id || name]
function handleBlurEvent(e: React.FocusEvent<HTMLTextAreaElement>) {
if (handleBlur) {
setTimeout(() => {
handleBlur(e)
}, 100)
}
if (onBlur) onBlur(e)
}
if (!error) {
if (errors && !error) error = errors[id || name]
error = touched && touched[id || name] ? error : undefined
}
function onInputChange(e: React.ChangeEvent<HTMLTextAreaElement>) {
setCharLength(e.target.value.length)
if (onChange) onChange(e)
// update form
if (formContextOnChange) formContextOnChange(e)
// run field level validation
if (validation) fieldLevelValidation(id, validation(e.target.value))
}
useEffect(() => {
if (validation) fieldLevelValidation(id, validation(value))
}, [])
const __styles = styleHandler('input')
let classes = [__styles.base]
@@ -329,8 +253,6 @@ function TextArea({
rows={rows}
cols={100}
placeholder={placeholder}
onChange={onInputChange}
onBlur={handleBlurEvent}
onCopy={onCopy}
value={value}
className={classes.join(' ')}
@@ -1,134 +0,0 @@
.sbui-inputnumber-container {
@apply relative;
}
.sbui-inputnumber {
@apply block box-border pl-3 pr-3 py-2 w-full rounded-md shadow-sm text-sm border border-solid transition-all;
@apply bg-white text-input-value-light border-input-border-light;
@apply focus:ring-input-border-focus-light focus:border-input-border-focus-light focus:outline-none;
@apply dark:bg-transparent dark:text-input-value-dark dark:border-input-border-dark;
@apply dark:focus:border-input-border-focus-dark dark:focus:ring-input-border-focus-dark;
/* box-shadow: 0 0 0 2px rgba(255, 255, 255, 0); */
font-family: inherit;
transition: box-shadow 0.3s ease-in-out;
-moz-appearance: textfield;
}
.sbui-inputnumber::-webkit-inner-spin-button,
.sbui-inputnumber::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
.sbui-inputnumber:focus {
box-shadow: 0 0 0 2px rgba(62, 207, 142, 0.1);
outline: 0;
}
.sbui-inputnumber--error {
@apply border-red-500;
}
.sbui-inputnumber--borderless {
@apply border-transparent shadow-none;
}
.sbui-inputnumber-actions-container {
@apply absolute inset-y-0 right-0 pl-3 pr-1 flex items-center;
}
.sbui-inputnumber-nav {
@apply hidden;
}
.sbui-inputnumber:focus + .sbui-inputnumber-nav {
@apply block;
}
.sbui-inputnumber-button {
@apply block box-border pl-3 pr-3 py-2 w-full rounded-md text-sm border border-solid;
@apply bg-transparent border-transparent;
@apply dark:text-white;
position: relative;
cursor: pointer;
width: 21px;
text-align: center;
color: #333;
font-size: 13px;
line-height: 1.5;
padding: 0;
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
.sbui-inputnumber-button:active {
background: #eaeaea;
background-clip: padding-box;
}
.sbui-inputnumber-button-up {
position: absolute;
height: 50%;
top: 0;
border-radius: 0 0.375rem 0 0;
line-height: 1.6;
}
.sbui-inputnumber-button-down {
position: absolute;
bottom: 0;
height: 50%;
border-radius: 0 0 0.375rem 0;
}
/*
Input sizes
*/
.sbui-inputnumber--tiny {
@apply px-2.5 py-1.5 text-xs;
}
.sbui-inputnumber--small {
@apply px-3 py-2 text-sm leading-4;
}
.sbui-inputnumber--medium {
@apply px-4 py-2 text-sm;
}
.sbui-inputnumber--large {
@apply px-4 py-2 text-base;
}
.sbui-inputnumber--xlarge {
@apply px-6 py-3 text-base;
}
.sbui-inputnumber-nav--tiny {
height: 30px;
}
.sbui-inputnumber-nav--small {
height: 34px;
}
.sbui-inputnumber-nav--medium {
height: 38px;
}
.sbui-inputnumber-nav--large {
height: 42px;
}
.sbui-inputnumber-nav--xlarge {
height: 50px;
}
/*
Input icon
*/
.sbui-inputnumber--with-icon {
@apply pl-7;
}
@@ -1,194 +0,0 @@
'use client'
import React, { useEffect } from 'react'
// import { IconChevronDown } from '../Icon/icons/IconChevronDown'
// import { IconChevronUp } from '../Icon/icons/IconChevronUp'
import { FormLayout } from '../../lib/Layout/FormLayout/FormLayout'
import InputErrorIcon from '../../lib/Layout/InputErrorIcon'
import InputIconContainer from '../../lib/Layout/InputIconContainer'
import styleHandler from '../../lib/theme/styleHandler'
import { useFormContext } from '../Form/FormContext'
export interface Props extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
defaultValue?: string | number
descriptionText?: string | React.ReactNode
error?: string
icon?: any
inputRef?: React.RefObject<HTMLInputElement>
label?: string
afterLabel?: string
beforeLabel?: string
labelOptional?: string | React.ReactNode
actions?: React.ReactNode
layout?: 'horizontal' | 'vertical'
size?: 'tiny' | 'small' | 'medium' | 'large' | 'xlarge'
validation?: (x: any) => void
}
/**
* @deprecated Use `import { Input_shadcn_ } from "ui"` with `type="number"` instead or ./ui-patterns/data-inputs/input with `type="number"`
*/
function InputNumber({
defaultValue,
descriptionText,
error,
icon,
inputRef,
label,
afterLabel,
beforeLabel,
labelOptional,
layout,
value = undefined,
actions,
size = 'medium',
validation,
id = '',
name = '',
...props
}: Props) {
const __styles = styleHandler('inputNumber')
const { formContextOnChange, values, errors, handleBlur, touched, fieldLevelValidation } =
useFormContext()
if (values && !value) value = values[id || name]
function handleBlurEvent(e: React.FocusEvent<HTMLInputElement>) {
if (handleBlur) handleBlur(e)
if (props.onBlur) props.onBlur(e)
}
if (!error) {
if (errors && !error) error = errors[id || name]
error = touched && touched[id || name] ? error : undefined
}
function onInputChange(e: React.ChangeEvent<HTMLInputElement>) {
if (props.onChange) props.onChange(e)
// update form
if (formContextOnChange) formContextOnChange(e)
// run field level validation
if (validation) fieldLevelValidation(id, validation(e.target.value))
}
useEffect(() => {
if (validation) fieldLevelValidation(id, validation(value))
}, [])
// const inputClasses = [InputNumberStyles['sbui-inputnumber']]
let inputClasses = [__styles.base]
// const iconUpClasses = [
// InputNumberStyles['sbui-inputnumber-button'],
// InputNumberStyles['sbui-inputnumber-button-up'],
// ]
// const inputRefCurrent = inputRef
// ? inputRef
// : React.createRef<HTMLInputElement>()
// const iconDownClasses = [
// InputNumberStyles['sbui-inputnumber-button'],
// InputNumberStyles['sbui-inputnumber-button-down'],
// ]
// const iconNavClasses = [InputNumberStyles['sbui-inputnumber-nav']]
// if (size) {
// inputClasses.push(InputNumberStyles[`sbui-inputnumber--${size}`])
// iconNavClasses.push(InputNumberStyles[`sbui-inputnumber-nav--${size}`])
// }
if (error) inputClasses.push(__styles.variants.error)
if (!error) inputClasses.push(__styles.variants.standard)
if (icon) inputClasses.push(__styles.with_icon[size])
if (size) inputClasses.push(__styles.size[size])
if (props.disabled) inputClasses.push(__styles.disabled)
// if (borderless)
// inputClasses.push(InputNumberStyles['sbui-inputnumber--borderless'])
// const onClickChevronUp = () => {
// inputRefCurrent.current?.stepUp()
// if (onChange) {
// inputRefCurrent.current?.dispatchEvent(
// new InputEvent('change', {
// view: window,
// bubbles: true,
// cancelable: false,
// })
// )
// }
// }
// const onClickChevronDown = () => {
// inputRefCurrent.current?.stepDown()
// if (onChange) {
// inputRefCurrent.current?.dispatchEvent(
// new InputEvent('change', {
// view: window,
// bubbles: true,
// cancelable: false,
// })
// )
// }
// }
return (
<div className={props.className}>
<FormLayout
label={label}
afterLabel={afterLabel}
beforeLabel={beforeLabel}
labelOptional={labelOptional}
layout={layout}
id={id}
error={error}
descriptionText={descriptionText}
style={props.style}
size={size}
>
<div className={__styles.container}>
<input
data-size={size}
id={id}
name={name}
onChange={onInputChange}
onBlur={handleBlurEvent}
type={'number'}
ref={inputRef}
value={value}
className={inputClasses.join(' ')}
{...props}
/>
{/* <div className={iconNavClasses.join(' ')}>
<IconChevronUp
className={iconUpClasses.join(' ')}
onClick={onClickChevronUp}
onMouseDown={(e: React.MouseEvent) => {
e.preventDefault()
}}
/>
<IconChevronDown
className={iconDownClasses.join(' ')}
onClick={onClickChevronDown}
onMouseDown={(e: React.MouseEvent) => {
e.preventDefault()
}}
/>
</div> */}
{icon && <InputIconContainer size={size} icon={icon} />}
{error || actions ? (
<div className={__styles.actions_container}>
{error && <InputErrorIcon size={size} />}
{actions && actions}
</div>
) : null}
</div>
</FormLayout>
</div>
)
}
export default InputNumber
@@ -1 +0,0 @@
export { default as InputNumber } from './InputNumber'
@@ -10,7 +10,6 @@ import InputErrorIcon from '../../lib/Layout/InputErrorIcon'
import InputIconContainer from '../../lib/Layout/InputIconContainer'
import styleHandler from '../../lib/theme/styleHandler'
import { cn } from '../../lib/utils/cn'
import { useFormContext } from '../Form/FormContext'
import { SelectContext } from './SelectContext'
export interface Props extends Omit<React.InputHTMLAttributes<HTMLButtonElement>, 'size'> {
@@ -70,24 +69,6 @@ function Listbox({
const triggerRef = useRef<HTMLButtonElement>(null)
const { formContextOnChange, values, errors, handleBlur, touched, fieldLevelValidation } =
useFormContext()
if (values && !value) {
value = values[id || name]
defaultValue = values[id || name]
}
function handleBlurEvent(e: React.FocusEvent<HTMLButtonElement>) {
if (handleBlur) handleBlur(e)
if (onBlur) onBlur(e)
}
if (!error) {
if (errors && !error) error = errors[id || name]
error = touched && touched[id || name] ? error : undefined
}
useEffect(() => {
if (value !== undefined) {
setSelected(value)
@@ -146,7 +127,7 @@ function Listbox({
return
} else if (defaultValue) {
setSelected(defaultValue)
const node: any = findNode(selected)
const node: any = findNode(defaultValue)
setSelectedNode(node?.props ? node.props : undefined)
return
} else {
@@ -161,28 +142,6 @@ function Listbox({
function handleOnChange(value: any) {
if (onChange) onChange(value)
setSelected(value)
/*
* Create change event for formik
* formik expects an input change event
*/
let event: any = {}
event.target = {
type: 'select',
name: name,
id: id,
value: value,
checked: undefined,
// outerHTML: undefined,
// options: undefined,
// multiple: undefined,
}
// update form
// Create a new 'change' event
if (formContextOnChange) formContextOnChange(event)
// run field level validation
if (validation) fieldLevelValidation(id, validation(value))
}
let selectClasses = [__styles.container, __styles.base, buttonClassName]
@@ -215,7 +174,7 @@ function Listbox({
data-size={size}
ref={triggerRef}
className={cn(selectClasses)}
onBlur={handleBlurEvent}
onBlur={onBlur}
onFocus={onFocus}
name={name}
id={id}
+1 -37
View File
@@ -4,7 +4,6 @@ import React, { useEffect, useState } from 'react'
import { FormLayout } from '../../lib/Layout/FormLayout/FormLayout'
import styleHandler from '../../lib/theme/styleHandler'
import { useFormContext } from '../Form/FormContext'
import { generateUID } from './../../lib/utils/randomIdGenerator'
import { RadioContext } from './RadioContext'
@@ -61,40 +60,12 @@ function RadioGroup({
const __styles = styleHandler('radio')
const {
formContextOnChange,
values,
errors,
// handleBlur,
touched,
fieldLevelValidation,
} = useFormContext()
if (values && !value) value = values[id || name]
// console.log('errors in. radio group', errors)
// console.log('values in radio group', values)
if (!error) {
if (errors && !error) error = errors[id || name]
error = touched && touched[id || name] ? error : undefined
}
useEffect(() => {
if (validation) fieldLevelValidation(id, validation(value))
}, [])
useEffect(() => {
setActiveId(value)
}, [value])
function parentCallback(e: React.ChangeEvent<HTMLInputElement>) {
if (onChange) onChange(e)
// update form
if (formContextOnChange) {
formContextOnChange(e)
}
// run field level validation
if (validation) fieldLevelValidation(id, validation(e.target.value))
setActiveId(e.target.id)
}
@@ -176,13 +147,6 @@ function Radio({
const inputName = name
const { handleBlur } = useFormContext()
function handleBlurEvent(e: React.FocusEvent<HTMLInputElement>) {
if (handleBlur) handleBlur(e)
if (onBlur) onBlur(e)
}
return (
<RadioContext.Consumer>
{({ parentCallback, type, name, activeId, parentSize }) => {
@@ -251,7 +215,7 @@ function Radio({
disabled={disabled}
value={value ? value : markupId}
onChange={(e) => onInputChange(e)}
onBlur={handleBlurEvent}
onBlur={onBlur}
/>
{addOnBefore}
{children || (
+1 -32
View File
@@ -1,12 +1,11 @@
'use client'
import React, { useEffect } from 'react'
import React from 'react'
import { FormLayout } from '../../lib/Layout/FormLayout/FormLayout'
import InputErrorIcon from '../../lib/Layout/InputErrorIcon'
import InputIconContainer from '../../lib/Layout/InputIconContainer'
import styleHandler from '../../lib/theme/styleHandler'
import { useFormContext } from '../Form/FormContext'
interface OptionProps {
value: string
@@ -60,8 +59,6 @@ function Select({
labelOptional,
layout,
name = '',
onChange,
onBlur,
placeholder,
required,
value = undefined,
@@ -72,32 +69,6 @@ function Select({
validation,
...props
}: Props) {
const { formContextOnChange, values, errors, handleBlur, touched, fieldLevelValidation } =
useFormContext()
if (values && !value) value = values[id]
function handleBlurEvent(e: React.FocusEvent<HTMLSelectElement>) {
if (handleBlur) handleBlur(e)
if (onBlur) onBlur(e)
}
if (!error) {
if (errors && !error) error = errors[id || name]
error = touched && touched[id || name] ? error : undefined
}
function onInputChange(e: React.ChangeEvent<HTMLSelectElement>) {
if (onChange) onChange(e)
// update form
if (formContextOnChange) formContextOnChange(e)
// run field level validation
if (validation) fieldLevelValidation(id, validation(e.target.value))
}
useEffect(() => {
if (validation) fieldLevelValidation(id, validation(value))
}, [])
const __styles = styleHandler('select')
let classesContainer = [__styles.container]
@@ -133,8 +104,6 @@ function Select({
autoComplete={autoComplete}
autoFocus={autofocus}
className={classes.join(' ')}
onChange={onInputChange}
onBlur={handleBlurEvent}
ref={inputRef}
value={value}
disabled={disabled}
@@ -5,7 +5,6 @@ import React, { useEffect, useState } from 'react'
import { FormLayout } from '../../lib/Layout/FormLayout/FormLayout'
import styleHandler from '../../lib/theme/styleHandler'
import { useFormContext } from '../Form/FormContext'
interface Props extends Omit<React.HTMLAttributes<HTMLButtonElement>, 'size'> {
name?: string
@@ -23,7 +22,6 @@ interface Props extends Omit<React.HTMLAttributes<HTMLButtonElement>, 'size'> {
align?: 'right' | 'left'
size?: 'tiny' | 'small' | 'medium' | 'large' | 'xlarge'
labelLayout?: 'horizontal' | 'vertical'
validation?: (x: any) => void
}
/**
@@ -41,23 +39,15 @@ function Toggle({
beforeLabel,
labelOptional,
onChange,
onBlur,
defaultChecked,
checked,
className,
align = 'left',
size = 'medium',
validation,
labelLayout,
...props
}: Props) {
const __styles = styleHandler('toggle')
const { formContextOnChange, values, errors, handleBlur, touched, fieldLevelValidation } =
useFormContext()
if (values && !checked) checked = values[id || name]
const [intChecked, setIntChecked] = useState((defaultChecked || checked) ?? false)
// check if toggle checked is true or false
@@ -68,18 +58,6 @@ function Toggle({
setIntChecked(active)
}, [])
function handleBlurEvent(e: React.FocusEvent<HTMLButtonElement>) {
setTimeout(() => {
if (handleBlur) handleBlur(e)
}, 100)
if (onBlur) onBlur(e)
}
if (!error) {
if (errors && !error) error = errors[id || name]
error = touched && touched[id || name] ? error : undefined
}
function onClick() {
// '`onChange` callback for this component
@@ -87,27 +65,6 @@ function Toggle({
if (onChange) onChange(!active)
setIntChecked(!intChecked)
/*
* Create change event for formik
* formik expects an input change event
*/
let event: any = {}
event.target = {
type: 'checkbox',
name: name,
id: id,
value: !active,
checked: !active,
// outerHTML: undefined,
// options: undefined,
// multiple: undefined,
}
// update form
if (formContextOnChange) formContextOnChange(event)
// run field level validation
if (validation) fieldLevelValidation(id, validation(!intChecked))
}
let toggleClasses = [__styles.base, __styles.handle_container[size]]
@@ -139,7 +96,6 @@ function Toggle({
className={clsx(...toggleClasses, disabled && 'opacity-50 cursor-default')}
onClick={onClick}
disabled={disabled}
onBlur={handleBlurEvent}
{...props}
>
<span aria-hidden="true" className={handleClasses.join(' ')}></span>
-44
View File
@@ -511,50 +511,6 @@ export default {
chevron: 'h-5 w-5 text-foreground-lighter',
},
/*
* Input Number
*/
inputNumber: {
base: `
block
box-border
w-full
rounded-md
shadow-sm
transition-all
text-foreground
border
focus-visible:shadow-md
${defaults.focus}
focus-visible:border-foreground-muted
focus-visible:ring-background-control
${defaults.placeholder}
appearance-none
bg-none
`,
variants: {
standard: `
bg-control
border border-strong
`,
error: `
bg-destructive-200
border border-destructive-500
focus:ring-destructive-400
placeholder:text-destructive-400
`,
},
disabled: 'opacity-50',
container: 'relative',
with_icon: with_icon_spacing_sizes,
size: {
...default__padding_and_text,
},
actions_container: 'absolute inset-y-0 right-0 pl-3 pr-1 flex space-x-1 items-center',
},
/*
* Checkbox
*
+4 -47
View File
@@ -1330,7 +1330,7 @@ importers:
version: 2.11.3(@types/node@22.13.14)(typescript@6.0.2)
next-router-mock:
specifier: ^0.9.13
version: 0.9.13(next@16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)
version: 0.9.13(next@16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)
node-mocks-http:
specifier: ^1.17.2
version: 1.17.2(@types/node@22.13.14)
@@ -2283,7 +2283,7 @@ importers:
version: 18.3.0
next-router-mock:
specifier: ^0.9.13
version: 0.9.13(next@16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)
version: 0.9.13(next@16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)
tsconfig:
specifier: workspace:*
version: link:../tsconfig
@@ -2542,9 +2542,6 @@ importers:
date-fns:
specifier: ^2.30.0
version: 2.30.0
formik:
specifier: ^2.2.9
version: 2.4.9(@types/react@18.3.3)(react@18.3.1)
framer-motion:
specifier: ^11.0.3
version: 11.11.17(@emotion/is-prop-valid@1.4.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -2846,7 +2843,7 @@ importers:
version: link:../api-types
next-router-mock:
specifier: ^0.9.13
version: 0.9.13(next@16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)
version: 0.9.13(next@16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1)
tsx:
specifier: 'catalog:'
version: 4.20.3
@@ -9303,11 +9300,6 @@ packages:
'@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
'@types/hoist-non-react-statics@3.3.7':
resolution: {integrity: sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==}
peerDependencies:
'@types/react': '*'
'@types/js-cookie@2.2.7':
resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==}
@@ -11391,10 +11383,6 @@ packages:
resolution: {integrity: sha512-RHd9ABw4Fvk+gYDWqwOftG849x0bYOySl/RgX0tLI9i27ZIeSO91mLZJEp7oPHOMFqHvpgu21YptmDt0FYD/0A==}
engines: {node: '>=0.10.0'}
deepmerge@2.2.1:
resolution: {integrity: sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==}
engines: {node: '>=0.10.0'}
deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
@@ -12367,11 +12355,6 @@ packages:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
engines: {node: '>=12.20.0'}
formik@2.4.9:
resolution: {integrity: sha512-5nI94BMnlFDdQRBY4Sz39WkhxajZJ57Fzs8wVbtsQlm5ScKIR1QLYqv/ultBnobObtlUyxpxoLodpixrsf36Og==}
peerDependencies:
react: '>=16.8.0'
forwarded-parse@2.1.2:
resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==}
@@ -16200,9 +16183,6 @@ packages:
peerDependencies:
react: '>=16.13.1'
react-fast-compare@2.0.4:
resolution: {integrity: sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==}
react-fast-compare@3.2.2:
resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==}
@@ -26975,11 +26955,6 @@ snapshots:
dependencies:
'@types/unist': 2.0.8
'@types/hoist-non-react-statics@3.3.7(@types/react@18.3.3)':
dependencies:
'@types/react': 18.3.3
hoist-non-react-statics: 3.3.2
'@types/js-cookie@2.2.7': {}
'@types/js-yaml@4.0.6': {}
@@ -29451,8 +29426,6 @@ snapshots:
kind-of: 3.2.2
rename-keys: 1.2.0
deepmerge@2.2.1: {}
deepmerge@4.3.1: {}
default-browser-id@5.0.0: {}
@@ -30603,20 +30576,6 @@ snapshots:
dependencies:
fetch-blob: 3.2.0
formik@2.4.9(@types/react@18.3.3)(react@18.3.1):
dependencies:
'@types/hoist-non-react-statics': 3.3.7(@types/react@18.3.3)
deepmerge: 2.2.1
hoist-non-react-statics: 3.3.2
lodash: 4.18.1
lodash-es: 4.18.1
react: 18.3.1
react-fast-compare: 2.0.4
tiny-warning: 1.0.3
tslib: 2.8.1
transitivePeerDependencies:
- '@types/react'
forwarded-parse@2.1.2: {}
forwarded@0.2.0: {}
@@ -33763,7 +33722,7 @@ snapshots:
dependencies:
js-yaml-loader: 1.2.2
next-router-mock@0.9.13(next@16.1.7(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1):
next-router-mock@0.9.13(next@16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react@18.3.1):
dependencies:
next: 16.1.7(@babel/core@7.29.0(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4)
react: 18.3.1
@@ -35451,8 +35410,6 @@ snapshots:
'@babel/runtime': 7.26.10
react: 18.3.1
react-fast-compare@2.0.4: {}
react-fast-compare@3.2.2: {}
react-from-dom@0.6.2(react@18.3.1):