@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
1 lines • 8.41 kB
Source Map (JSON)
{"version":3,"file":"atoms.mjs","names":["useControlledState"],"sources":["../../../src/base-ui/Switch/atoms.tsx"],"sourcesContent":["'use client';\n\nimport { Switch } from '@base-ui/react/switch';\nimport { cx } from 'antd-style';\nimport { useReducedMotion } from 'motion/react';\nimport type { KeyboardEvent, MouseEvent } from 'react';\nimport { createContext, use, useMemo, useRef, useState } from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport { useMotionComponent } from '@/MotionProvider';\n\nimport { rootVariants, styles, thumbVariants } from './style';\nimport type {\n SwitchChangeEventHandler,\n SwitchContextType,\n SwitchIconPosition,\n SwitchIconProps,\n SwitchRootProps,\n SwitchThumbProps,\n} from './type';\n\nconst SwitchContext = createContext<SwitchContextType | null>(null);\n\nexport const useSwitchContext = () => {\n const context = use(SwitchContext);\n if (!context) {\n throw new Error('useSwitchContext must be used within a SwitchRoot');\n }\n return context;\n};\n\ntype SwitchRootInternalProps = Omit<SwitchRootProps, 'onCheckedChange' | 'onClick'> & {\n onCheckedChange?: SwitchChangeEventHandler;\n onClick?: SwitchChangeEventHandler;\n};\n\nexport const SwitchRoot = ({\n checked,\n className,\n defaultChecked,\n onCheckedChange,\n onClick,\n size = 'default',\n children,\n disabled,\n readOnly,\n required,\n inputRef,\n id,\n name,\n ...rest\n}: SwitchRootInternalProps) => {\n const Motion = useMotionComponent();\n const [isPressed, setIsPressed] = useState(false);\n const lastEventRef = useRef<MouseEvent<HTMLButtonElement> | KeyboardEvent<HTMLButtonElement>>(\n null,\n );\n\n const [isChecked, setIsChecked] = useControlledState(defaultChecked ?? false, {\n defaultValue: defaultChecked,\n onChange: (value: boolean) => {\n if (lastEventRef.current) {\n onCheckedChange?.(value, lastEventRef.current);\n }\n },\n value: checked,\n });\n\n const baseClassName = rootVariants({ size });\n\n const contextValue = useMemo(\n () => ({\n isChecked: Boolean(isChecked),\n isPressed,\n setIsChecked: (value: boolean) => setIsChecked(value),\n setIsPressed,\n }),\n [isChecked, isPressed, setIsChecked],\n );\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n lastEventRef.current = event;\n onClick?.(!isChecked, event);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n lastEventRef.current = event;\n }\n (rest as any).onKeyDown?.(event);\n };\n\n return (\n <SwitchContext value={contextValue}>\n <Switch.Root\n nativeButton\n checked={isChecked}\n defaultChecked={defaultChecked}\n disabled={disabled}\n id={id}\n inputRef={inputRef}\n name={name}\n readOnly={readOnly}\n required={required}\n render={\n <Motion.button\n {...rest}\n className={cx(baseClassName, className)}\n initial={false}\n whileTap=\"tap\"\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onTap={() => setIsPressed(false)}\n onTapCancel={() => setIsPressed(false)}\n onTapStart={() => setIsPressed(true)}\n />\n }\n onCheckedChange={setIsChecked}\n >\n {children}\n </Switch.Root>\n </SwitchContext>\n );\n};\n\nSwitchRoot.displayName = 'SwitchRoot';\n\nexport const SwitchThumb = ({\n className,\n pressedAnimation,\n size = 'default',\n transition = { damping: 24, stiffness: 360, type: 'spring' },\n children,\n ...rest\n}: SwitchThumbProps) => {\n const Motion = useMotionComponent();\n const { isPressed } = useSwitchContext();\n const shouldReduceMotion = useReducedMotion();\n const baseClassName = thumbVariants({ size });\n\n const defaultPressedAnimation = {\n width: size === 'small' ? 16 : 22,\n };\n\n const effectiveAnimate =\n !shouldReduceMotion && isPressed ? pressedAnimation || defaultPressedAnimation : undefined;\n const effectiveTransition = shouldReduceMotion ? { duration: 0 } : transition;\n\n return (\n <Switch.Thumb\n render={\n <Motion.span\n layout\n animate={effectiveAnimate}\n className={cx(baseClassName, className)}\n transition={effectiveTransition}\n {...rest}\n >\n {children}\n </Motion.span>\n }\n />\n );\n};\n\nSwitchThumb.displayName = 'SwitchThumb';\n\nconst getIconPositionClass = (position: SwitchIconPosition, size: 'default' | 'small') => {\n if (position === 'thumb') return styles.iconThumb;\n if (position === 'left') return size === 'small' ? styles.iconLeftSmall : styles.iconLeft;\n return size === 'small' ? styles.iconRightSmall : styles.iconRight;\n};\n\nexport const SwitchIcon = ({\n children,\n className,\n position,\n size = 'default',\n transition = { bounce: 0, type: 'spring' },\n ...rest\n}: SwitchIconProps) => {\n const Motion = useMotionComponent();\n const { isChecked } = useSwitchContext();\n const shouldReduceMotion = useReducedMotion();\n\n const isAnimated = useMemo(() => {\n if (position === 'right') return !isChecked;\n if (position === 'left') return isChecked;\n if (position === 'thumb') return true;\n return false;\n }, [position, isChecked]);\n\n const positionClass = getIconPositionClass(position, size);\n const effectiveTransition = shouldReduceMotion ? { duration: 0 } : transition;\n\n return (\n <Motion.span\n animate={isAnimated ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0 }}\n className={cx(styles.icon, positionClass, className)}\n transition={effectiveTransition}\n {...rest}\n >\n {children}\n </Motion.span>\n );\n};\n\nSwitchIcon.displayName = 'SwitchIcon';\n\nexport { styles as switchStyles } from './style';\n"],"mappings":"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"}