{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "card", "type": "registry:ui", "title": "Card", "description": "Card from @pitsi-ui/native for native projects.", "dependencies": [ "@gorhom/bottom-sheet@^5.2.8", "react-native-reanimated@^4.1.1", "tailwind-variants@^3.2.2", "uniwind" ], "registryDependencies": [], "files": [ { "path": "registry/native-ui/src/components/card/card.tsx", "content": "import { forwardRef } from \"react\";\nimport { type TextProps, View, type ViewProps } from \"react-native\";\nimport { tv } from \"tailwind-variants\";\nimport { HeroText } from \"../../helpers/internal/components/hero-text\";\nimport type { TextRef, ViewRef } from \"../../helpers/internal/types\";\nimport { combineStyles } from \"../../helpers/internal/utils\";\nimport { Surface, type SurfaceRootProps } from \"../surface\";\n\n/* -------------------------------------------------------------------------------------------------\n * Constants\n * -----------------------------------------------------------------------------------------------*/\n/**\n * Display names for Card components\n */\nexport const DISPLAY_NAME = {\n ROOT: \"PitsiUINative.Card.Root\",\n HEADER: \"PitsiUINative.Card.Header\",\n BODY: \"PitsiUINative.Card.Body\",\n FOOTER: \"PitsiUINative.Card.Footer\",\n TITLE: \"PitsiUINative.Card.Title\",\n DESCRIPTION: \"PitsiUINative.Card.Description\",\n};\n\n/* -------------------------------------------------------------------------------------------------\n * Types\n * -----------------------------------------------------------------------------------------------*/\n/**\n * Props for the Card.Root component\n */\nexport interface CardRootProps extends SurfaceRootProps {}\n\n/**\n * Props for the Card.Header component\n */\nexport interface CardHeaderProps extends ViewProps {\n /**\n * Children elements to be rendered inside the header\n */\n children?: React.ReactNode;\n /**\n * Additional CSS classes\n */\n className?: string;\n}\n\n/**\n * Props for the Card.Body component\n */\nexport interface CardBodyProps extends ViewProps {\n /**\n * Children elements to be rendered inside the body\n */\n children?: React.ReactNode;\n /**\n * Additional CSS classes\n */\n className?: string;\n}\n\n/**\n * Props for the Card.Footer component\n */\nexport interface CardFooterProps extends ViewProps {\n /**\n * Children elements to be rendered inside the footer\n */\n children?: React.ReactNode;\n /**\n * Additional CSS classes\n */\n className?: string;\n}\n\n/**\n * Props for the Card.Title component\n */\nexport interface CardTitleProps extends TextProps {\n /**\n * Children elements to be rendered as the title text\n */\n children?: React.ReactNode;\n /**\n * Additional CSS classes\n */\n className?: string;\n}\n\n/**\n * Props for the Card.Description component\n */\nexport interface CardDescriptionProps extends TextProps {\n /**\n * Children elements to be rendered as the description text\n */\n children?: React.ReactNode;\n /**\n * Additional CSS classes\n */\n className?: string;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Styles\n * -----------------------------------------------------------------------------------------------*/\nconst root = tv({\n base: \"min-h-32\",\n});\n\nconst header = tv({\n base: \"\",\n});\n\nconst body = tv({\n base: \"\",\n});\n\nconst footer = tv({\n base: \"\",\n});\n\nconst label = tv({\n base: \"text-lg text-foreground font-medium\",\n});\n\nconst description = tv({\n base: \"text-base text-muted\",\n});\n\nexport const cardClassNames = combineStyles({\n root,\n header,\n body,\n footer,\n label,\n description,\n});\n\n/* -------------------------------------------------------------------------------------------------\n * Card.Root\n * -----------------------------------------------------------------------------------------------*/\nconst CardRoot = forwardRef((props, ref) => {\n const { children, variant = \"default\", className, ...restProps } = props;\n\n const rootClassName = cardClassNames.root({ className });\n\n return (\n \n {children}\n \n );\n});\n\n/* -------------------------------------------------------------------------------------------------\n * Card.Header\n * -----------------------------------------------------------------------------------------------*/\nconst CardHeader = forwardRef((props, ref) => {\n const { children, className, ...restProps } = props;\n\n const headerClassName = cardClassNames.header({ className });\n\n return (\n \n {children}\n \n );\n});\n\n/* -------------------------------------------------------------------------------------------------\n * Card.Body\n * -----------------------------------------------------------------------------------------------*/\nconst CardBody = forwardRef((props, ref) => {\n const { children, className, ...restProps } = props;\n\n const bodyClassName = cardClassNames.body({ className });\n\n return (\n \n {children}\n \n );\n});\n\n/* -------------------------------------------------------------------------------------------------\n * Card.Footer\n * -----------------------------------------------------------------------------------------------*/\nconst CardFooter = forwardRef((props, ref) => {\n const { children, className, ...restProps } = props;\n\n const footerClassName = cardClassNames.footer({ className });\n\n return (\n \n {children}\n \n );\n});\n\n/* -------------------------------------------------------------------------------------------------\n * Card.Title\n * -----------------------------------------------------------------------------------------------*/\nconst CardTitle = forwardRef((props, ref) => {\n const { children, className, ...restProps } = props;\n\n const titleClassName = cardClassNames.label({ className });\n\n return (\n \n {children}\n \n );\n});\n\n/* -------------------------------------------------------------------------------------------------\n * Card.Description\n * -----------------------------------------------------------------------------------------------*/\nconst CardDescription = forwardRef((props, ref) => {\n const { children, className, ...restProps } = props;\n\n const descriptionClassName = cardClassNames.description({\n className,\n });\n\n return (\n \n {children}\n \n );\n});\n\nCardRoot.displayName = DISPLAY_NAME.ROOT;\nCardHeader.displayName = DISPLAY_NAME.HEADER;\nCardBody.displayName = DISPLAY_NAME.BODY;\nCardFooter.displayName = DISPLAY_NAME.FOOTER;\nCardTitle.displayName = DISPLAY_NAME.TITLE;\nCardDescription.displayName = DISPLAY_NAME.DESCRIPTION;\n\n/* -------------------------------------------------------------------------------------------------\n * Compound export\n *\n * @component Card - Main container that extends Surface component. Provides base card structure\n * with configurable surface variants and handles overall layout.\n * @component Card.Header - Header section for top-aligned content like icons or badges.\n * @component Card.Body - Main content area with flex-1 that expands to fill all available space\n * between Card.Header and Card.Footer.\n * @component Card.Title - Title text with foreground color and medium font weight.\n * @component Card.Description - Description text with muted color and smaller font size.\n * @component Card.Footer - Footer section for bottom-aligned actions like buttons.\n *\n * @see https://pitsiui.com/docs/native/components/card\n * -----------------------------------------------------------------------------------------------*/\nconst Card = Object.assign(CardRoot, {\n /** @optional Top-aligned header section */\n Header: CardHeader,\n /** @optional Main content area that expands between header and footer */\n Body: CardBody,\n /** @optional Bottom-aligned footer for actions */\n Footer: CardFooter,\n /** @optional Title text with styled typography */\n Title: CardTitle,\n /** @optional Description text with muted styling */\n Description: CardDescription,\n});\n\nexport { Card };\nexport default Card;\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/components/card/card.tsx" }, { "path": "registry/native-ui/src/components/card/index.ts", "content": "export type {\n CardBodyProps,\n CardDescriptionProps,\n CardFooterProps,\n CardHeaderProps,\n CardRootProps,\n CardTitleProps,\n} from \"./card\";\nexport { Card, cardClassNames, default } from \"./card\";\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/components/card/index.ts" }, { "path": "registry/native-ui/src/components/surface/index.ts", "content": "export type { SurfaceRootProps, SurfaceVariant } from \"./surface\";\nexport {\n default,\n Surface,\n surfaceClassNames,\n useSurface,\n} from \"./surface\";\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/components/surface/index.ts" }, { "path": "registry/native-ui/src/components/surface/surface.tsx", "content": "import { forwardRef, useMemo } from \"react\";\nimport { StyleSheet, View, type ViewProps } from \"react-native\";\nimport { tv } from \"tailwind-variants\";\n\nimport { AnimationSettingsProvider } from \"../../helpers/internal/contexts\";\nimport type { AnimationRootDisableAll, ViewRef } from \"../../helpers/internal/types\";\nimport { combineStyles, createContext } from \"../../helpers/internal/utils\";\nimport * as Slot from \"../../primitives/slot\";\nimport { useSurfaceRootAnimation } from \"./surface.animation\";\n\n/* -------------------------------------------------------------------------------------------------\n * Constants\n * -----------------------------------------------------------------------------------------------*/\n/**\n * Display names for Surface components\n */\nexport const DISPLAY_NAME = {\n ROOT: \"PitsiUINative.Surface.Root\",\n};\n\n/* -------------------------------------------------------------------------------------------------\n * Types\n * -----------------------------------------------------------------------------------------------*/\n/**\n * Variant options for the Surface component\n */\nexport type SurfaceVariant = \"default\" | \"secondary\" | \"tertiary\" | \"transparent\";\n\n/**\n * Props for the Surface.Root component\n */\nexport interface SurfaceRootProps extends ViewProps {\n /**\n * Children elements to be rendered inside the surface\n */\n children?: React.ReactNode;\n /**\n * Visual variant of the surface\n * @default 'default'\n */\n variant?: SurfaceVariant;\n /**\n * Additional CSS classes\n */\n className?: string;\n /**\n * Animation configuration for surface\n * - `\"disable-all\"`: Disable all animations including children\n * - `undefined`: Use default animations\n */\n animation?: AnimationRootDisableAll;\n /**\n * When `true`, merges surface styling onto the single child element (Slot pattern).\n * The child must be one React element. Uses `Slot.View` internally.\n * @default false\n */\n asChild?: boolean;\n}\n\n/**\n * Context value for the Surface component\n */\nexport interface SurfaceContextValue {\n /**\n * Visual variant of the surface\n */\n variant: SurfaceVariant;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Styles\n * -----------------------------------------------------------------------------------------------*/\nconst root = tv({\n base: \"p-4 rounded-3xl shadow-surface overflow-hidden\",\n variants: {\n variant: {\n default: \"bg-surface\",\n secondary: \"bg-surface-secondary\",\n tertiary: \"bg-surface-tertiary\",\n transparent: \"bg-transparent shadow-none\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n});\n\nexport const surfaceClassNames = combineStyles({\n root,\n});\n\nexport const surfaceStyleSheet = StyleSheet.create({\n root: {\n borderCurve: \"continuous\",\n },\n});\n\n/* -------------------------------------------------------------------------------------------------\n * Context\n * -----------------------------------------------------------------------------------------------*/\nconst [SurfaceProvider, useSurface] = createContext({\n name: \"SurfaceContext\",\n strict: false,\n});\n\n/* -------------------------------------------------------------------------------------------------\n * Surface\n * -----------------------------------------------------------------------------------------------*/\nconst Surface = forwardRef(\n (\n { children, variant = \"default\", className, style, animation, asChild = false, ...props },\n ref,\n ) => {\n const RootComponent = asChild ? Slot.View : View;\n\n const rootClassName = surfaceClassNames.root({ variant, className });\n\n const { isAllAnimationsDisabled } = useSurfaceRootAnimation({\n animation,\n });\n\n const animationSettingsContextValue = useMemo(\n () => ({\n isAllAnimationsDisabled,\n }),\n [isAllAnimationsDisabled],\n );\n\n const contextValue = useMemo(() => ({ variant }), [variant]);\n\n return (\n \n \n \n {children}\n \n \n \n );\n },\n);\n\nSurface.displayName = DISPLAY_NAME.ROOT;\n\n/**\n * Surface component\n *\n * @component Surface - Container component that provides elevation and background styling.\n * - Polymorphic via `asChild` prop (Slot.View merges surface styling onto the child)\n *\n * @see Full documentation: https://pitsiui.com/docs/native/components/surface\n */\nexport default Surface;\n\nexport { Surface, useSurface };\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/components/surface/surface.tsx" }, { "path": "registry/native-ui/src/helpers/external/hooks/index.ts", "content": "export { useTextComponent } from \"../../../providers/text-component/index\";\nexport * from \"../../internal/hooks/use-combined-animation-disabled-state\";\nexport * from \"./use-bottom-sheet-aware-handlers\";\nexport * from \"./use-is-on-surface\";\nexport * from \"./use-theme-color\";\n", "type": "registry:hook", "target": "@components/pitsi-ui/native-ui/src/helpers/external/hooks/index.ts" }, { "path": "registry/native-ui/src/helpers/external/hooks/use-bottom-sheet-aware-handlers.ts", "content": "import { useCallback } from \"react\";\nimport { type BlurEvent, type FocusEvent, findNodeHandle, TextInput } from \"react-native\";\nimport GorhomBottomSheetPackage from \"../../../optional/gorhom-bottom-sheet\";\n\n/**\n * Return type for the bottom-sheet-aware handlers hook\n */\ninterface UseBottomSheetAwareHandlersReturn {\n /** Focus handler that notifies the bottom sheet about the keyboard target */\n onFocus: (e: FocusEvent) => void;\n /** Blur handler that conditionally clears the keyboard target in the bottom sheet */\n onBlur: (e: BlurEvent) => void;\n}\n\n/**\n * Hook that provides onFocus/onBlur handlers for managing bottom sheet\n * keyboard state when an input is rendered inside a BottomSheet context.\n *\n * Uses `useBottomSheetInternal(true)` (unsafe mode) so it returns `null`\n * instead of throwing when called outside a BottomSheet. When inside a\n * BottomSheet it returns handlers that wire into the keyboard state\n * management logic required by `@gorhom/bottom-sheet`.\n *\n * Pass the returned handlers to your `` or `` component:\n *\n * ```tsx\n * const { onFocus, onBlur } = useBottomSheetAwareHandlers();\n * \n * ```\n *\n * @returns onFocus and onBlur handlers for bottom sheet keyboard management\n */\nexport function useBottomSheetAwareHandlers(): UseBottomSheetAwareHandlersReturn {\n const useBottomSheetInternal = GorhomBottomSheetPackage?.useBottomSheetInternal;\n const bottomSheetContext = useBottomSheetInternal?.(true) ?? null;\n\n const isActive = bottomSheetContext !== null;\n\n /**\n * Handles focus event: notifies the bottom sheet about the keyboard target.\n */\n const onFocus = useCallback(\n (e: FocusEvent) => {\n if (isActive && bottomSheetContext) {\n bottomSheetContext.animatedKeyboardState.set((state: Record) => ({\n ...state,\n target: e.nativeEvent.target,\n }));\n }\n },\n [isActive, bottomSheetContext],\n );\n\n /**\n * Handles blur event: conditionally clears the keyboard target in the\n * bottom sheet state.\n */\n const onBlur = useCallback(\n (e: BlurEvent) => {\n if (isActive && bottomSheetContext) {\n const keyboardState = bottomSheetContext.animatedKeyboardState.get();\n const currentFocusedInput = findNodeHandle(\n TextInput.State.currentlyFocusedInput() as TextInput | null,\n );\n const shouldRemoveCurrentTarget = keyboardState.target === e.nativeEvent.target;\n const shouldIgnoreBlurEvent =\n currentFocusedInput &&\n bottomSheetContext.textInputNodesRef.current.has(currentFocusedInput);\n\n if (shouldRemoveCurrentTarget && !shouldIgnoreBlurEvent) {\n bottomSheetContext.animatedKeyboardState.set((state: Record) => ({\n ...state,\n target: undefined,\n }));\n }\n }\n },\n [isActive, bottomSheetContext],\n );\n\n return { onFocus, onBlur };\n}\n", "type": "registry:hook", "target": "@components/pitsi-ui/native-ui/src/helpers/external/hooks/use-bottom-sheet-aware-handlers.ts" }, { "path": "registry/native-ui/src/helpers/external/hooks/use-is-on-surface.ts", "content": "import { useSurface } from \"../../../components/surface\";\n\nexport const useIsOnSurface = () => {\n const surfaceContext = useSurface();\n return !!(surfaceContext?.variant && surfaceContext.variant !== \"transparent\");\n};\n", "type": "registry:hook", "target": "@components/pitsi-ui/native-ui/src/helpers/external/hooks/use-is-on-surface.ts" }, { "path": "registry/native-ui/src/helpers/external/hooks/use-theme-color.ts", "content": "import { useCSSVariable } from \"uniwind\";\n\n/**\n * Unique brand symbol used to prevent accidental array destructuring of a\n * single theme color value returned from `useThemeColor`.\n */\ndeclare const _colorValueBrand: unique symbol;\n\n/**\n * A resolved theme color string.\n *\n * This type intentionally removes `[Symbol.iterator]` so that TypeScript\n * surfaces a `never`-typed element when the value is array-destructured,\n * making the misuse visible in the IDE immediately.\n *\n * @example\n * // ✅ Correct – single value\n * const color = useThemeColor('muted');\n *\n * @example\n * // ✅ Correct – multiple values\n * const [primary, bg] = useThemeColor(['accent', 'background']);\n *\n * @example\n * // ❌ Wrong – destructuring a single-color result yields `never`\n * const [color] = useThemeColor('muted');\n */\nexport type ThemeColorValue = string & {\n readonly [_colorValueBrand]: undefined;\n /** Removed to prevent accidental array destructuring. */\n readonly [Symbol.iterator]: never;\n};\n\n/**\n * Theme colors as const array for efficient mapping\n * Ordered to match the order in src/styles/theme.css\n */\nconst THEME_COLORS = [\n \"background\",\n \"foreground\",\n \"surface\",\n \"surface-foreground\",\n \"surface-hover\",\n \"overlay\",\n \"overlay-foreground\",\n \"overlay-backdrop\",\n \"muted\",\n \"accent\",\n \"accent-foreground\",\n \"segment\",\n \"segment-foreground\",\n \"border\",\n \"separator\",\n \"focus\",\n \"link\",\n \"default\",\n \"default-foreground\",\n \"success\",\n \"success-foreground\",\n \"warning\",\n \"warning-foreground\",\n \"danger\",\n \"danger-foreground\",\n \"field\",\n \"field-foreground\",\n \"field-placeholder\",\n \"field-border\",\n \"background-secondary\",\n \"background-tertiary\",\n \"background-inverse\",\n \"default-hover\",\n \"accent-hover\",\n \"success-hover\",\n \"warning-hover\",\n \"danger-hover\",\n \"field-hover\",\n \"field-focus\",\n \"field-border-hover\",\n \"field-border-focus\",\n \"accent-soft\",\n \"accent-soft-foreground\",\n \"accent-soft-hover\",\n \"danger-soft\",\n \"danger-soft-foreground\",\n \"danger-soft-hover\",\n \"warning-soft\",\n \"warning-soft-foreground\",\n \"warning-soft-hover\",\n \"success-soft\",\n \"success-soft-foreground\",\n \"success-soft-hover\",\n \"surface-secondary\",\n \"surface-tertiary\",\n \"on-surface\",\n \"on-surface-foreground\",\n \"on-surface-hover\",\n \"on-surface-focus\",\n \"on-surface-secondary\",\n \"on-surface-secondary-foreground\",\n \"on-surface-secondary-hover\",\n \"on-surface-secondary-focus\",\n \"on-surface-tertiary\",\n \"on-surface-tertiary-foreground\",\n \"on-surface-tertiary-hover\",\n \"on-surface-tertiary-focus\",\n \"separator-secondary\",\n \"separator-tertiary\",\n \"border-secondary\",\n \"border-tertiary\",\n] as const;\n\n/**\n * Theme colors type derived from THEME_COLORS array\n */\nexport type ThemeColor = (typeof THEME_COLORS)[number];\n\n/**\n * Helper type to create a tuple of strings with the same length as the input array\n */\ntype CreateStringTuple = TAcc[\"length\"] extends N\n ? TAcc\n : CreateStringTuple;\n\n/**\n * Hook to retrieve theme color values from CSS variables.\n * Supports both single color and multiple colors for efficient batch retrieval.\n *\n * @param themeColor - Single theme color name or array of theme color names\n * @returns `ThemeColorValue` for a single name, or a string tuple/array for multiple names.\n *\n * @example\n * // Single color – returns `ThemeColorValue` (not destructurable)\n * const primaryColor = useThemeColor('accent');\n *\n * @example\n * // Multiple colors – returns a typed string tuple (destructurable)\n * const [primaryColor, backgroundColor] = useThemeColor(['accent', 'background']);\n */\nexport function useThemeColor(themeColor: ThemeColor): ThemeColorValue;\nexport function useThemeColor(\n themeColor: T,\n): CreateStringTuple;\nexport function useThemeColor(themeColor: ThemeColor[]): string[];\nexport function useThemeColor(themeColor: ThemeColor | ThemeColor[]): ThemeColorValue | string[] {\n const isArray = Array.isArray(themeColor);\n const cssVariables = isArray\n ? themeColor.map((color) => `--color-${color}`)\n : [`--color-${themeColor}`];\n\n const resolvedColors = useCSSVariable(cssVariables);\n\n const processedColors: string[] = resolvedColors.map((color) => {\n if (typeof color === \"string\") {\n return color;\n }\n if (typeof color === \"number\") {\n return String(color);\n }\n return \"invalid\";\n });\n\n if (isArray) {\n return processedColors;\n }\n\n /** `cssVariables` always contains one entry when `isArray` is false, so index 0 is always defined. */\n return (processedColors[0] ?? \"invalid\") as ThemeColorValue;\n}\n", "type": "registry:hook", "target": "@components/pitsi-ui/native-ui/src/helpers/external/hooks/use-theme-color.ts" }, { "path": "registry/native-ui/src/helpers/external/utils/cn.ts", "content": "import { type CnOptions, cnMerge } from \"tailwind-variants\";\n\nexport function cn(...args: CnOptions) {\n return cnMerge(args)({\n twMerge: true,\n twMergeConfig: {\n classGroups: {\n opacity: [{ opacity: [\"disabled\"] }],\n },\n },\n });\n}\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/external/utils/cn.ts" }, { "path": "registry/native-ui/src/helpers/external/utils/color-kit/index.ts", "content": "/**\n * Color manipulation utilities adapted from reanimated-color-picker\n *\n * Original source: https://github.com/alabsi91/reanimated-color-picker\n * Author: @alabsi91\n * License: MIT\n *\n * This code has been adapted for use in PitsiUI Native with modifications\n * for TypeScript compatibility and integration with the theme system.\n */\n\nimport type {\n ColorFormats,\n ColorTypes,\n ConversionMethods,\n hslaT,\n hslT,\n hsvaT,\n hsvT,\n hwbaT,\n hwbT,\n rgbaT,\n rgbT,\n SupportedColorFormats,\n} from \"./types\";\n\n// If you find yourself wondering why all of this is within a single function,\n// the reason is that to execute each method on the UI thread, you must include the 'worklet' directive.\n// Functions marked with this directive are transformed by the Reanimated Babel plugin\n// into IIFE — IMMEDIATELY INVOKED FUNCTION EXPRESSION: `const fun = (function{})()`.\n// Due to the presence of numerous methods,\n// this transformation can lead to a slow initial execution.\n// To address this issue, I consolidated them into a single worklet function.\n\nexport const colorKitUI = () => {\n \"worklet\";\n\n const NAMED_COLORS = {\n aliceblue: \"#f0f8ff\",\n antiquewhite: \"#faebd7\",\n aqua: \"#00ffff\",\n aquamarine: \"#7fffd4\",\n azure: \"#f0ffff\",\n beige: \"#f5f5dc\",\n bisque: \"#ffe4c4\",\n black: \"#000000\",\n blanchedalmond: \"#ffebcd\",\n blue: \"#0000ff\",\n blueviolet: \"#8a2be2\",\n brown: \"#a52a2a\",\n burlywood: \"#deb887\",\n cadetblue: \"#5f9ea0\",\n chartreuse: \"#7fff00\",\n chocolate: \"#d2691e\",\n coral: \"#ff7f50\",\n cornflowerblue: \"#6495ed\",\n cornsilk: \"#fff8dc\",\n crimson: \"#dc143c\",\n cyan: \"#00ffff\",\n darkblue: \"#00008b\",\n darkcyan: \"#008b8b\",\n darkgoldenrod: \"#b8860b\",\n darkgray: \"#a9a9a9\",\n darkgreen: \"#006400\",\n darkgrey: \"#a9a9a9\",\n darkkhaki: \"#bdb76b\",\n darkmagenta: \"#8b008b\",\n darkolivegreen: \"#556b2f\",\n darkorange: \"#ff8c00\",\n darkorchid: \"#9932cc\",\n darkred: \"#8b0000\",\n darksalmon: \"#e9967a\",\n darkseagreen: \"#8fbc8f\",\n darkslateblue: \"#483d8b\",\n darkslategrey: \"#2f4f4f\",\n darkturquoise: \"#00ced1\",\n darkviolet: \"#9400d3\",\n deeppink: \"#ff1493\",\n deepskyblue: \"#00bfff\",\n dimgray: \"#696969\",\n dimgrey: \"#696969\",\n dodgerblue: \"#1e90ff\",\n firebrick: \"#b22222\",\n floralwhite: \"#fffaf0\",\n forestgreen: \"#228b22\",\n fuchsia: \"#ff00ff\",\n gainsboro: \"#dcdcdc\",\n ghostwhite: \"#f8f8ff\",\n gold: \"#ffd700\",\n goldenrod: \"#daa520\",\n gray: \"#808080\",\n green: \"#008000\",\n greenyellow: \"#adff2f\",\n grey: \"#808080\",\n honeydew: \"#f0fff0\",\n hotpink: \"#ff69b4\",\n indianred: \"#cd5c5c\",\n indigo: \"#4b0082\",\n ivory: \"#fffff0\",\n khaki: \"#f0e68c\",\n lavender: \"#e6e6fa\",\n lavenderblush: \"#fff0f5\",\n lawngreen: \"#7cfc00\",\n lemonchiffon: \"#fffacd\",\n lightblue: \"#add8e6\",\n lightcoral: \"#f08080\",\n lightcyan: \"#e0ffff\",\n lightgoldenrodyellow: \"#fafad2\",\n lightgray: \"#d3d3d3\",\n lightgreen: \"#90ee90\",\n lightgrey: \"#d3d3d3\",\n lightpink: \"#ffb6c1\",\n lightsalmon: \"#ffa07a\",\n lightseagreen: \"#20b2aa\",\n lightskyblue: \"#87cefa\",\n lightslategrey: \"#778899\",\n lightsteelblue: \"#b0c4de\",\n lightyellow: \"#ffffe0\",\n lime: \"#00ff00\",\n limegreen: \"#32cd32\",\n linen: \"#faf0e6\",\n magenta: \"#ff00ff\",\n maroon: \"#800000\",\n mediumaquamarine: \"#66cdaa\",\n mediumblue: \"#0000cd\",\n mediumorchid: \"#ba55d3\",\n mediumpurple: \"#9370db\",\n mediumseagreen: \"#3cb371\",\n mediumslateblue: \"#7b68ee\",\n mediumspringgreen: \"#00fa9a\",\n mediumturquoise: \"#48d1cc\",\n mediumvioletred: \"#c71585\",\n midnightblue: \"#191970\",\n mintcream: \"#f5fffa\",\n mistyrose: \"#ffe4e1\",\n moccasin: \"#ffe4b5\",\n navajowhite: \"#ffdead\",\n navy: \"#000080\",\n oldlace: \"#fdf5e6\",\n olive: \"#808000\",\n olivedrab: \"#6b8e23\",\n orange: \"#ffa500\",\n orangered: \"#ff4500\",\n orchid: \"#da70d6\",\n palegoldenrod: \"#eee8aa\",\n palegreen: \"#98fb98\",\n paleturquoise: \"#afeeee\",\n palevioletred: \"#db7093\",\n papayawhip: \"#ffefd5\",\n peachpuff: \"#ffdab9\",\n peru: \"#cd853f\",\n pink: \"#ffc0cb\",\n plum: \"#dda0dd\",\n powderblue: \"#b0e0e6\",\n purple: \"#800080\",\n rebeccapurple: \"#663399\",\n red: \"#ff0000\",\n rosybrown: \"#bc8f8f\",\n royalblue: \"#4169e1\",\n saddlebrown: \"#8b4513\",\n salmon: \"#fa8072\",\n sandybrown: \"#f4a460\",\n seagreen: \"#2e8b57\",\n seashell: \"#fff5ee\",\n sienna: \"#a0522d\",\n silver: \"#c0c0c0\",\n skyblue: \"#87ceeb\",\n slateblue: \"#6a5acd\",\n slategray: \"#708090\",\n snow: \"#fffafa\",\n springgreen: \"#00ff7f\",\n steelblue: \"#4682b4\",\n tan: \"#d2b48c\",\n teal: \"#008080\",\n thistle: \"#d8bfd8\",\n tomato: \"#ff6347\",\n turquoise: \"#40e0d0\",\n violet: \"#ee82ee\",\n wheat: \"#f5deb3\",\n white: \"#ffffff\",\n whitesmoke: \"#f5f5f5\",\n yellow: \"#ffff00\",\n yellowgreen: \"#9acd32\",\n };\n\n const COLORS_REGEX: Record = {\n // #rgb\n hex3: /^#([A-Fa-f0-9]{3})$/,\n // #rgba\n hex4: /^#([A-Fa-f0-9]{3}[A-Fa-f0-9]{1})$/,\n // #rrggbb\n hex6: /^#([A-Fa-f0-9]{6})$/,\n // #rrggbbaa\n hex8: /^#([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i,\n\n hsl: [\n // hsl(360deg, 100%, 100%) hsl(360, 100%, 100%) hsl(23.55, 12.22%, 34.56%)\n /^hsl\\s*\\(\\s*([\\d.]+)(?:deg)?\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%\\s*\\)$/i,\n // hsl(360deg 100% 100%) hsl(360 100% 100%) hsl(23.55 12.22% 34.56%)\n /^hsl\\s*\\(\\s*([\\d.]+)(?:deg)?\\s+([\\d.]+)%\\s+([\\d.]+)%\\s*\\)$/i,\n ],\n hsla: [\n // hsla(360deg, 100%, 100%, 1.0) hsla(360, 100%, 100%, 1.0) hsl(360deg, 100%, 100%, 1.0) hsl(360, 100%, 100%, 1.0)\n /^hsla?\\s*\\(\\s*([\\d.]+)(?:deg)?\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%\\s*,\\s*(\\d|\\d\\.\\d+)\\s*\\)$/i,\n // hsla(360deg 100% 100% / 1.0) hsla(360 100% 100% / 1.0) hsl(360deg 100% 100% / 1.0) hsl(360 100% 100% / 1.0)\n /^hsla?\\s*\\(\\s*([\\d.]+)(?:deg)?\\s+([\\d.]+)%\\s+([\\d.]+)%\\s*\\/\\s*(\\d|\\d\\.\\d+)\\s*\\)$/i,\n ],\n\n hsv: [\n // hsv(360deg, 000%, 000%) hsv(360, 100%, 100%)\n /^hsv\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%\\s*\\)$/i,\n // hsv(360deg 000% 000%) hsv(360 100% 100%)\n /^hsv\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s+([\\d.]+)%\\s+([\\d.]+)%\\s*\\)$/i,\n ],\n hsva: [\n // hsva(360deg, 100%, 100%, 1.0) hsva(360, 100%, 100%, 1.0) hsv(360deg, 100%, 100%, 1.0) hsv(360, 100%, 100%, 1.0)\n /^hsva?\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%\\s*,\\s*(\\d|\\d\\.\\d+)\\s*\\)$/i,\n // hsva(360deg 100% 100% / 1.0) hsva(360 100% 100% / 1.0) hsv(360deg 100% 100% / 1.0) hsv(360 100% 100% / 1.0)\n /^hsva?\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s+([\\d.]+)%\\s+([\\d.]+)%\\s*\\/\\s*(\\d|\\d\\.\\d+)\\s*\\)$/i,\n ],\n\n hwb: [\n // hwb(360deg, 100%, 100%) hwb(360, 100%, 100%)\n /^hwb\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%\\s*\\)$/i,\n // hwb(360deg 100% 100%) hwb(360 100% 100%)\n /^hwb\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s+([\\d.]+)%\\s+([\\d.]+)%\\s*\\)$/i,\n ],\n hwba: [\n // hwba(360deg, 100%, 100%, 1.0) hwba(360, 100%, 100%, 1.0) hwb(360deg, 100%, 100%, 1.0) hwb(360, 100%, 100%, 1.0)\n /^hwba?\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s*,\\s*([\\d.]+)%\\s*,\\s*([\\d.]+)%\\s*,\\s*(\\d|\\d\\.\\d+)\\s*\\)$/i,\n // hwb(360deg 100% 100% 1.0) hwb(360 100% 100% / 1.0) hwba(360deg 100% 100% 1.0) hwba(360 100% 100% / 1.0)\n /^hwba?\\s*\\(\\s*(\\d{1,3})(?:deg)?\\s+([\\d.]+)%\\s+([\\d.]+)%\\s*\\/\\s*(\\d|\\d\\.\\d+)\\s*\\)$/i,\n ],\n\n rgb: [\n // rgb(255, 255, 255)\n /^rgb\\s*\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*\\)$/i,\n // rgb(255 255 255)\n /^rgb\\s*\\(\\s*(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s*\\)$/i,\n ],\n rgba: [\n // rgba(255, 255, 255, 1.0) rgb(255, 255, 255, 1.0)\n /^rgba?\\s*\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*([\\d.]+)\\s*\\)$/i,\n // rgba(255 255 255 / 1.0) rgb(255 255 255 / 1.0)\n /^rgba?\\s*\\(\\s*(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s*\\/\\s*([\\d.]+)\\s*\\)$/i,\n ],\n };\n\n // * MARK: General utilities\n\n const clamp = (value: number, min: number, max: number) => {\n return Math.max(min, Math.min(value, max));\n };\n\n const clampRGB = (value: number) => {\n return clamp(value, 0, 255);\n };\n\n const clampHue = (value: number) => {\n return clamp(value, 0, 360);\n };\n\n const clamp100 = (value: number) => {\n return clamp(value, 0, 100);\n };\n\n const clampAlpha = (value: number) => {\n return clamp(+value.toFixed(2), 0, 1);\n };\n\n const randomNumber = (min: number, max: number) => {\n return Math.random() * (max - min) + min;\n };\n\n const numberToHexString = (c: number): string => {\n c = clampRGB(Math.round(c));\n const hex = c.toString(16).padStart(2, \"0\");\n return hex;\n };\n\n const calculateHueValue = (p: number, q: number, t: number): number => {\n if (t < 0) t += 1;\n if (t > 1) t -= 1;\n if (t < 1 / 6) return p + (q - p) * 6 * t;\n if (t < 1 / 2) return q;\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;\n return p;\n };\n\n /** - Identify the color format of a given `string` or `object` */\n const detectColorFormat = (color: SupportedColorFormats): ColorFormats | null => {\n // color int\n if (typeof color === \"number\") {\n // eslint-disable-next-line no-bitwise\n if (color >>> 0 === color && color >= 0 && color <= 0xffffffff) return \"hex8\";\n return null;\n }\n\n // color string\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n for (const key in COLORS_REGEX) {\n const format = key as ColorFormats;\n const entry = COLORS_REGEX[format];\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(color)) return format;\n }\n continue;\n }\n if (entry.test(color)) return format;\n }\n }\n\n // color object\n if (typeof color === \"object\") {\n const rgbaKeys = [\"r\", \"g\", \"b\", \"a\"] as (keyof rgbaT)[];\n const isRgbaOb = rgbaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as rgbaT)[k] === \"number\",\n );\n if (isRgbaOb) return \"rgba\";\n\n const rgbKeys = [\"r\", \"g\", \"b\"] as (keyof rgbT)[];\n const isRgbOb = rgbKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as rgbT)[k] === \"number\",\n );\n if (isRgbOb) return \"rgb\";\n\n const hslaKeys = [\"h\", \"s\", \"l\", \"a\"] as (keyof hslaT)[];\n const isHslaOb = hslaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hslaT)[k] === \"number\",\n );\n if (isHslaOb) return \"hsla\";\n\n const hslKeys = [\"h\", \"s\", \"l\"] as (keyof hslT)[];\n const isHslOb = hslKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hslT)[k] === \"number\",\n );\n if (isHslOb) return \"hsl\";\n\n const hsvaKeys = [\"h\", \"s\", \"v\", \"a\"] as (keyof hsvaT)[];\n const isHsvaOb = hsvaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hsvaT)[k] === \"number\",\n );\n if (isHsvaOb) return \"hsva\";\n\n const hsvKeys = [\"h\", \"s\", \"v\"] as (keyof hsvT)[];\n const isHsvOb = hsvKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hsvT)[k] === \"number\",\n );\n if (isHsvOb) return \"hsv\";\n\n const hwbaKeys = [\"h\", \"w\", \"b\", \"a\"] as (keyof hwbaT)[];\n const isHwbaOb = hwbaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hwbaT)[k] === \"number\",\n );\n if (isHwbaOb) return \"hwba\";\n\n const hwbKeys = [\"h\", \"w\", \"b\"] as (keyof hwbT)[];\n const isHwbOb = hwbKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hwbT)[k] === \"number\",\n );\n if (isHwbOb) return \"hwb\";\n }\n\n return null;\n };\n\n // * MARK: RGB\n\n /** - Parse `RGB` or `RGBA` color string to an `object` */\n const RGB_string_to_object = (color: string): rgbaT => {\n color = color.trim().toLowerCase();\n const colorType = detectColorFormat(color);\n\n if (!colorType?.includes(\"rgb\")) {\n console.error(\n '[colorKit.getRgbObject] is unable to parse the string into an `RGB` object. As a result, the color \"black\" will be returned instead.',\n );\n return { r: 0, g: 0, b: 0, a: 1 };\n }\n\n let matches: RegExpMatchArray | null = null;\n const entry = COLORS_REGEX[colorType];\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(color)) {\n matches = color.match(regex);\n }\n }\n } else {\n matches = color.match(entry);\n }\n\n if (!matches || matches.length < 4) {\n console.error(\n '[colorKit.getRgbObject] An error occurred while attempting to destructuring `RGB` values from the given string. As a result, the color \"black\" will be returned instead.',\n );\n return { r: 0, g: 0, b: 0, a: 1 };\n }\n\n const r = parseInt(matches[1] || \"0\", 10),\n g = parseInt(matches[2] || \"0\", 10),\n b = parseInt(matches[3] || \"0\", 10),\n a = parseFloat(matches[4] ?? \"1\");\n\n return {\n r: clampRGB(r),\n g: clampRGB(g),\n b: clampRGB(b),\n a: clampAlpha(a),\n };\n };\n\n /** - Ensure that the `RGB` object values are within the correct range and that it has the alpha channel */\n const normalize_RGB_object = (color: rgbaT | rgbT): rgbaT => {\n return {\n r: clampRGB(color.r),\n g: clampRGB(color.g),\n b: clampRGB(color.b),\n a: clampAlpha((color as rgbaT).a ?? 1),\n };\n };\n\n /** - Convert an `RGB` or `RGBA` color to its corresponding `Hex` color */\n const RGB_to_HEX = (color: string | rgbaT | rgbT): string => {\n const { r, g, b, a } =\n typeof color === \"string\" ? RGB_string_to_object(color) : normalize_RGB_object(color);\n\n const red = numberToHexString(r),\n green = numberToHexString(g),\n blue = numberToHexString(b),\n alpha = a === 1 ? \"\" : numberToHexString(a * 255);\n\n return `#${red + green + blue + alpha}`;\n };\n\n /** - Convert `RGB` or `RGBA` color to an `RGBA` object representation */\n const RGB_to_RGB = (color: string | rgbaT | rgbT): rgbaT => {\n return typeof color === \"string\" ? RGB_string_to_object(color) : normalize_RGB_object(color);\n };\n\n /** - Convert an `RGB` or `RGBA` color to an `HSLA` object representation */\n const RGB_to_HSLA = (color: string | rgbaT | rgbT): hslaT => {\n const rgb =\n typeof color === \"string\" ? RGB_string_to_object(color) : normalize_RGB_object(color),\n r = rgb.r / 255,\n g = rgb.g / 255,\n b = rgb.b / 255,\n a = rgb.a;\n\n const max = Math.max(r, g, b),\n min = Math.min(r, g, b);\n\n let h = 0;\n let s = 0;\n let l = (max + min) / 2;\n\n if (max === min) {\n h = s = 0;\n } else {\n const d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n\n if (max === r) {\n h = (g - b) / d + (g < b ? 6 : 0);\n } else if (max === g) {\n h = (b - r) / d + 2;\n } else if (max === b) {\n h = (r - g) / d + 4;\n }\n\n h /= 6;\n }\n\n h = clampHue(h * 360);\n s = clamp100(s * 100);\n l = clamp100(l * 100);\n\n return { h, s, l, a: clampAlpha(a) };\n };\n\n /** - Convert `RGB` or `RGBA` color to an `HSVA` object representation */\n const RGB_to_HSVA = (color: string | rgbaT | rgbT): hsvaT => {\n const rgb =\n typeof color === \"string\" ? RGB_string_to_object(color) : normalize_RGB_object(color),\n r = rgb.r / 255,\n g = rgb.g / 255,\n b = rgb.b / 255,\n a = rgb.a;\n\n const max = Math.max(r, g, b),\n min = Math.min(r, g, b),\n d = max - min,\n v = max,\n s = max === 0 ? 0 : d / max;\n\n let h = 0;\n\n if (max === min) {\n h = 0;\n } else {\n if (max === r) {\n h = (g - b) / d + (g < b ? 6 : 0);\n } else if (max === g) {\n h = (b - r) / d + 2;\n } else if (max === b) {\n h = (r - g) / d + 4;\n }\n\n h = h / 6;\n }\n\n return {\n h: clampHue(h * 360),\n s: clamp100(s * 100),\n v: clamp100(v * 100),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `RGB` or `RGBA` color to an `HWBA` object representation */\n const RGB_to_HWBA = (color: string | rgbaT | rgbT): hwbaT => {\n const rgb =\n typeof color === \"string\" ? RGB_string_to_object(color) : normalize_RGB_object(color),\n red = rgb.r / 255,\n green = rgb.g / 255,\n blue = rgb.b / 255,\n a = rgb.a;\n\n const { h } = RGB_to_HSLA(color);\n\n const white = Math.min(red, green, blue) * 100;\n const black = (1 - Math.max(red, green, blue)) * 100;\n\n return {\n h: clampHue(h),\n w: clamp100(white),\n b: clamp100(black),\n a: clampAlpha(a),\n };\n };\n\n /** - Return the `RGB` color as a string, an array, or an object */\n const RGB_types = ({ r, g, b, a }: rgbaT): ColorTypes => {\n return {\n string: (forceAlpha?: boolean) => {\n r = Math.round(r);\n g = Math.round(g);\n b = Math.round(b);\n\n // auto\n if (typeof forceAlpha === \"undefined\") {\n if (typeof a === \"number\" && a !== 1) return `rgba(${r}, ${g}, ${b}, ${a})`;\n return `rgb(${r}, ${g}, ${b})`;\n }\n\n if (forceAlpha) return `rgba(${r}, ${g}, ${b}, ${a ?? 1})`;\n\n return `rgb(${r}, ${g}, ${b})`;\n },\n array: (roundValues = true) => {\n if (roundValues) {\n r = Math.round(r);\n g = Math.round(g);\n b = Math.round(b);\n }\n return [r, g, b, a];\n },\n object: (roundValues = true) => {\n if (roundValues) {\n r = Math.round(r);\n g = Math.round(g);\n b = Math.round(b);\n }\n return { r, g, b, a };\n },\n };\n };\n\n // * MARK: HSL\n\n /** - Parse `HSL` or `HSLA` color string to an `object` */\n const HSL_string_to_object = (color: string): hslaT => {\n color = color.trim().toLowerCase();\n const colorType = detectColorFormat(color);\n\n if (!colorType?.includes(\"hsl\")) {\n console.error(\n '[colorKit.getHslObject] is unable to parse the string into an `HSL` object. As a result, the color \"black\" will be returned instead.',\n );\n return { h: 0, s: 0, l: 0, a: 1 };\n }\n\n let matches: RegExpMatchArray | null = null;\n const entry = COLORS_REGEX[colorType as \"hsl\" | \"hsla\"];\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(color)) {\n matches = color.match(regex);\n }\n }\n } else {\n matches = color.match(entry);\n }\n\n if (!matches || matches.length < 3) {\n console.error(\n '[colorKit.getHslObject] An error occurred while attempting to destructuring `HSL` values from the given string. As a result, the color \"black\" will be returned instead.',\n );\n return { h: 0, s: 0, l: 0, a: 1 };\n }\n\n const h = parseInt(matches[1] || \"0\", 10),\n s = parseInt(matches[2] || \"0\", 10),\n l = parseInt(matches[3] || \"0\", 10),\n a = parseFloat(matches[4] ?? \"1\");\n\n return {\n h: clampHue(h),\n s: clamp100(s),\n l: clamp100(l),\n a: clampAlpha(a),\n };\n };\n\n /** - Ensure that the `HSL` object values are within the correct range and that it has the alpha channel */\n const normalize_HSL_object = (color: hslaT | hslT): hslaT => {\n return {\n h: clampHue(color.h),\n s: clamp100(color.s),\n l: clamp100(color.l),\n a: clampAlpha((color as hslaT).a ?? 1),\n };\n };\n\n /** - Convert `HSL` or `HSLA` color to an `RGBA` object representation */\n const HSL_to_RGBA = (color: string | hslaT | hslT): rgbaT => {\n const hsla =\n typeof color === \"string\" ? HSL_string_to_object(color) : normalize_HSL_object(color);\n\n const h = hsla.h / 360,\n s = hsla.s / 100,\n l = hsla.l / 100,\n a = hsla.a;\n\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s,\n p = 2 * l - q;\n\n const r = calculateHueValue(p, q, h + 1 / 3),\n g = calculateHueValue(p, q, h),\n b = calculateHueValue(p, q, h - 1 / 3);\n\n return {\n r: clampRGB(r * 255),\n g: clampRGB(g * 255),\n b: clampRGB(b * 255),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `HSL` or `HSLA` color to `HEX` color */\n const HSL_to_HEX = (color: string | hslaT | hslT): string => {\n const hsla =\n typeof color === \"string\" ? HSL_string_to_object(color) : normalize_HSL_object(color);\n const rgb = HSL_to_RGBA(hsla);\n\n const r = numberToHexString(rgb.r),\n g = numberToHexString(rgb.g),\n b = numberToHexString(rgb.b),\n a = rgb.a === 1 ? \"\" : numberToHexString(rgb.a * 255);\n\n return `#${r + g + b + a}`;\n };\n\n /** - Convert `HSL` or `HSLA` color to an `HSVA` object representation */\n const HSL_to_HSVA = (color: string | hslaT | hslT): hsvaT => {\n const hsla =\n typeof color === \"string\" ? HSL_string_to_object(color) : normalize_HSL_object(color);\n const h = hsla.h;\n\n const s = hsla.s / 100,\n l = hsla.l / 100,\n a = (hsla as hslaT).a ?? 1,\n v = l + s * Math.min(l, 1 - l),\n sNew = v === 0 ? 0 : 2 - (2 * l) / v;\n\n return {\n h: clampHue(h),\n s: clamp100(sNew * 100),\n v: clamp100(v * 100),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `HSL` or `HSLA` color to an `HWBA` object representation */\n const HSL_to_HWBA = (color: string | hslaT | hslT): hwbaT => {\n const hsva = HSL_to_HSVA(color);\n return HSV_to_HWBA(hsva);\n };\n\n /** - Convert `HSL` or `HSLA` color to an `HSLA` object representation */\n const HSL_to_HSL = (color: string | hslaT | hslT): hslaT => {\n return typeof color === \"string\" ? HSL_string_to_object(color) : normalize_HSL_object(color);\n };\n\n /** - Return the `HSL` color as a string, an array, or an object */\n const HSL_types = ({ h, s, l, a }: hslaT): ColorTypes => {\n return {\n string: (forceAlpha?: boolean) => {\n h = Math.round(h);\n s = Math.round(s);\n l = Math.round(l);\n\n // auto\n if (typeof forceAlpha === \"undefined\") {\n if (typeof a === \"number\" && a !== 1) return `hsla(${h}, ${s}%, ${l}%, ${a})`;\n return `hsl(${h}, ${s}%, ${l}%)`;\n }\n\n if (forceAlpha) return `hsla(${h}, ${s}%, ${l}%, ${a ?? 1})`;\n\n return `hsl(${h}, ${s}%, ${l}%)`;\n },\n array: (roundValues = true) => {\n if (roundValues) {\n h = Math.round(h);\n s = Math.round(s);\n l = Math.round(l);\n }\n return [h, s, l, a];\n },\n object: (roundValues = true) => {\n if (roundValues) {\n h = Math.round(h);\n s = Math.round(s);\n l = Math.round(l);\n }\n return { h, s, l, a };\n },\n };\n };\n\n // * MARK: HWB\n\n /** - Parse `HWB` or `HWBA` color strong to an `object` */\n const HWB_string_to_object = (color: string): hwbaT => {\n color = color.trim().toLowerCase();\n const colorType = detectColorFormat(color);\n\n if (!colorType?.includes(\"hwb\")) {\n console.error(\n '[colorKit.getHwbObject] is unable to parse the string into an `HWB` object. As a result, the color \"black\" will be returned instead.',\n );\n return { h: 0, w: 0, b: 0, a: 1 };\n }\n\n let matches: RegExpMatchArray | null = null;\n const entry = COLORS_REGEX[colorType as \"hwb\" | \"hwba\"];\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(color)) {\n matches = color.match(regex);\n }\n }\n } else {\n matches = color.match(entry);\n }\n\n if (!matches || matches.length < 4) {\n console.error(\n '[colorKit.getHwbObject] An error occurred while attempting to destructuring `HWB` values from the given string. As a result, the color \"black\" will be returned instead.',\n );\n return { h: 0, w: 0, b: 0, a: 1 };\n }\n\n const h = parseInt(matches[1] || \"0\", 10),\n w = parseInt(matches[2] || \"0\", 10),\n b = parseInt(matches[3] || \"0\", 10),\n a = parseFloat(matches[4] ?? \"1\");\n\n return {\n h: clampHue(h),\n w: clamp100(w),\n b: clamp100(b),\n a: clampAlpha(a),\n };\n };\n\n /** - Ensure that the `HWB` object values are within the correct range and that it has the alpha channel */\n const normalize_HWB_object = (color: hwbaT | hwbT): hwbaT => {\n return {\n h: clampHue(color.h),\n w: clamp100(color.w),\n b: clamp100(color.b),\n a: clampAlpha((color as hwbaT).a ?? 1),\n };\n };\n\n /** - Convert `HWB` or `HWBA` color to an `RGBA` object representation */\n const HWB_to_RGBA = (color: hwbaT | hwbT | string): rgbaT => {\n const hwba =\n typeof color === \"string\" ? HWB_string_to_object(color) : normalize_HWB_object(color);\n\n const h = hwba.h / 360,\n w = hwba.w / 100,\n b = hwba.b / 100,\n a = hwba.a;\n\n if (w + b >= 1) {\n const gray = clampRGB((w * 255) / (w + b));\n return {\n r: gray,\n g: gray,\n b: gray,\n a,\n };\n }\n\n const red = calculateHueValue(0, 1, h + 1 / 3) * (1 - w - b) + w,\n green = calculateHueValue(0, 1, h) * (1 - w - b) + w,\n blue = calculateHueValue(0, 1, h - 1 / 3) * (1 - w - b) + w;\n\n return {\n r: clampRGB(red * 255),\n g: clampRGB(green * 255),\n b: clampRGB(blue * 255),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `HWB` or `HWBA` color to an `Hex` color */\n const HWB_to_HEX = (color: hwbaT | hwbT | string): string => {\n const rgba = HWB_to_RGBA(color);\n return RGB_to_HEX(rgba);\n };\n\n /** - Convert `HWB` or `HWBA` color to an `HSVA` object representation */\n function HWB_to_HSVA(color: hwbaT | hwbT | string): hsvaT {\n const hwba =\n typeof color === \"string\" ? HWB_string_to_object(color) : normalize_HWB_object(color);\n\n const h = hwba.h % 360,\n w = hwba.w / 100,\n b = hwba.b / 100,\n a = hwba.a;\n\n const v = (1 - b) * 100;\n let s = (1 - w / (v / 100)) * 100;\n s = Number.isNaN(s) ? 0 : s;\n\n return {\n h: clampHue(h),\n s: clamp100(s),\n v: clamp100(v),\n a: clampAlpha(a),\n };\n }\n\n /** - Convert `HWB` or `HWBA` color to an `HSLA` object representation */\n const HWB_to_HSLA = (color: hwbaT | hwbT | string): hslaT => {\n const hsva = HWB_to_HSVA(color);\n return HSV_to_HSLA(hsva);\n };\n\n /** - Convert `HWB` or `HWBA` color to an `HWBA` object representation */\n const HWB_to_HWB = (color: hwbaT | hwbT | string): hwbaT => {\n return typeof color === \"string\" ? HWB_string_to_object(color) : normalize_HWB_object(color);\n };\n\n /** - Return the `HWB` color as a string, an array, or an object */\n const HWB_types = ({ h, w, b, a }: hwbaT): ColorTypes => {\n return {\n string: (forceAlpha?: boolean) => {\n h = Math.round(h);\n w = Math.round(w);\n b = Math.round(b);\n\n // auto\n if (typeof forceAlpha === \"undefined\") {\n if (typeof a === \"number\" && a !== 1) return `hwb(${h} ${w}% ${b}% / ${a})`;\n return `hwb(${h}, ${w}%, ${b}%)`;\n }\n\n if (forceAlpha) return `hwb(${h} ${w}% ${b}% / ${a ?? 1})`;\n\n return `hwb(${h} ${w}% ${b}%)`;\n },\n array: (roundValues = true) => {\n if (roundValues) {\n h = Math.round(h);\n w = Math.round(w);\n b = Math.round(b);\n }\n return [h, w, b, a];\n },\n object: (roundValues = true) => {\n if (roundValues) {\n h = Math.round(h);\n w = Math.round(w);\n b = Math.round(b);\n }\n return { h, w, b, a };\n },\n };\n };\n\n // * MARK: HSV\n\n /** - Parse `HSV` or `HSVA` color string to an `object` */\n const HSV_string_to_object = (color: string): hsvaT => {\n color = color.trim().toLowerCase();\n const colorType = detectColorFormat(color);\n\n if (!colorType?.includes(\"hsv\")) {\n console.error(\n '[colorKit.getHsvObject] is unable to parse the string into an `HSV` object. As a result, the color \"black\" will be returned instead.',\n );\n return { h: 0, s: 0, v: 0, a: 1 };\n }\n\n let matches: RegExpMatchArray | null = null;\n const entry = COLORS_REGEX[colorType as \"hsv\" | \"hsva\"];\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(color)) {\n matches = color.match(regex);\n }\n }\n } else {\n matches = color.match(entry);\n }\n\n if (!matches || matches.length < 4) {\n console.error(\n '[colorKit.getHsvObject] An error occurred while attempting to destructuring `HSV` values from the given string. As a result, the color \"black\" will be returned instead.',\n );\n return { h: 0, s: 0, v: 0, a: 1 };\n }\n\n const h = parseInt(matches[1] || \"0\", 10),\n s = parseInt(matches[2] || \"0\", 10),\n v = parseInt(matches[3] || \"0\", 10),\n a = parseFloat(matches[4] ?? \"1\");\n\n return {\n h: clampHue(h),\n s: clamp100(s),\n v: clamp100(v),\n a: clampAlpha(a),\n };\n };\n\n /** - Ensure that the `HSV` object values are within the correct range and that it has the alpha channel */\n const normalize_HSV_object = (color: hsvaT | hsvT): hsvaT => {\n return {\n h: clampHue(color.h),\n s: clamp100(color.s),\n v: clamp100(color.v),\n a: clampAlpha((color as hsvaT).a ?? 1),\n };\n };\n\n /** - Convert `HSV` color to an `RGBA` object representation */\n const HSV_to_RGBA = (color: hsvaT | hsvT | string): rgbaT => {\n const hsva =\n typeof color === \"string\" ? HSV_string_to_object(color) : normalize_HSV_object(color);\n\n const h = hsva.h / 360,\n s = hsva.s / 100,\n v = hsva.v / 100,\n a = hsva.a;\n\n const i = Math.floor(h * 6),\n f = h * 6 - i,\n p = v * (1 - s),\n q = v * (1 - f * s),\n t = v * (1 - (1 - f) * s);\n\n let r = 0,\n g = 0,\n b = 0;\n\n if (i % 6 === 0) {\n r = v;\n g = t;\n b = p;\n } else if (i % 6 === 1) {\n r = q;\n g = v;\n b = p;\n } else if (i % 6 === 2) {\n r = p;\n g = v;\n b = t;\n } else if (i % 6 === 3) {\n r = p;\n g = q;\n b = v;\n } else if (i % 6 === 4) {\n r = t;\n g = p;\n b = v;\n } else if (i % 6 === 5) {\n r = v;\n g = p;\n b = q;\n }\n\n return {\n r: clampRGB(r * 255),\n g: clampRGB(g * 255),\n b: clampRGB(b * 255),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `HSV` color to an `HSLA` object representation */\n const HSV_to_HSLA = (color: hsvaT | hsvT | string): hslaT => {\n const hsva =\n typeof color === \"string\" ? HSV_string_to_object(color) : normalize_HSV_object(color);\n\n const h = hsva.h,\n s = hsva.s / 100,\n v = hsva.v / 100,\n a = hsva.a;\n\n const l = ((2 - s) * v) / 2,\n sl = s * v,\n sln = l !== 0 && l !== 1 ? sl / (l < 0.5 ? l * 2 : 2 - l * 2) : sl;\n\n return {\n h: clampHue(h),\n s: clamp100(sln * 100),\n l: clamp100(l * 100),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `HSV` color to an `Hex` color */\n const HSV_to_HEX = (color: hsvaT | hsvT | string): string => {\n const rgba = HSV_to_RGBA(color);\n const hex = RGB_to_HEX(rgba);\n return hex;\n };\n\n /** - Convert `HSV` color to an `HWBA` object representation */\n const HSV_to_HWBA = (color: hsvaT | hsvT | string): hwbaT => {\n const { h, s, v, a } =\n typeof color === \"string\" ? HSV_string_to_object(color) : normalize_HSV_object(color);\n\n const w = (1 - s / 100) * v,\n b = (1 - v / 100) * 100;\n\n return {\n h: clampHue(h),\n w: clamp100(w),\n b: clamp100(b),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert `HSV` color to an `HSVA` object representation */\n const HSV_to_HSV = (color: hsvaT | hsvT | string): hsvaT => {\n return typeof color === \"string\" ? HSV_string_to_object(color) : normalize_HSV_object(color);\n };\n\n /** - Return the `HSV` color as a string, an array, or an object */\n const HSV_types = ({ h, s, v, a }: hsvaT): ColorTypes => {\n return {\n string: (forceAlpha?: boolean) => {\n h = Math.round(h);\n s = Math.round(s);\n v = Math.round(v);\n\n // auto\n if (typeof forceAlpha === \"undefined\") {\n if (typeof a === \"number\" && a !== 1) return `hsva(${h}, ${s}%, ${v}%, ${a})`;\n return `hsv(${h}, ${s}%, ${v}%)`;\n }\n\n if (forceAlpha) return `hsva(${h}, ${s}%, ${v}%, ${a ?? 1})`;\n\n return `hsv(${h}, ${s}%, ${v}%)`;\n },\n array: (roundValues = true) => {\n if (roundValues) {\n h = Math.round(h);\n s = Math.round(s);\n v = Math.round(v);\n }\n return [h, s, v, a];\n },\n object: (roundValues = true) => {\n if (roundValues) {\n h = Math.round(h);\n s = Math.round(s);\n v = Math.round(v);\n }\n return { h, s, v, a };\n },\n };\n };\n\n // * MARK: HEX\n\n /** - Convert any `HEX` color to 8-digit `HEX` color (#rrggbbaa) */\n const normalize_HEX = (color: string | number): string => {\n if (typeof color === \"number\") {\n return `#${color.toString(16).padStart(8, \"0\")}`;\n }\n\n color = color.trim().toLowerCase();\n const colorType = detectColorFormat(color);\n\n if (!colorType?.includes(\"hex\")) {\n console.error(\n '[colorKit.normalizeHexColor] is unable to normalize the `HEX` string provided. As a result, the color \"black\" will be returned instead.',\n );\n return \"#000000ff\";\n }\n\n const hex = color.replace(/^#/, \"\").split(\"\");\n\n if (hex.length === 3) return `#${hex.map((x) => x + x).join(\"\")}ff`;\n if (hex.length === 4) return `#${hex.map((x) => x + x).join(\"\")}`;\n if (hex.length === 6) return `#${hex.join(\"\")}ff`;\n\n return color;\n };\n\n /** - Convert any `HEX` color to an `RGBA` object representation */\n const HEX_to_RGBA = (color: string | number): rgbaT => {\n const hex = normalize_HEX(color);\n\n let matches: RegExpMatchArray | null = null;\n const entry = COLORS_REGEX.hex8;\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(hex)) matches = hex.match(regex);\n }\n } else {\n matches = hex.match(entry);\n }\n\n if (!matches || matches.length < 4) {\n console.error(\n '[colorKit.HEX_RGBA] An error occurred while attempting to destructuring `HEX` values from the given string. As a result, the color \"black\" will be returned instead.',\n );\n return { r: 0, g: 0, b: 0, a: 1 };\n }\n\n const r = parseInt(matches[1] || \"0\", 16),\n g = parseInt(matches[2] || \"0\", 16),\n b = parseInt(matches[3] || \"0\", 16),\n a = parseInt(matches[4] || \"ff\", 16) / 255;\n\n return {\n r: clampRGB(r),\n g: clampRGB(g),\n b: clampRGB(b),\n a: clampAlpha(a),\n };\n };\n\n /** - Convert any `HEX` color to an `HSVA` object representation */\n const HEX_to_HSVA = (color: string | number): hsvaT => {\n const rgb = HEX_to_RGBA(color);\n const hsva = RGB_to_HSVA(rgb);\n return hsva;\n };\n\n /** - Convert any `HEX` color to an `HSLA` object representation */\n const HEX_to_HSLA = (color: string): hslaT => {\n const rgb = HEX_to_RGBA(color);\n return RGB_to_HSLA(rgb);\n };\n\n /** - Convert any `HEX` color to an `HWBA` object representation */\n const HEX_to_HWBA = (color: string): hwbaT => {\n const rgba = HEX_to_RGBA(color);\n return RGB_to_HWBA(rgba);\n };\n\n // * MARK: Color conversions\n\n /** - Convert `HSL`, `HSV`, `HWB`, or `RGB` color to the `HEX` color format. */\n const HEX = (color: SupportedColorFormats): string => {\n // named color\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n\n if (Object.hasOwn(NAMED_COLORS, color)) {\n color = NAMED_COLORS[color as keyof typeof NAMED_COLORS] as string;\n }\n }\n\n const colorType = detectColorFormat(color);\n\n // RGB to HEX\n if (colorType === \"rgb\" || colorType === \"rgba\") {\n return RGB_to_HEX(color as string | rgbT | rgbaT);\n }\n\n // HSL to HEX\n if (colorType === \"hsl\" || colorType === \"hsla\") {\n return HSL_to_HEX(color as string | hslaT | hslT);\n }\n\n // HSV to HEX\n if (colorType === \"hsv\" || colorType === \"hsva\") {\n return HSV_to_HEX(color as string | hsvaT | hsvT);\n }\n\n // HWB to HEX\n if (colorType === \"hwb\" || colorType === \"hwba\") {\n return HWB_to_HEX(color as string | hwbaT | hwbT);\n }\n\n // HEX\n if (colorType?.includes(\"hex\")) {\n return normalize_HEX(color as string | number);\n }\n\n // ! error\n console.error(\n '[colorKit.HEX] An error occurred while attempting to convert the provided parameter into an `HEX` color. As a result, the default color \"black\" will be used instead.',\n );\n\n return \"#000000\";\n };\n\n /** - Convert `HSL`, `HSV`, `HWB`, or `HEX` color to the `RGB` color format. */\n const RGB = (color: SupportedColorFormats): ColorTypes => {\n // named color\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n\n if (Object.hasOwn(NAMED_COLORS, color)) {\n color = NAMED_COLORS[color as keyof typeof NAMED_COLORS] as string;\n }\n }\n\n const colorType = detectColorFormat(color);\n\n // HEX to RGB\n if (colorType?.includes(\"hex\")) {\n const rgb = HEX_to_RGBA(color as string | number);\n return RGB_types(rgb);\n }\n\n // HSL to RGB\n if (colorType === \"hsl\" || colorType === \"hsla\") {\n const rgb = HSL_to_RGBA(color as string | hslaT | hslT);\n return RGB_types(rgb);\n }\n\n // HSV to RGB\n if (colorType === \"hsv\" || colorType === \"hsva\") {\n const rgb = HSV_to_RGBA(color as string | hsvaT | hsvT);\n return RGB_types(rgb);\n }\n\n // HWB to RGB\n if (colorType === \"hwb\" || colorType === \"hwba\") {\n const rgb = HWB_to_RGBA(color as string | hwbaT | hwbT);\n return RGB_types(rgb);\n }\n\n // RGB to normalized RGB\n if (colorType === \"rgb\" || colorType === \"rgba\") {\n const rgba = RGB_to_RGB(color as string | rgbaT | rgbT);\n return RGB_types(rgba);\n }\n\n // ! error\n console.error(\n '[colorKit.RGB] An error occurred while attempting to convert the provided parameter into an `RGB` color. As a result, the default color \"black\" will be used instead.',\n );\n\n return RGB_types({ r: 0, g: 0, b: 0, a: 1 });\n };\n\n /** - Convert `HEX`, `HSV`, `HWB`, or `RGB` color to the `HSL` color format. */\n const HSL = (color: SupportedColorFormats): ColorTypes => {\n // named color\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n\n if (Object.hasOwn(NAMED_COLORS, color)) {\n color = NAMED_COLORS[color as keyof typeof NAMED_COLORS] as string;\n }\n }\n\n const colorType = detectColorFormat(color);\n\n // HEX to HSL\n if (colorType?.includes(\"hex\")) {\n const hsla = HEX_to_HSLA(color as string);\n return HSL_types(hsla);\n }\n\n // RGB to HSL\n if (colorType === \"rgb\" || colorType === \"rgba\") {\n const hsla = RGB_to_HSLA(color as string | rgbaT | rgbT);\n return HSL_types(hsla);\n }\n\n // HSV to HSL\n if (colorType === \"hsv\" || colorType === \"hsva\") {\n const hsla = HSV_to_HSLA(color as string | hsvaT | hsvT);\n return HSL_types(hsla);\n }\n\n // HWB to HSL\n if (colorType === \"hwb\" || colorType === \"hwba\") {\n const hsla = HWB_to_HSLA(color as string | hwbaT | hwbT);\n return HSL_types(hsla);\n }\n\n // HSL to normalized HSL\n if (colorType === \"hsl\" || colorType === \"hsla\") {\n const hsla = HSL_to_HSL(color as string | hslaT | hslT);\n return HSL_types(hsla);\n }\n\n // ! error\n console.error(\n '[colorKit.HSL] An error occurred while attempting to convert the provided parameter into an `HSL` color. As a result, the default color \"black\" will be used instead.',\n );\n\n return HSL_types({ h: 0, s: 0, l: 0, a: 1 });\n };\n\n /** - Convert `HSL`, `HEX`, `HSV`, or `RGB` color to the `HWB` color format. */\n const HWB = (color: SupportedColorFormats): ColorTypes => {\n // named color\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n\n if (Object.hasOwn(NAMED_COLORS, color)) {\n color = NAMED_COLORS[color as keyof typeof NAMED_COLORS] as string;\n }\n }\n\n const colorType = detectColorFormat(color);\n\n // HEX to HWB\n if (colorType?.includes(\"hex\")) {\n const hwba = HEX_to_HWBA(color as string);\n return HWB_types(hwba);\n }\n\n // RGB to HWB\n if (colorType === \"rgb\" || colorType === \"rgba\") {\n const hwba = RGB_to_HWBA(color as string | rgbaT | rgbT);\n return HWB_types(hwba);\n }\n\n // HSL to HWB\n if (colorType === \"hsl\" || colorType === \"hsla\") {\n const hwba = HSL_to_HWBA(color as string | hslaT | hslT);\n return HWB_types(hwba);\n }\n\n // HSV to HWB\n if (colorType === \"hsv\" || colorType === \"hsva\") {\n const hwba = HSV_to_HWBA(color as string | hsvaT | hsvT);\n return HWB_types(hwba);\n }\n\n // HWB to normalized HWB\n if (colorType === \"hwb\" || colorType === \"hwba\") {\n const hwba = HWB_to_HWB(color as string | hwbaT | hwbT);\n return HWB_types(hwba);\n }\n\n // ! error\n console.error(\n '[colorKit.HWB] An error occurred while attempting to convert the provided parameter into an `HWB` color. As a result, the default color \"black\" will be used instead.',\n );\n\n return HWB_types({ h: 0, w: 0, b: 100, a: 1 });\n };\n\n /** - Convert `HSL`, `HEX`, `HWB`, or `RGB` color to the `HSV` color format. */\n const HSV = (color: SupportedColorFormats): ColorTypes => {\n // named color\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n\n if (Object.hasOwn(NAMED_COLORS, color)) {\n color = NAMED_COLORS[color as keyof typeof NAMED_COLORS] as string;\n }\n }\n\n const colorType = detectColorFormat(color);\n\n // HEX to HSV\n if (colorType?.includes(\"hex\")) {\n const hsva = HEX_to_HSVA(color as string);\n return HSV_types(hsva);\n }\n\n // RGB to HSV\n if (colorType === \"rgb\" || colorType === \"rgba\") {\n const hsva = RGB_to_HSVA(color as string | rgbaT | rgbT);\n return HSV_types(hsva);\n }\n\n // HSL to HSV\n if (colorType === \"hsl\" || colorType === \"hsla\") {\n const hsva = HSL_to_HSVA(color as string | hslaT | hslT);\n return HSV_types(hsva);\n }\n\n // HWB to HSV\n if (colorType === \"hwb\" || colorType === \"hwba\") {\n const hsva = HWB_to_HSVA(color as string | hwbaT | hwbT);\n return HSV_types(hsva);\n }\n\n // HSV to normalized HSV\n if (colorType === \"hsv\" || colorType === \"hsva\") {\n const hsva = HSV_to_HSV(color as string | hsvaT | hsvT);\n return HSV_types(hsva);\n }\n\n // ! error\n console.error(\n '[colorKit.HSV] An error occurred while attempting to convert the provided parameter into an `HSV` color. As a result, the default color \"black\" will be used instead.',\n );\n\n return HSV_types({ h: 0, s: 0, v: 0, a: 1 });\n };\n\n // * MARK: Color Information\n\n /** - Identify the color format of a given `string` or `object`, and return `null` for invalid colors. */\n const getFormat = (color: SupportedColorFormats): ColorFormats | \"named\" | null => {\n // color int\n if (typeof color === \"number\") {\n // eslint-disable-next-line no-bitwise\n if (color >>> 0 === color && color >= 0 && color <= 0xffffffff) return \"hex8\";\n return null;\n }\n\n // color string\n if (typeof color === \"string\") {\n color = color.trim().toLowerCase();\n if (Object.hasOwn(NAMED_COLORS, color)) return \"named\";\n\n for (const key in COLORS_REGEX) {\n const format = key as ColorFormats;\n const entry = COLORS_REGEX[format];\n if (Array.isArray(entry)) {\n for (let i = 0; i < entry.length; i++) {\n const regex = entry[i];\n if (regex?.test(color)) return format;\n }\n continue;\n }\n if (entry.test(color)) return format;\n }\n }\n\n // color object\n if (typeof color === \"object\") {\n const rgbaKeys = [\"r\", \"g\", \"b\", \"a\"] as (keyof rgbaT)[];\n const isRgbaOb = rgbaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as rgbaT)[k] === \"number\",\n );\n if (isRgbaOb) return \"rgba\";\n\n const rgbKeys = [\"r\", \"g\", \"b\"] as (keyof rgbT)[];\n const isRgbOb = rgbKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as rgbT)[k] === \"number\",\n );\n if (isRgbOb) return \"rgb\";\n\n const hslaKeys = [\"h\", \"s\", \"l\", \"a\"] as (keyof hslaT)[];\n const isHslaOb = hslaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hslaT)[k] === \"number\",\n );\n if (isHslaOb) return \"hsla\";\n\n const hslKeys = [\"h\", \"s\", \"l\"] as (keyof hslT)[];\n const isHslOb = hslKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hslT)[k] === \"number\",\n );\n if (isHslOb) return \"hsl\";\n\n const hsvaKeys = [\"h\", \"s\", \"v\", \"a\"] as (keyof hsvaT)[];\n const isHsvaOb = hsvaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hsvaT)[k] === \"number\",\n );\n if (isHsvaOb) return \"hsva\";\n\n const hsvKeys = [\"h\", \"s\", \"v\"] as (keyof hsvT)[];\n const isHsvOb = hsvKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hsvT)[k] === \"number\",\n );\n if (isHsvOb) return \"hsv\";\n\n const hwbaKeys = [\"h\", \"w\", \"b\", \"a\"] as (keyof hwbaT)[];\n const isHwbaOb = hwbaKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hwbaT)[k] === \"number\",\n );\n if (isHwbaOb) return \"hwba\";\n\n const hwbKeys = [\"h\", \"w\", \"b\"] as (keyof hwbT)[];\n const isHwbOb = hwbKeys.every(\n (k) => Object.hasOwn(color, k) && typeof (color as hwbT)[k] === \"number\",\n );\n if (isHwbOb) return \"hwb\";\n }\n\n return null;\n };\n\n /** - Get the `red` channel value of a given color. */\n const getRed = (color: SupportedColorFormats): number => {\n const { r } = RGB(color).object();\n return r;\n };\n\n /** - Get the `green` channel value of a given color. */\n const getGreen = (color: SupportedColorFormats): number => {\n const { g } = RGB(color).object();\n return g;\n };\n\n /** - Get the `blue` channel value of a given color. */\n const getBlue = (color: SupportedColorFormats): number => {\n const { b } = RGB(color).object();\n return b;\n };\n\n /** - Get the `hue` channel value of a given color. */\n const getHue = (color: SupportedColorFormats): number => {\n const { h } = HSL(color).object();\n return h;\n };\n\n /** - Get the `saturation` value of a given color. */\n const getSaturation = (color: SupportedColorFormats): number => {\n const { s } = HSL(color).object();\n return s;\n };\n\n /**\n * - Get color's HSL `luminosity` channel value.\n * - If you want the overall `luminosity` of a color use `getLuminanceWCAG` method.\n */\n const getLuminance = (color: SupportedColorFormats): number => {\n const { l } = HSL(color).object();\n return l;\n };\n\n /** - Get the HSV's `value` (brightness) channel value of a given color. */\n const getBrightness = (color: SupportedColorFormats): number => {\n const { v } = HSV(color).object();\n return v;\n };\n\n /** - Returns the perceived `luminance` of a color, from `0-1` as defined by Web Content Accessibility Guidelines (Version 2.0). */\n const getLuminanceWCAG = (color: SupportedColorFormats): number => {\n const { r, g, b } = RGB(color).object(false);\n const a = [r, g, b].map((v) =>\n v / 255 <= 0.03928 ? v / 255 / 12.92 : ((v / 255 + 0.055) / 1.055) ** 2.4,\n );\n return (a[0] || 0) * 0.2126 + (a[1] || 0) * 0.7152 + (a[2] || 0) * 0.0722;\n };\n\n /** - Returns a boolean indicating whether the color is considered \"dark\" or not */\n const isDark = (color: SupportedColorFormats): boolean => {\n const luminance = getLuminanceWCAG(color);\n return luminance < 0.5;\n };\n\n /** - Returns a boolean indicating whether the color is considered \"light\" or not */\n const isLight = (color: SupportedColorFormats): boolean => {\n const luminance = getLuminanceWCAG(color);\n return luminance >= 0.5;\n };\n\n /**\n * - Check if two colors are similar within a specified tolerance.\n *\n * @example\n * const tolerance = 0;\n * const isEqual = colorKit.areColorsEqual('#f00', 'red', tolerance); // true\n */\n const areColorsEqual = (\n color1: SupportedColorFormats,\n color2: SupportedColorFormats,\n tolerance = 0,\n ): boolean => {\n const rgb1 = RGB(color1).object();\n const rgb2 = RGB(color2).object();\n\n const deltaR = rgb1.r - rgb2.r;\n const deltaG = rgb1.g - rgb2.g;\n const deltaB = rgb1.b - rgb2.b;\n const difference = Math.sqrt(deltaR * deltaR + deltaG * deltaG + deltaB * deltaB);\n\n return difference <= tolerance;\n };\n\n /** - Calculates the contrast ratio between two colors, useful for ensuring accessibility and readability. */\n const contrastRatio = (color1: SupportedColorFormats, color2: SupportedColorFormats): number => {\n const luminance1 = getLuminanceWCAG(color1);\n const luminance2 = getLuminanceWCAG(color2);\n const contrast =\n (Math.max(luminance1, luminance2) + 0.05) / (Math.min(luminance1, luminance2) + 0.05);\n return Math.round(contrast * 100) / 100;\n };\n\n // * MARK: Color Manipulation\n\n const returnColorObject = (color: SupportedColorFormats) => {\n return {\n hex() {\n return HEX(color);\n },\n rgb() {\n return RGB(color);\n },\n hsl() {\n return HSL(color);\n },\n hsv() {\n return HSV(color);\n },\n hwb() {\n return HWB(color);\n },\n };\n };\n\n // * MARK: Red Manuipulation\n /** Set the `red` value of a color to a specific amount. */\n const setRed = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { g, b, a } = RGB(color).object();\n const newR = clampRGB(amount);\n const newColor = { r: newR, g, b, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Increase the `red` value of a color by the given percentage/amount.\n *\n * @example\n * increaseRed('rgb(100, 100, 100)', 20).hex();\n * increaseRed('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const increaseRed = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const red = typeof amount === \"string\" ? r + r * (parseFloat(amount) / 100) : r + amount;\n const newR = clampRGB(red);\n const newColor = { r: newR, g, b, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Decrease the `red` value of a color by the given percentage/amount\n *\n * @example\n * decreaseRed('rgb(100, 100, 100)', 20).hex();\n * decreaseRed('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const decreaseRed = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const red = typeof amount === \"string\" ? r - r * (parseFloat(amount) / 100) : r - amount;\n const newR = clampRGB(red);\n const newColor = { r: newR, g, b, a };\n\n return returnColorObject(newColor);\n };\n\n // * MARK: Green Manuipulation\n /** - Set the `green` value of a color to a specific amount. */\n const setGreen = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { r, b, a } = RGB(color).object();\n const newG = clampRGB(amount);\n const newColor = { r, g: newG, b, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Increase the `green` value of a color by the given percentage.\n *\n * @example\n * increaseGreen('rgb(100, 100, 100)', 20).hex();\n * increaseGreen('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const increaseGreen = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const green = typeof amount === \"string\" ? g + g * (parseFloat(amount) / 100) : g + amount;\n const newG = clampRGB(green);\n const newColor = { r, g: newG, b, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Decrease the `green` value of a color by the given percentage.\n *\n * @example\n * decreaseGreen('rgb(100, 100, 100)', 20).hex();\n * decreaseGreen('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const decreaseGreen = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const green = typeof amount === \"string\" ? g - g * (parseFloat(amount) / 100) : g - amount;\n const newG = clampRGB(green);\n const newColor = { r, g: newG, b, a };\n\n return returnColorObject(newColor);\n };\n\n // * MARK: Blue Manuipulation\n /** - Set the `blue` value of a color to a specific amount. */\n const setBlue = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { r, g, a } = RGB(color).object();\n const newB = clampRGB(amount);\n const newColor = { r, g, b: newB, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Increase the `blue` value of a color by the given percentage.\n *\n * @example\n * increaseBlue('rgb(100, 100, 100)', 20).hex();\n * increaseBlue('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const increaseBlue = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const blue = typeof amount === \"string\" ? b + b * (parseFloat(amount) / 100) : b + amount;\n const newB = clampRGB(blue);\n const newColor = { r, g, b: newB, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Decrease the `blue` value of a color by the given percentage.\n *\n * @example\n * decreaseBlue('rgb(100, 100, 100)', 20).hex();\n * decreaseBlue('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const decreaseBlue = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const blue = typeof amount === \"string\" ? b - b * (parseFloat(amount) / 100) : b - amount;\n const newB = clampRGB(blue);\n const newColor = { r, g, b: newB, a };\n\n return returnColorObject(newColor);\n };\n\n //* MARK: Alpha Manuipulation\n /** - Get the `alpha` value of a given color. */\n const getAlpha = (color: SupportedColorFormats): number => {\n const { a } = RGB(color).object();\n return a;\n };\n\n /** - Set the `alpha` value of a color to a specific amount. */\n const setAlpha = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { r, g, b } = RGB(color).object();\n const newA = clampAlpha(amount);\n const newColor = { r, g, b, a: newA };\n\n return returnColorObject(newColor);\n };\n\n /** Increase the `alpha` value of a color by the given percentage. */\n const increaseAlpha = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const alpha = typeof amount === \"string\" ? a + a * (parseFloat(amount) / 100) : a + amount;\n const newA = clampAlpha(alpha);\n const newColor = { r, g, b, a: newA };\n\n return returnColorObject(newColor);\n };\n\n /** Decrease the `alpha` value of a color by the given percentage. */\n const decreaseAlpha = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const alpha = typeof amount === \"string\" ? a - a * (parseFloat(amount) / 100) : a - amount;\n const newA = clampAlpha(alpha);\n const newColor = { r, g, b, a: newA };\n\n return returnColorObject(newColor);\n };\n\n // * MARK: Hue Manuipulation\n /** - Set the `hue` value of a color to a specific amount. */\n const setHue = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { s, l, a } = HSL(color).object();\n const newH = clampHue(amount);\n const newColor = { h: newH, s, l, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Increase the `hue` value of a color by the given percentage/amount.\n *\n * @example\n * increaseHue('rgb(100, 100, 100)', 20).hex();\n * increaseHue('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const increaseHue = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const hue = typeof amount === \"string\" ? h + h * (parseFloat(amount) / 100) : h + amount;\n const newH = clampHue(hue);\n const newColor = { h: newH, s, l, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * Decrease the `hue` value of a color by the given percentage/amount.\n *\n * @example\n * decreaseHue('rgb(100, 100, 100)', 20).hex();\n * decreaseHue('rgb(100, 100, 100)', '20%').rgb().string();\n */\n const decreaseHue = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const hue = typeof amount === \"string\" ? h - h * (parseFloat(amount) / 100) : h - amount;\n const newH = clampHue(hue);\n const newColor = { h: newH, s, l, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * - Spin the `hue` channel by a certain percentage/amount.\n *\n * @example\n * spin('red', 20).hex();\n * spin('rgb(255, 0, 0)', '20%').rgb().string();\n */\n const spin = (color: SupportedColorFormats, degree: number | string): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const spinDegree = typeof degree === \"string\" ? s * (parseFloat(degree) / 100) : degree;\n const newColor = { h: Math.round((h + spinDegree) % 360), s, l, a };\n\n return returnColorObject(newColor);\n };\n\n // * MARK: Saturation Manuipulation\n /** - Set the `saturation` value of a color to a specific amount. */\n const setSaturation = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { h, l, a } = HSL(color).object();\n const newS = clamp100(amount);\n const saturatedColor = { h, s: newS, l, a };\n\n return returnColorObject(saturatedColor);\n };\n\n /**\n * - Increase the saturation of the given color by a certain percentage/amount.\n *\n * @example\n * saturate('red', 20).hex();\n * saturate('rgb(255, 0, 0)', '20%').rgb().string();\n */\n const saturate = (color: SupportedColorFormats, amount: number | string): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const saturation = typeof amount === \"string\" ? s + s * (parseFloat(amount) / 100) : s + amount;\n const newS = clamp100(saturation);\n const saturatedColor = { h, s: newS, l, a };\n\n return returnColorObject(saturatedColor);\n };\n\n /**\n * - Decrease the saturation of the given color by a certain percentage/amount.\n *\n * @example\n * saturate('red', 20).hex();\n * saturate('rgb(255, 0, 0)', '20%').rgb().string();\n */\n const desaturate = (color: SupportedColorFormats, amount: number | string): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const saturation = typeof amount === \"string\" ? s - s * (parseFloat(amount) / 100) : s - amount;\n const newS = clamp100(saturation);\n const desaturatedColor = { h, s: newS, l, a };\n\n return returnColorObject(desaturatedColor);\n };\n\n // * MARK: Brightness Manuipulation\n /** - Set HSL's `luminosity` channel for a given color to a specific amount. */\n const setLuminance = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { h, s, a } = HSL(color).object();\n const newL = clamp100(amount);\n const newColor = { h, s, l: newL, a };\n\n return returnColorObject(newColor);\n };\n\n /**\n * - Increase the brightness of the given color by a certain percentage/amount.\n *\n * @example\n * brighten('red', 20).hex();\n * brighten('rgb(255, 0, 0)', '20%').rgb().string();\n */\n const brighten = (color: SupportedColorFormats, amount: number | string): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const lum = typeof amount === \"string\" ? l + l * (parseFloat(amount) / 100) : l + amount;\n const newL = clamp100(lum);\n const brightenedColor = { h, s, l: newL, a };\n\n return returnColorObject(brightenedColor);\n };\n\n /**\n * - Decrease the brightness of the given color by a certain percentage/amount.\n *\n * @example\n * darken('red', 20).hex();\n * darken('rgb(255, 0, 0)', '20%').rgb().string();\n */\n const darken = (color: SupportedColorFormats, amount: number | string): ConversionMethods => {\n const { h, s, l, a } = HSL(color).object();\n const lum = typeof amount === \"string\" ? l - l * (parseFloat(amount) / 100) : l - amount;\n const newL = clamp100(lum);\n const darkenedColor = { h, s, l: newL, a };\n\n return returnColorObject(darkenedColor);\n };\n\n /** - Set HSV's `value` (brightness) channel for a given color to a specific amount. */\n const setBrightness = (color: SupportedColorFormats, amount: number): ConversionMethods => {\n const { h, s, a } = HSV(color).object();\n const newV = clamp100(amount);\n const newColor = { h, s, v: newV, a };\n\n return returnColorObject(newColor);\n };\n\n /** Increase HSV's `value` (brightness) channel value of a color by the given percentage/amount. */\n const increaseBrightness = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { h, s, v, a } = HSV(color).object();\n const value = typeof amount === \"string\" ? v + v * (parseFloat(amount) / 100) : v + amount;\n const newV = clamp100(value);\n const newColor = { h, s, v: newV, a };\n\n return returnColorObject(newColor);\n };\n\n /** Decrease HSV's `value` (brightness) channel value of a color by the given percentage/amount. */\n const decreaseBrightness = (\n color: SupportedColorFormats,\n amount: number | string,\n ): ConversionMethods => {\n const { h, s, v, a } = HSV(color).object();\n const value = typeof amount === \"string\" ? v - v * (parseFloat(amount) / 100) : v - amount;\n const newV = clamp100(value);\n const newColor = { h, s, v: newV, a };\n\n return returnColorObject(newColor);\n };\n\n // * MARK: Color Utilities\n\n /**\n * - Blends two colors by a certain amount.\n *\n * @example\n * blend('yellow', 'red', 50).hex(); // #ff8000\n */\n const blend = (\n color1: SupportedColorFormats,\n color2: SupportedColorFormats,\n percentage: number,\n ): ConversionMethods => {\n percentage = percentage / 100;\n\n const rgba1 = RGB(color1).object();\n const rgba2 = RGB(color2).object();\n\n const r = clampRGB(rgba1.r * (1 - percentage) + rgba2.r * percentage),\n g = clampRGB(rgba1.g * (1 - percentage) + rgba2.g * percentage),\n b = clampRGB(rgba1.b * (1 - percentage) + rgba2.b * percentage),\n a = clampAlpha(rgba1.a * (1 - percentage) + rgba2.a * percentage);\n\n const blendedColor = { r, g, b, a };\n\n return returnColorObject(blendedColor);\n };\n\n /** - Invert (negate) a color, black becomes white, white becomes black, blue becomes orange and so on. */\n const invert = (color: SupportedColorFormats): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const invertedColor = { r: 255 - r, g: 255 - g, b: 255 - b, a };\n return returnColorObject(invertedColor);\n };\n\n /** - Completely desaturate a color into grayscale. */\n const grayscale = (color: SupportedColorFormats): ConversionMethods => {\n const { r, g, b, a } = RGB(color).object();\n const gray = clampRGB(r * 0.3 + g * 0.59 + b * 0.11);\n const grayColor = { r: gray, g: gray, b: gray, a };\n\n return returnColorObject(grayColor);\n };\n\n /** - Generate a random color from `HSL` values. */\n const randomHslColor = ({\n h = [0, 360],\n s = [0, 100],\n l = [0, 100],\n a = [1, 1],\n } = {}): ConversionMethods => {\n const random = {\n h: clampHue(randomNumber(h[0] ?? 0, h[1] ?? 360)),\n s: clamp100(randomNumber(s[0] ?? 0, s[1] ?? 100)),\n l: clamp100(randomNumber(l[0] ?? 0, l[1] ?? 100)),\n a: clampAlpha(randomNumber(a[0] ?? 1, a[1] ?? 1)),\n };\n\n return returnColorObject(random);\n };\n\n /** - Generate a random color from `HSV` values. */\n const randomHsvColor = ({\n h = [0, 360],\n s = [0, 100],\n v = [0, 100],\n a = [1, 1],\n } = {}): ConversionMethods => {\n const random = {\n h: clampHue(randomNumber(h[0] ?? 0, h[1] ?? 360)),\n s: clamp100(randomNumber(s[0] ?? 0, s[1] ?? 100)),\n v: clamp100(randomNumber(v[0] ?? 0, v[1] ?? 100)),\n a: clampAlpha(randomNumber(a[0] ?? 1, a[1] ?? 1)),\n };\n\n return returnColorObject(random);\n };\n\n /** - Generate a random color from `RGB` values. */\n const randomRgbColor = ({\n r = [0, 255],\n g = [0, 255],\n b = [0, 255],\n a = [1, 1],\n } = {}): ConversionMethods => {\n const random = {\n r: clampRGB(randomNumber(r[0] ?? 0, r[1] ?? 255)),\n g: clampRGB(randomNumber(g[0] ?? 0, g[1] ?? 255)),\n b: clampRGB(randomNumber(b[0] ?? 0, b[1] ?? 255)),\n a: clampAlpha(randomNumber(a[0] ?? 1, a[1] ?? 1)),\n };\n\n return returnColorObject(random);\n };\n\n /** - Generate a random color from `HWB` values. */\n const randomHwbColor = ({\n h = [0, 360],\n w = [0, 100],\n b = [0, 100],\n a = [1, 1],\n } = {}): ConversionMethods => {\n const random = {\n h: clampHue(randomNumber(h[0] ?? 0, h[1] ?? 360)),\n w: clamp100(randomNumber(w[0] ?? 0, w[1] ?? 100)),\n b: clamp100(randomNumber(b[0] ?? 0, b[1] ?? 100)),\n a: clampAlpha(randomNumber(a[0] ?? 1, a[1] ?? 1)),\n };\n\n return returnColorObject(random);\n };\n\n /** - Returns the first color with the desired contrast ratio against the second color */\n const adjustContrast = (\n color1: SupportedColorFormats,\n color2: SupportedColorFormats,\n ratio = 4.5,\n ): ConversionMethods => {\n const contrast = contrastRatio(color1, color2);\n const color1RGB = RGB(color1).object();\n const channels = [\"r\", \"g\", \"b\"] as const;\n\n function adjustLuminance(colorRGB: rgbaT, by: number) {\n const r = clampRGB(colorRGB.r + by);\n const g = clampRGB(colorRGB.g + by);\n const b = clampRGB(colorRGB.b + by);\n return { r, g, b, a: colorRGB.a };\n }\n\n let newColor = color1RGB;\n\n //* increase contrast\n if (ratio && contrast < ratio) {\n while (contrastRatio(newColor, color2) < ratio) {\n const adjustBy = isDark(color2) ? 1 : -1; // increase or decrease relative to the background color\n newColor = adjustLuminance(newColor, adjustBy);\n\n // break if the color reached the limit\n if (channels.every((e) => newColor[e] === 0)) break;\n if (channels.every((e) => newColor[e] === 255)) break;\n }\n //* decrease contrast\n } else if (ratio && contrast > ratio) {\n while (contrastRatio(newColor, color2) > ratio) {\n const adjustBy = !isDark(color2) ? 1 : -1; // increase or decrease relative to the background color\n newColor = adjustLuminance(newColor, adjustBy);\n\n // break if the color reached the limit\n if (channels.every((e) => newColor[e] === 0)) break;\n if (channels.every((e) => newColor[e] === 255)) break;\n }\n }\n\n return returnColorObject(newColor);\n };\n\n return {\n // color conversion\n HEX,\n RGB,\n HSL,\n HWB,\n HSV,\n // color information\n getFormat,\n getRed,\n getGreen,\n getBlue,\n getHue,\n getSaturation,\n getBrightness,\n getLuminance,\n getLuminanceWCAG,\n isDark,\n isLight,\n areColorsEqual,\n contrastRatio,\n\n // color manipulation\n setRed,\n increaseRed,\n decreaseRed,\n\n setGreen,\n increaseGreen,\n decreaseGreen,\n\n setBlue,\n increaseBlue,\n decreaseBlue,\n\n getAlpha,\n setAlpha,\n increaseAlpha,\n decreaseAlpha,\n\n setHue,\n increaseHue,\n decreaseHue,\n spin,\n\n setSaturation,\n saturate,\n desaturate,\n\n setLuminance,\n brighten,\n darken,\n setBrightness,\n increaseBrightness,\n decreaseBrightness,\n\n // color utilities\n blend,\n invert,\n grayscale,\n randomHslColor,\n randomHsvColor,\n randomRgbColor,\n randomHwbColor,\n adjustContrast,\n };\n};\n\ntype ColorKit = ReturnType & {\n /** - Initiates the asynchronous execution of a workletized colorKit function on the UI thread. */\n runOnUI: typeof colorKitUI;\n};\n\nconst colorKit = colorKitUI() as ColorKit;\ncolorKit.runOnUI = colorKitUI;\nexport default colorKit;\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/external/utils/color-kit/index.ts" }, { "path": "registry/native-ui/src/helpers/external/utils/color-kit/types.ts", "content": "/**\n * Color manipulation utilities adapted from reanimated-color-picker\n *\n * Original source: https://github.com/alabsi91/reanimated-color-picker\n * Author: @alabsi91\n * License: MIT\n *\n * This code has been adapted for use in PitsiUI Native with modifications\n * for TypeScript compatibility and integration with the theme system.\n */\n\ntype NAMED_COLORS = {\n readonly aliceblue: \"#f0f8ff\";\n readonly antiquewhite: \"#faebd7\";\n readonly aqua: \"#00ffff\";\n readonly aquamarine: \"#7fffd4\";\n readonly azure: \"#f0ffff\";\n readonly beige: \"#f5f5dc\";\n readonly bisque: \"#ffe4c4\";\n readonly black: \"#000000\";\n readonly blanchedalmond: \"#ffebcd\";\n readonly blue: \"#0000ff\";\n readonly blueviolet: \"#8a2be2\";\n readonly brown: \"#a52a2a\";\n readonly burlywood: \"#deb887\";\n readonly cadetblue: \"#5f9ea0\";\n readonly chartreuse: \"#7fff00\";\n readonly chocolate: \"#d2691e\";\n readonly coral: \"#ff7f50\";\n readonly cornflowerblue: \"#6495ed\";\n readonly cornsilk: \"#fff8dc\";\n readonly crimson: \"#dc143c\";\n readonly cyan: \"#00ffff\";\n readonly darkblue: \"#00008b\";\n readonly darkcyan: \"#008b8b\";\n readonly darkgoldenrod: \"#b8860b\";\n readonly darkgray: \"#a9a9a9\";\n readonly darkgreen: \"#006400\";\n readonly darkgrey: \"#a9a9a9\";\n readonly darkkhaki: \"#bdb76b\";\n readonly darkmagenta: \"#8b008b\";\n readonly darkolivegreen: \"#556b2f\";\n readonly darkorange: \"#ff8c00\";\n readonly darkorchid: \"#9932cc\";\n readonly darkred: \"#8b0000\";\n readonly darksalmon: \"#e9967a\";\n readonly darkseagreen: \"#8fbc8f\";\n readonly darkslateblue: \"#483d8b\";\n readonly darkslategrey: \"#2f4f4f\";\n readonly darkturquoise: \"#00ced1\";\n readonly darkviolet: \"#9400d3\";\n readonly deeppink: \"#ff1493\";\n readonly deepskyblue: \"#00bfff\";\n readonly dimgray: \"#696969\";\n readonly dimgrey: \"#696969\";\n readonly dodgerblue: \"#1e90ff\";\n readonly firebrick: \"#b22222\";\n readonly floralwhite: \"#fffaf0\";\n readonly forestgreen: \"#228b22\";\n readonly fuchsia: \"#ff00ff\";\n readonly gainsboro: \"#dcdcdc\";\n readonly ghostwhite: \"#f8f8ff\";\n readonly gold: \"#ffd700\";\n readonly goldenrod: \"#daa520\";\n readonly gray: \"#808080\";\n readonly green: \"#008000\";\n readonly greenyellow: \"#adff2f\";\n readonly grey: \"#808080\";\n readonly honeydew: \"#f0fff0\";\n readonly hotpink: \"#ff69b4\";\n readonly indianred: \"#cd5c5c\";\n readonly indigo: \"#4b0082\";\n readonly ivory: \"#fffff0\";\n readonly khaki: \"#f0e68c\";\n readonly lavender: \"#e6e6fa\";\n readonly lavenderblush: \"#fff0f5\";\n readonly lawngreen: \"#7cfc00\";\n readonly lemonchiffon: \"#fffacd\";\n readonly lightblue: \"#add8e6\";\n readonly lightcoral: \"#f08080\";\n readonly lightcyan: \"#e0ffff\";\n readonly lightgoldenrodyellow: \"#fafad2\";\n readonly lightgray: \"#d3d3d3\";\n readonly lightgreen: \"#90ee90\";\n readonly lightgrey: \"#d3d3d3\";\n readonly lightpink: \"#ffb6c1\";\n readonly lightsalmon: \"#ffa07a\";\n readonly lightseagreen: \"#20b2aa\";\n readonly lightskyblue: \"#87cefa\";\n readonly lightslategrey: \"#778899\";\n readonly lightsteelblue: \"#b0c4de\";\n readonly lightyellow: \"#ffffe0\";\n readonly lime: \"#00ff00\";\n readonly limegreen: \"#32cd32\";\n readonly linen: \"#faf0e6\";\n readonly magenta: \"#ff00ff\";\n readonly maroon: \"#800000\";\n readonly mediumaquamarine: \"#66cdaa\";\n readonly mediumblue: \"#0000cd\";\n readonly mediumorchid: \"#ba55d3\";\n readonly mediumpurple: \"#9370db\";\n readonly mediumseagreen: \"#3cb371\";\n readonly mediumslateblue: \"#7b68ee\";\n readonly mediumspringgreen: \"#00fa9a\";\n readonly mediumturquoise: \"#48d1cc\";\n readonly mediumvioletred: \"#c71585\";\n readonly midnightblue: \"#191970\";\n readonly mintcream: \"#f5fffa\";\n readonly mistyrose: \"#ffe4e1\";\n readonly moccasin: \"#ffe4b5\";\n readonly navajowhite: \"#ffdead\";\n readonly navy: \"#000080\";\n readonly oldlace: \"#fdf5e6\";\n readonly olive: \"#808000\";\n readonly olivedrab: \"#6b8e23\";\n readonly orange: \"#ffa500\";\n readonly orangered: \"#ff4500\";\n readonly orchid: \"#da70d6\";\n readonly palegoldenrod: \"#eee8aa\";\n readonly palegreen: \"#98fb98\";\n readonly paleturquoise: \"#afeeee\";\n readonly palevioletred: \"#db7093\";\n readonly papayawhip: \"#ffefd5\";\n readonly peachpuff: \"#ffdab9\";\n readonly peru: \"#cd853f\";\n readonly pink: \"#ffc0cb\";\n readonly plum: \"#dda0dd\";\n readonly powderblue: \"#b0e0e6\";\n readonly purple: \"#800080\";\n readonly rebeccapurple: \"#663399\";\n readonly red: \"#ff0000\";\n readonly rosybrown: \"#bc8f8f\";\n readonly royalblue: \"#4169e1\";\n readonly saddlebrown: \"#8b4513\";\n readonly salmon: \"#fa8072\";\n readonly sandybrown: \"#f4a460\";\n readonly seagreen: \"#2e8b57\";\n readonly seashell: \"#fff5ee\";\n readonly sienna: \"#a0522d\";\n readonly silver: \"#c0c0c0\";\n readonly skyblue: \"#87ceeb\";\n readonly slateblue: \"#6a5acd\";\n readonly slategray: \"#708090\";\n readonly snow: \"#fffafa\";\n readonly springgreen: \"#00ff7f\";\n readonly steelblue: \"#4682b4\";\n readonly tan: \"#d2b48c\";\n readonly teal: \"#008080\";\n readonly thistle: \"#d8bfd8\";\n readonly tomato: \"#ff6347\";\n readonly turquoise: \"#40e0d0\";\n readonly violet: \"#ee82ee\";\n readonly wheat: \"#f5deb3\";\n readonly white: \"#ffffff\";\n readonly whitesmoke: \"#f5f5f5\";\n readonly yellow: \"#ffff00\";\n readonly yellowgreen: \"#9acd32\";\n};\n\nexport type ColorFormats =\n | \"hex3\"\n | \"hex4\"\n | \"hex6\"\n | \"hex8\"\n | \"hsl\"\n | \"hsla\"\n | \"rgb\"\n | \"rgba\"\n | \"hsva\"\n | \"hsv\"\n | \"hwba\"\n | \"hwb\";\n\nexport type ColorString = keyof NAMED_COLORS | (string & NonNullable);\n\nexport type rgbaT = { r: number; g: number; b: number; a: number };\nexport type rgbT = Omit;\n\nexport type hslaT = { h: number; s: number; l: number; a: number };\nexport type hslT = Omit;\n\nexport type hsvaT = { h: number; s: number; v: number; a: number };\nexport type hsvT = Omit;\n\nexport type hwbaT = { h: number; w: number; b: number; a: number };\nexport type hwbT = Omit;\n\nexport type SupportedColorFormats =\n | ColorString\n | rgbaT\n | rgbT\n | hslaT\n | hslT\n | hsvaT\n | hsvT\n | hwbaT\n | hwbT\n | number;\n\nexport type ColorTypes = {\n object: (roundValues?: boolean) => T;\n string: (alpha?: boolean) => string;\n array: (roundValues?: boolean) => number[];\n};\n\nexport type ConversionMethods = {\n hex: () => string;\n rgb: () => ColorTypes;\n hsl: () => ColorTypes;\n hsv: () => ColorTypes;\n hwb: () => ColorTypes;\n};\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/external/utils/color-kit/types.ts" }, { "path": "registry/native-ui/src/helpers/external/utils/index.ts", "content": "export * from \"./cn\";\nexport { default as colorKit } from \"./color-kit\";\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/external/utils/index.ts" }, { "path": "registry/native-ui/src/helpers/internal/components/hero-text.tsx", "content": "import React from \"react\";\nimport { Text as RNText, type TextProps as RNTextProps } from \"react-native\";\nimport { useTextComponent } from \"../../external/hooks\";\nimport { cn } from \"../../external/utils\";\n\n/**\n * Props for HeroText component\n */\nexport interface HeroTextProps extends RNTextProps {\n /**\n * Additional CSS classes that will be merged with the default 'font-normal' class\n */\n className?: string;\n}\n\n/**\n * HeroText component that automatically applies global text configuration\n * from PitsiUINativeProvider.\n *\n * This component is distinct from React Native's Text component and includes\n * a default 'font-normal' className that can be extended via the className prop.\n *\n * Global text props that can be configured:\n * - adjustsFontSizeToFit: Auto-scale text to fit constraints\n * - allowFontScaling: Respect Text Size accessibility settings\n * - maxFontSizeMultiplier: Maximum font scale when allowFontScaling is enabled\n * - minimumFontScale: Minimum scale when adjustsFontSizeToFit is enabled (iOS only)\n *\n * @example\n * ```tsx\n * Hello World\n * ```\n *\n * @example\n * With custom className:\n * ```tsx\n * Hello World\n * ```\n *\n * @example\n * Global configuration in PitsiUINativeProvider:\n * ```tsx\n * \n * \n * \n * ```\n */\nexport const HeroText = React.forwardRef((props, ref) => {\n const { className, ...restProps } = props;\n const { textProps } = useTextComponent();\n\n const mergedProps = Object.assign({}, textProps, restProps);\n\n return ;\n});\n\nHeroText.displayName = \"HeroText\";\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/components/hero-text.tsx" }, { "path": "registry/native-ui/src/helpers/internal/contexts/animation-settings-context.ts", "content": "import { createContext } from \"../utils\";\n\n/**\n * Context value for global animation settings\n */\nexport interface AnimationSettingsContextValue {\n /**\n * Whether all animations should be disabled (cascading from parent)\n */\n isAllAnimationsDisabled: boolean;\n}\n\nconst [AnimationSettingsProvider, useAnimationSettings] =\n createContext({\n name: \"AnimationSettingsContext\",\n strict: false,\n });\n\nexport { AnimationSettingsProvider, useAnimationSettings };\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/contexts/animation-settings-context.ts" }, { "path": "registry/native-ui/src/helpers/internal/contexts/bottom-sheet-is-dragging-context.ts", "content": "import type { SharedValue } from \"react-native-reanimated\";\nimport { createContext } from \"../utils\";\n\nconst [BottomSheetIsDraggingProvider, useBottomSheetIsDragging] = createContext<{\n isDragging: SharedValue;\n}>({\n name: \"BottomSheetIsDraggingContext\",\n});\n\nexport { BottomSheetIsDraggingProvider, useBottomSheetIsDragging };\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/contexts/bottom-sheet-is-dragging-context.ts" }, { "path": "registry/native-ui/src/helpers/internal/contexts/form-field-context.ts", "content": "import { createContext } from \"../utils\";\n\n/**\n * Combined context value for form field state and layout (shared across form field components).\n *\n * Providers: TextField, SearchField, ControlField, RadioGroup.\n * Consumers: Label, Description, FieldError, Input.\n */\nexport interface FormFieldContextValue {\n /**\n * Whether the form field is required\n */\n isRequired: boolean;\n /**\n * Whether the form field is disabled\n */\n isDisabled: boolean;\n /**\n * Whether the form field is in an invalid state\n */\n isInvalid: boolean;\n /**\n * When true, child components (Label, Description, FieldError) apply\n * additional horizontal padding (`px-1.5`) for consistent field layout.\n *\n * Set to `true` by container components like TextField and SearchField.\n */\n hasFieldPadding: boolean;\n}\n\nconst [FormFieldProvider, useFormField] = createContext({\n name: \"FormFieldContext\",\n strict: false,\n});\n\nexport { FormFieldProvider, useFormField };\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/contexts/form-field-context.ts" }, { "path": "registry/native-ui/src/helpers/internal/contexts/index.ts", "content": "export * from \"./animation-settings-context\";\nexport * from \"./bottom-sheet-is-dragging-context\";\nexport * from \"./form-field-context\";\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/contexts/index.ts" }, { "path": "registry/native-ui/src/helpers/internal/hooks/use-combined-animation-disabled-state.ts", "content": "import { useGlobalAnimationSettings } from \"../../../providers/animation-settings\";\nimport { useAnimationSettings } from \"../contexts/animation-settings-context\";\nimport type { AnimationRoot } from \"../types/animation\";\nimport { getCombinedAnimationDisabledState, getRootAnimationState } from \"../utils/animation\";\n\n/**\n * Hook to combine global, parent, and own animation disabled states\n *\n * @description\n * This hook combines three sources of animation disabled state:\n * 1. Global state from GlobalAnimationSettingsProvider\n * 2. Parent state from AnimationSettingsContext (component tree cascading)\n * 3. Own state from the component's animation prop\n *\n * Priority: Global > Parent > Own (global wins if enabled)\n *\n * @param animation - Root animation configuration for the component\n * @returns Combined isAllAnimationsDisabled value\n *\n * @example\n * ```tsx\n * const isAllAnimationsDisabled = useCombinedAnimationDisabledState(animation);\n * ```\n */\nexport function useCombinedAnimationDisabledState>(\n animation: AnimationRoot | undefined,\n): boolean {\n // Get global animation disabled state\n const { globalIsAllAnimationsDisabled } = useGlobalAnimationSettings();\n\n // Read parent animation disabled state from global context\n const parentAnimationSettingsContext = useAnimationSettings();\n const parentIsAllAnimationsDisabled = parentAnimationSettingsContext?.isAllAnimationsDisabled;\n\n // Get own animation disabled state\n const { isAllAnimationsDisabled: ownIsAllAnimationsDisabled } = getRootAnimationState(animation);\n\n // Combine global, parent, and own disable-all states (global > parent > own)\n return getCombinedAnimationDisabledState({\n globalIsAllAnimationsDisabled,\n parentIsAllAnimationsDisabled,\n ownIsAllAnimationsDisabled,\n });\n}\n", "type": "registry:hook", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/hooks/use-combined-animation-disabled-state.ts" }, { "path": "registry/native-ui/src/helpers/internal/types/animation.ts", "content": "import type {\n BaseAnimationBuilder,\n EntryOrExitLayoutType,\n LayoutAnimationFunction,\n WithSpringConfig,\n WithTimingConfig,\n} from \"react-native-reanimated\";\n\n/**\n * Universal animation prop type\n * - `true` or `undefined`: Use default animations\n * - `false` or `\"disabled\"`: Disable all animations\n * - `object`: Custom animation configuration\n * - Can include `state?: 'disabled' | boolean | undefined` to disable animations while customizing properties\n */\nexport type Animation = Record> =\n | boolean\n | \"disabled\"\n | (TConfig & { state?: \"disabled\" | boolean });\n\nexport type AnimationDisabled = \"disabled\" | false;\n\n/**\n * Root-level animation prop type with cascading control\n * - `true` or `undefined`: Use default animations\n * - `false` or `\"disabled\"`: Disable only root animations (children can still animate)\n * - `\"disable-all\"`: Disable all animations including children (cascades down)\n * - `object`: Custom animation configuration\n * - Can include `state?: 'disabled' | 'disable-all' | boolean` to disable animations while customizing properties\n */\nexport type AnimationRoot = Record> =\n | boolean\n | \"disabled\"\n | \"disable-all\"\n | (TConfig & { state?: \"disabled\" | \"disable-all\" | boolean });\n\nexport type AnimationRootDisableAll = Extract;\n\n/**\n * Animation value that can be a custom config\n * Used for granular animation control within a component\n */\nexport type AnimationValue = Record> = TConfig;\n\nexport type LayoutTransition =\n | BaseAnimationBuilder\n | LayoutAnimationFunction\n | typeof BaseAnimationBuilder\n | undefined;\n\n/**\n * Spring animation configuration\n */\nexport interface SpringAnimationConfig {\n type: \"spring\";\n config?: WithSpringConfig;\n}\n\n/**\n * Timing animation configuration\n */\nexport interface TimingAnimationConfig {\n type: \"timing\";\n config?: WithTimingConfig;\n}\n\n/**\n * Animation configuration for popup overlay components (Dialog, Select, BottomSheet, Popover, etc.)\n * Supports both progress-based opacity animation and entering/exiting animations\n */\nexport type PopupOverlayAnimation = Animation<{\n /**\n * Opacity animation configuration (progress-based)\n * Takes effect for bottom-sheet/dialog presentation\n * @default [0, 1, 0] - opacity values for [idle, open, close] states\n */\n opacity?: AnimationValue<{\n /**\n * Opacity values [idle, open, close]\n * @default [0, 1, 0]\n */\n value?: [number, number, number];\n }>;\n /**\n * Takes effect for popover presentation\n * @default FadeIn with duration 200ms\n */\n entering?: EntryOrExitLayoutType;\n /**\n * Takes effect for popover presentation\n * @default FadeOut with duration 150ms\n */\n exiting?: EntryOrExitLayoutType;\n}>;\n\n/**\n * Animation configuration for popup dialog content components (Dialog, Select dialog presentation)\n * Supports opacity and scale animations\n */\nexport type PopupDialogContentAnimation = Animation<{\n /**\n * Custom Keyframe animation for entering transition\n * @default Keyframe with scale, and opacity (200ms)\n */\n entering?: EntryOrExitLayoutType;\n /**\n * Custom Keyframe animation for exiting transition\n * @default Keyframe mirroring entering animation (150ms)\n */\n exiting?: EntryOrExitLayoutType;\n}>;\n\n/**\n * Animation configuration for popup popover content components (Popover, Select popover presentation)\n * Supports custom Keyframe animations for entering and exiting transitions\n */\nexport type PopupPopoverContentAnimation = Animation<{\n /**\n * Custom Keyframe animation for entering transition\n * @default Keyframe with translateY/translateX, scale, and opacity (200ms)\n */\n entering?: EntryOrExitLayoutType;\n /**\n * Custom Keyframe animation for exiting transition\n * @default Keyframe mirroring entering animation (150ms)\n */\n exiting?: EntryOrExitLayoutType;\n}>;\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/types/animation.ts" }, { "path": "registry/native-ui/src/helpers/internal/types/bottom-sheet.ts", "content": "import type { BottomSheetViewProps } from \"@gorhom/bottom-sheet/lib/typescript/components/bottomSheetView/types\";\nimport type { ReactNode } from \"react\";\nimport type { SharedValue } from \"react-native-reanimated\";\nimport type { AnimationDisabled } from \"./animation\";\n\n/**\n * State type for bottom sheet content container animation coordination\n */\nexport type BottomSheetContentContainerState = \"idle\" | \"open\" | \"close\";\n\n/**\n * Props for the reusable BottomSheetContentContainer component\n */\nexport interface BottomSheetContentContainerProps {\n /**\n * The content to be rendered inside the container\n */\n children?: ReactNode;\n /**\n * Additional CSS class for the content container\n */\n contentContainerClassName?: string;\n /**\n * Props for the content container\n */\n contentContainerProps?: Omit;\n /**\n * Whether the bottom sheet is open\n */\n isOpen: boolean;\n /**\n * Animation progress shared value (0=idle, 1=open, 2=close)\n */\n progress: SharedValue;\n /**\n * Whether the bottom sheet is dragging\n */\n isDragging: SharedValue;\n /**\n * Whether the bottom sheet is pan activated\n */\n isPanActivated: SharedValue;\n /**\n * Whether the bottom sheet is closing on swipe\n */\n isClosingOnSwipe: SharedValue;\n /**\n * Initial index of the bottom sheet\n */\n initialIndex: number;\n /**\n * Callback when the bottom sheet is opened\n */\n onOpenChange: (open: boolean) => void;\n /**\n * Whether the bottom sheet can be closed by panning down\n */\n enablePanDownToClose: boolean;\n}\n\n/**\n * Base props shared across BottomSheet Content components\n * Used by BottomSheet, Popover, and Select components when using bottom-sheet presentation\n */\nexport interface BaseBottomSheetContentProps {\n /**\n * The bottom sheet content\n */\n children?: ReactNode;\n /**\n * Additional CSS class for the bottom sheet\n */\n className?: string;\n /**\n * Additional CSS class for the container\n */\n containerClassName?: string;\n /**\n * Additional CSS class for the content container\n */\n contentContainerClassName?: string;\n /**\n * Additional CSS class for the background\n */\n backgroundClassName?: string;\n /**\n * Additional CSS class for the handle\n */\n handleClassName?: string;\n /**\n * Additional CSS class for the handle indicator\n */\n handleIndicatorClassName?: string;\n /**\n * Props for the content container\n */\n contentContainerProps?: Omit;\n /**\n * Animation configuration for bottom sheet content\n * - `false` or `\"disabled\"`: Disable all animations\n */\n animation?: AnimationDisabled;\n}\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/types/bottom-sheet.ts" }, { "path": "registry/native-ui/src/helpers/internal/types/index.ts", "content": "export * from \"./animation\";\nexport * from \"./bottom-sheet\";\nexport * from \"./misc\";\nexport * from \"./primitives\";\nexport * from \"./theme\";\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/types/index.ts" }, { "path": "registry/native-ui/src/helpers/internal/types/misc.ts", "content": "type ReactChild =\n | string\n | number\n | bigint\n | React.ReactElement>\n | Iterable\n | React.ReactPortal\n | Promise;\n\nexport type { ReactChild };\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/types/misc.ts" }, { "path": "registry/native-ui/src/helpers/internal/types/primitives.ts", "content": "import type { Pressable, Text, View, ViewStyle } from \"react-native\";\n\n// Base utility types\n\n/**\n * Component props with optional asChild prop for polymorphic components\n * Allows components to render as different elements when asChild is true\n */\ntype ComponentPropsWithAsChild> =\n React.ComponentPropsWithoutRef & { asChild?: boolean };\n\n// Ref types\n\n/**\n * Reference type for React Native View component\n * Used for forwarding refs to View elements\n */\ntype ViewRef = React.ComponentRef;\n\n/**\n * Reference type for React Native Pressable component\n * Used for forwarding refs to Pressable elements\n */\ntype PressableRef = React.ComponentRef;\n\n/**\n * Reference type for React Native Text component\n * Used for forwarding refs to Text elements\n */\ntype TextRef = React.ComponentRef;\n\n// Slottable component props\n\n/**\n * View component props with asChild support for slot composition\n * Enables View components to be used with the Slot pattern\n */\ntype SlottableViewProps = ComponentPropsWithAsChild;\n\n/**\n * Pressable component props with asChild support for slot composition\n * Enables Pressable components to be used with the Slot pattern\n */\ntype SlottablePressableProps = ComponentPropsWithAsChild;\n\n/**\n * Text component props with asChild support for slot composition\n * Enables Text components to be used with the Slot pattern\n */\ntype SlottableTextProps = ComponentPropsWithAsChild;\n\n/**\n * Interface for components that can be force mounted even when normally hidden\n */\ninterface ForceMountable {\n /**\n * Whether to force mount the component in the DOM\n * Useful for animation purposes when component needs to be present but hidden\n */\n forceMount?: true | undefined;\n}\n\n/**\n * Interface for defining spacing/padding from screen edges\n */\ninterface Insets {\n /**\n * Distance from the top edge in pixels\n */\n top?: number;\n /**\n * Distance from the bottom edge in pixels\n */\n bottom?: number;\n /**\n * Distance from the left edge in pixels\n */\n left?: number;\n /**\n * Distance from the right edge in pixels\n */\n right?: number;\n}\n\n/**\n * Props for components that need to be positioned relative to a trigger element\n * Certain props are only available on the native version of the component.\n * @docs For the web version, see the Radix documentation https://www.radix-ui.com/primitives\n */\ninterface PositionedContentProps {\n /**\n * Whether to force mount the component in the DOM\n */\n forceMount?: true | undefined;\n /**\n * Custom styles to apply to the positioned content\n */\n style?: ViewStyle;\n /**\n * Offset along the alignment axis in pixels\n */\n alignOffset?: number;\n /**\n * Screen edge insets to respect when positioning\n */\n insets?: Insets;\n /**\n * Whether to automatically adjust position to avoid screen edges\n * @default true\n */\n avoidCollisions?: boolean;\n /**\n * Alignment relative to the trigger element\n * @default 'start'\n */\n align?: \"start\" | \"center\" | \"end\";\n /**\n * Preferred placement of the trigger element to position against\n * @default 'bottom'\n */\n placement?: \"top\" | \"bottom\" | \"left\" | \"right\";\n /**\n * Offset from the trigger element in pixels\n * @default 0\n */\n offset?: number;\n /**\n * Whether to disable the automatic positioning styles\n * Useful when you want to handle positioning manually\n * @default false\n */\n disablePositioningStyle?: boolean;\n}\n\nexport type {\n ComponentPropsWithAsChild,\n ForceMountable,\n Insets,\n PositionedContentProps,\n PressableRef,\n SlottablePressableProps,\n SlottableTextProps,\n SlottableViewProps,\n TextRef,\n ViewRef,\n};\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/types/primitives.ts" }, { "path": "registry/native-ui/src/helpers/internal/types/theme.ts", "content": "import type { ClassValue } from \"tailwind-variants\";\n\n/**\n * This Typescript utility transform a list of slots into a list of {slot: classes}\n */\ntype ElementSlots = {\n [key in S]?: Exclude;\n};\n\n/**\n * Type helper that preserves the exact type of combined style objects\n * This ensures that VariantProps inference works correctly for each style\n */\ntype CombinedStyles> = {\n [K in keyof T]: T[K];\n};\n\nexport type { CombinedStyles, ElementSlots };\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/types/theme.ts" }, { "path": "registry/native-ui/src/helpers/internal/utils/animation.ts", "content": "import type { Animation, AnimationRoot, AnimationValue } from \"../types/animation\";\n\n/**\n * Check if the entire animation is disabled\n * @param animation - Animation configuration\n * @returns true if animation is disabled\n */\nexport function isAnimationDisabled>(\n animation: Animation | AnimationRoot | undefined,\n): boolean {\n // Check top-level disabled values\n if (animation === false || animation === \"disabled\") {\n return true;\n }\n\n // Check state property in config objects\n if (typeof animation === \"object\" && animation !== null && \"state\" in animation) {\n const state = animation.state;\n return state === false || state === \"disabled\";\n }\n\n return false;\n}\n\n/**\n * Check if root animation should cascade disable to all children\n * @param animation - Root animation configuration\n * @returns true if all animations should be disabled (including children)\n */\nexport function shouldDisableAll>(\n animation: AnimationRoot | undefined,\n): boolean {\n // Check top-level disable-all value\n if (animation === \"disable-all\") {\n return true;\n }\n\n // Check state property in config objects\n if (typeof animation === \"object\" && animation !== null && \"state\" in animation) {\n const state = animation.state;\n return state === \"disable-all\";\n }\n\n return false;\n}\n\n/**\n * Get animation state including config and disabled status\n * @param animation - Animation configuration\n * @returns Object with animationConfig and isAnimationDisabled\n */\nexport function getAnimationState>(\n animation: Animation | undefined,\n): {\n animationConfig: TConfig | undefined;\n isAnimationDisabled: boolean;\n} {\n const isDisabled = isAnimationDisabled(animation);\n // Always extract config when it's an object, regardless of disabled state\n // This allows users to customize colors/properties even when animations are disabled\n const config =\n typeof animation === \"object\" && animation !== null ? (animation as TConfig) : undefined;\n\n return {\n animationConfig: config,\n isAnimationDisabled: isDisabled,\n };\n}\n\n/**\n * Get root animation state including config, disabled status, and cascade flag\n * @param animation - Root animation configuration\n * @returns Object with animationConfig, isAnimationDisabled, and isAllAnimationsDisabled\n */\nexport function getRootAnimationState>(\n animation: AnimationRoot | undefined,\n): {\n animationConfig: TConfig | undefined;\n isAnimationDisabled: boolean;\n isAllAnimationsDisabled: boolean;\n} {\n const shouldCascade = shouldDisableAll(animation);\n const isDisabled = isAnimationDisabled(animation) || shouldCascade;\n // Always extract config when it's an object, regardless of disabled state\n // This allows users to customize colors/properties even when animations are disabled\n const config =\n typeof animation === \"object\" && animation !== null ? (animation as TConfig) : undefined;\n\n return {\n animationConfig: config,\n isAnimationDisabled: isDisabled,\n isAllAnimationsDisabled: shouldCascade,\n };\n}\n\n/**\n * Get animation value property or return default\n * Extracts a property from the animation value config object\n *\n * @param options - Object containing animationValue, property, and defaultValue\n * @param options.animationValue - The animation value configuration\n * @param options.property - Property name to extract\n * @param options.defaultValue - Default value if property is not found\n * @returns The property value or default (never undefined)\n *\n * @example\n * const scaleValue = getAnimationValueProperty({\n * animationValue: animation?.scale,\n * property: 'value',\n * defaultValue: 0.95\n * });\n */\nexport function getAnimationValueProperty<\n TConfig extends Record,\n K extends keyof TConfig,\n D extends NonNullable,\n>(options: {\n animationValue: AnimationValue | undefined;\n property: K;\n defaultValue: D;\n}): NonNullable {\n // If animation value is undefined, return default\n if (options.animationValue === undefined) {\n return options.defaultValue;\n }\n\n // Return the property value if it exists, otherwise return default\n return (options.animationValue[options.property] ?? options.defaultValue) as NonNullable<\n TConfig[K]\n >;\n}\n\n/**\n * Get animation value merged config or return default\n * Merges the animation value config with defaults, useful when you need multiple properties\n *\n * @param options - Object containing animationValue, property, and defaultValue\n * @param options.animationValue - The animation value configuration\n * @param options.property - Property name to extract from the config\n * @param options.defaultValue - Default configuration object\n * @returns The merged config object or default\n *\n * @example\n * const scaleConfig = getAnimationValueMergedConfig({\n * animationValue: animation?.scale,\n * property: 'timingConfig',\n * defaultValue: { duration: 150 }\n * });\n */\nexport function getAnimationValueMergedConfig<\n TConfig extends Record,\n K extends keyof TConfig,\n>(options: {\n animationValue: AnimationValue | undefined;\n property: K;\n defaultValue: TConfig[K];\n}): TConfig[K] {\n // If animation value is undefined, return default\n if (options.animationValue === undefined) {\n return options.defaultValue;\n }\n\n const value = options.animationValue[options.property];\n\n // If the specific property value is undefined or not an object, return default\n if (value === undefined || typeof value !== \"object\") {\n return options.defaultValue;\n }\n\n // Merge with defaults to ensure all properties exist\n return { ...options.defaultValue, ...value };\n}\n\n/**\n * Determine if animations should be disabled based on disabled flags\n * Priority: isAllAnimationsDisabled > isAnimationDisabled\n *\n * @param options - Object containing isAnimationDisabled and isAllAnimationsDisabled\n * @param options.isAnimationDisabled - Whether animation is explicitly disabled\n * @param options.isAllAnimationsDisabled - Whether all animations should be disabled (cascading from root/global)\n * @returns true if animations should be disabled, false otherwise\n *\n * @example\n * const isDisabled = getIsAnimationDisabledValue({\n * isAnimationDisabled: false,\n * isAllAnimationsDisabled: true\n * });\n * // Returns: true (all animations disabled takes priority)\n */\nexport function getIsAnimationDisabledValue(options: {\n isAnimationDisabled: boolean;\n isAllAnimationsDisabled: boolean | undefined;\n}): boolean {\n const { isAnimationDisabled: isDisabled, isAllAnimationsDisabled } = options;\n\n // First priority: if all animations are disabled, return true\n if (isAllAnimationsDisabled === true) {\n return true;\n }\n\n // Second priority: if this animation is disabled, return true\n if (isDisabled) {\n return true;\n }\n\n // Default: animations are enabled\n return false;\n}\n\n/**\n * Combine global, parent, and own animation disabled states\n * Priority: Global > Parent > Own (global wins if enabled)\n *\n * @param options - Object containing globalIsAllAnimationsDisabled, parentIsAllAnimationsDisabled, and ownIsAllAnimationsDisabled\n * @param options.globalIsAllAnimationsDisabled - Whether global provider has disable-all (from GlobalAnimationSettingsProvider)\n * @param options.parentIsAllAnimationsDisabled - Whether parent context has disable-all (from AnimationSettingsContext)\n * @param options.ownIsAllAnimationsDisabled - Whether own animation prop has disable-all\n * @returns Combined isAllAnimationsDisabled value (global || parent || own)\n *\n * @example\n * const combined = getCombinedAnimationDisabledState({\n * globalIsAllAnimationsDisabled: true,\n * parentIsAllAnimationsDisabled: false,\n * ownIsAllAnimationsDisabled: false\n * });\n * // Returns: true (global wins)\n */\nexport function getCombinedAnimationDisabledState(options: {\n globalIsAllAnimationsDisabled?: boolean;\n parentIsAllAnimationsDisabled: boolean | undefined;\n ownIsAllAnimationsDisabled: boolean;\n}): boolean {\n const {\n globalIsAllAnimationsDisabled,\n parentIsAllAnimationsDisabled,\n ownIsAllAnimationsDisabled,\n } = options;\n\n // Global always wins if it has disable-all\n if (globalIsAllAnimationsDisabled === true) {\n return true;\n }\n\n // Parent wins if it has disable-all\n if (parentIsAllAnimationsDisabled === true) {\n return true;\n }\n\n // Otherwise use own value\n return ownIsAllAnimationsDisabled;\n}\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/utils/animation.ts" }, { "path": "registry/native-ui/src/helpers/internal/utils/children-to-string.ts", "content": "import { Children, isValidElement, type ReactNode } from \"react\";\nimport type { SharedValue } from \"react-native-reanimated\";\n\n/**\n * Recursively checks if children contain any React elements.\n * Used to determine if children can be stringified.\n *\n * @param children - React children to check\n * @returns True if children contain React elements, false otherwise\n */\nfunction hasReactElements(children: ReactNode): boolean {\n if (children == null || typeof children === \"boolean\") {\n return false;\n }\n\n if (isValidElement(children)) {\n return true;\n }\n\n if (Array.isArray(children)) {\n return children.some((child) => hasReactElements(child));\n }\n\n return false;\n}\n\n/**\n * Converts React children to a string representation.\n * Handles cases where children might be an array of mixed types (strings, numbers, variables).\n *\n * @param children - React children that might be string, number, array, or React elements\n * @returns A string representation of the children or null if not convertible\n */\nexport function childrenToString(children: ReactNode | SharedValue): string | null {\n // Handle null/undefined\n if (children == null) {\n return null;\n }\n\n // Handle string directly\n if (typeof children === \"string\") {\n return children;\n }\n\n // Handle number\n if (typeof children === \"number\") {\n return String(children);\n }\n\n // Handle boolean (usually we don't want to render true/false as text)\n if (typeof children === \"boolean\") {\n return null;\n }\n\n // Check if children is a React element - if so, cannot be stringified\n if (isValidElement(children)) {\n return null;\n }\n\n // Handle array of children (e.g., {someVar} text)\n if (Array.isArray(children)) {\n // Check if array contains any React elements - if so, cannot be stringified\n // This handles cases where conditional children create arrays with React elements\n if (hasReactElements(children)) {\n return null;\n }\n\n const stringified = children\n .map((child) => {\n // Recursively handle each child\n if (typeof child === \"string\" || typeof child === \"number\") {\n return String(child);\n }\n // Skip booleans, null, undefined\n if (child == null || typeof child === \"boolean\") {\n return \"\";\n }\n // Recursively process nested arrays (only if they don't contain React elements)\n if (Array.isArray(child)) {\n const nested = childrenToString(child);\n return nested ?? \"\";\n }\n return String(child);\n })\n .join(\"\");\n\n return stringified || null;\n }\n\n // Handle React fragments and other iterable children\n try {\n const childArray = Children.toArray(children as ReactNode);\n if (childArray.length > 0) {\n // Check if any children are React elements\n if (hasReactElements(childArray)) {\n return null;\n }\n return childrenToString(childArray);\n }\n } catch {\n // Not iterable or other error, return null\n }\n\n return null;\n}\n\n/**\n * Checks if React children can be converted to a string.\n *\n * @param children - React children to check\n * @returns True if children can be converted to string, false otherwise\n */\nexport function isStringifiableChildren(children: ReactNode): boolean {\n return childrenToString(children) !== null;\n}\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/utils/children-to-string.ts" }, { "path": "registry/native-ui/src/helpers/internal/utils/combine-styles.ts", "content": "import type { CombinedStyles } from \"../types\";\n\n/**\n * Helper function to combine style objects with proper type inference\n * This preserves the exact types of each style object, including VariantProps\n * @example\n * const styles = combineStyles({\n * root,\n * item,\n * content\n * });\n */\nexport function combineStyles>(styles: T): CombinedStyles {\n return styles as CombinedStyles;\n}\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/utils/combine-styles.ts" }, { "path": "registry/native-ui/src/helpers/internal/utils/create-context.ts", "content": "import * as React from \"react\";\n\nexport interface CreateContextOptions {\n /**\n * If `true`, React will throw if context is `null` or `undefined`\n * In some cases, you might want to support nested context, so you can set it to `false`\n */\n strict?: boolean;\n /**\n * Error message to throw if the context is `undefined`\n */\n errorMessage?: string;\n /**\n * The display name of the context\n */\n name?: string;\n}\n\nexport type CreateContextReturn = [React.Provider, () => T, React.Context];\n\n/**\n * Creates a named context, provider, and hook.\n *\n * @param options create context options\n */\nexport function createContext(options: CreateContextOptions = {}) {\n const {\n strict = true,\n errorMessage = \"useContext: `context` is undefined. Seems you forgot to wrap component within the Provider\",\n name,\n } = options;\n\n const Context = React.createContext(undefined);\n\n Context.displayName = name;\n\n function useContext() {\n const context = React.useContext(Context);\n\n if (!context && strict) {\n const error = new Error(errorMessage);\n\n error.name = \"ContextError\";\n (\n Error as ErrorConstructor & {\n captureStackTrace?: (\n targetObject: object,\n constructorOpt?: (...args: unknown[]) => unknown,\n ) => void;\n }\n ).captureStackTrace?.(error, useContext);\n throw error;\n }\n\n return context;\n }\n\n return [Context.Provider, useContext, Context] as CreateContextReturn;\n}\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/utils/create-context.ts" }, { "path": "registry/native-ui/src/helpers/internal/utils/ease-gradient/create-interpolation.ts", "content": "/**\n * Easing gradient utilities for React Native\n *\n * Original source: https://github.com/phamfoo/react-native-easing-gradient\n * Author: @phamfoo\n * License: MIT\n *\n * This code has been adapted for use in PitsiUI Native with modifications\n * for TypeScript compatibility and integration with the animation system.\n */\n\nimport { Animated } from \"react-native\";\n\n// @ts-expect-error\nconst AnimatedInterpolation = Animated.Interpolation;\n\ntype ColorInterpolateFunction = (input: number) => string;\n\nfunction createInterpolation(config: Animated.InterpolationConfigType): ColorInterpolateFunction {\n if (AnimatedInterpolation.__createInterpolation) {\n return AnimatedInterpolation.__createInterpolation(config);\n }\n\n return (input) => {\n const interpolation = new AnimatedInterpolation({ __getValue: () => input }, config);\n\n return interpolation.__getValue();\n };\n}\n\nexport { createInterpolation };\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/utils/ease-gradient/create-interpolation.ts" }, { "path": "registry/native-ui/src/helpers/internal/utils/ease-gradient/index.ts", "content": "/**\n * Easing gradient utilities for React Native\n *\n * Original source: https://github.com/phamfoo/react-native-easing-gradient\n * Author: @phamfoo\n * License: MIT\n *\n * This code has been adapted for use in PitsiUI Native with modifications\n * for TypeScript compatibility and integration with the animation system.\n */\n\nimport { Easing, type EasingFunction } from \"react-native\";\nimport { createInterpolation } from \"./create-interpolation\";\n\ninterface ColorStops {\n [location: number]: {\n color: string;\n easing?: EasingFunction;\n };\n}\n\ninterface GradientParams {\n colorStops: ColorStops;\n extraColorStopsPerTransition?: number;\n easing?: EasingFunction;\n}\n\nconst easeInOut = Easing.bezier(0.42, 0, 0.58, 1);\n\nfunction easeGradient({\n colorStops,\n easing = easeInOut,\n extraColorStopsPerTransition = 12,\n}: GradientParams): {\n colors: [string, string, ...string[]];\n locations: [number, number, ...number[]];\n} {\n const colors: string[] = [];\n const locations: number[] = [];\n\n const initialLocations = Object.keys(colorStops)\n .map((key) => Number(key))\n .sort();\n\n const totalColorStops = initialLocations.length;\n\n for (let currentStopIndex = 0; currentStopIndex < totalColorStops - 1; currentStopIndex++) {\n const startLocation = initialLocations[currentStopIndex];\n const endLocation = initialLocations[currentStopIndex + 1];\n\n if (startLocation === undefined || endLocation === undefined) {\n continue;\n }\n\n const startStop = colorStops[startLocation];\n const endStop = colorStops[endLocation];\n\n if (!startStop || !endStop) {\n continue;\n }\n\n const startColor = startStop.color;\n const endColor = endStop.color;\n const currentEasing = startStop.easing ?? easing;\n\n const colorScale = createInterpolation({\n inputRange: [0, 1],\n outputRange: [startColor, endColor],\n easing: currentEasing,\n });\n\n const currentTransitionLength = endLocation - startLocation;\n const stepSize = 1 / (extraColorStopsPerTransition + 1);\n\n for (let stepIndex = 0; stepIndex <= extraColorStopsPerTransition + 1; stepIndex++) {\n const progress = stepIndex * stepSize;\n const color = colorScale(progress);\n colors.push(color);\n locations.push(startLocation + currentTransitionLength * progress);\n }\n }\n\n return {\n colors: colors as [string, string, ...string[]],\n locations: locations as [number, number, ...number[]],\n };\n}\n\nexport { easeGradient };\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/utils/ease-gradient/index.ts" }, { "path": "registry/native-ui/src/helpers/internal/utils/get-element-by-display-name.ts", "content": "import React from \"react\";\nimport type { ReactChild } from \"../types\";\n\nexport const getElementByDisplayName = (\n children: React.ReactNode,\n displayName: string,\n): ReactChild | undefined => {\n const element = React.Children.toArray(children).find(\n (child) => React.isValidElement(child) && (child.type as any)?.displayName === displayName,\n );\n\n return element;\n};\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/utils/get-element-by-display-name.ts" }, { "path": "registry/native-ui/src/helpers/internal/utils/get-element-with-default.ts", "content": "import type React from \"react\";\nimport type { ReactChild } from \"../types\";\nimport { getElementByDisplayName } from \"./get-element-by-display-name\";\n\nexport const getElementWithDefault = (\n children: React.ReactNode,\n displayName: string,\n defaultElement: React.ReactElement,\n): ReactChild => {\n const element = getElementByDisplayName(children, displayName);\n\n if (!element) {\n return defaultElement;\n }\n\n return element;\n};\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/utils/get-element-with-default.ts" }, { "path": "registry/native-ui/src/helpers/internal/utils/has-prop.ts", "content": "import type { ReactElement } from \"react\";\n\n/**\n * Checks if a React element has a specific prop defined\n * @param element - The React element to check\n * @param propName - The name of the prop to check for\n * @returns true if the element has the prop, false otherwise\n */\nexport function hasProp(element: ReactElement | null | undefined, propName: string): boolean {\n if (!element?.props || typeof element.props !== \"object\") {\n return false;\n }\n\n return propName in element.props;\n}\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/utils/has-prop.ts" }, { "path": "registry/native-ui/src/helpers/internal/utils/index.ts", "content": "export * from \".//animation\";\nexport * from \"./children-to-string\";\nexport * from \"./combine-styles\";\nexport * from \"./create-context\";\nexport * from \"./ease-gradient\";\nexport * from \"./get-element-by-display-name\";\nexport * from \"./get-element-with-default\";\nexport * from \"./has-prop\";\n", "type": "registry:lib", "target": "@components/pitsi-ui/native-ui/src/helpers/internal/utils/index.ts" }, { "path": "registry/native-ui/src/optional/gorhom-bottom-sheet.ts", "content": "let GorhomBottomSheetPackage: any;\n\ntry {\n GorhomBottomSheetPackage = require(\"@gorhom/bottom-sheet\");\n} catch (_error) {\n /* @gorhom/bottom-sheet is an optional peer dependency */\n}\n\nexport default GorhomBottomSheetPackage;\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/optional/gorhom-bottom-sheet.ts" }, { "path": "registry/native-ui/src/primitives/slot/index.ts", "content": "export * from \"./slot\";\nexport type * from \"./slot.types\";\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/primitives/slot/index.ts" }, { "path": "registry/native-ui/src/primitives/slot/slot.tsx", "content": "import { type ComponentRef, cloneElement, forwardRef, isValidElement } from \"react\";\nimport type {\n Image as RNImage,\n Pressable as RNPressable,\n PressableProps as RNPressableProps,\n Text as RNText,\n TextProps as RNTextProps,\n View as RNView,\n ViewProps as RNViewProps,\n} from \"react-native\";\nimport type { AnyProps, ImageSlotProps } from \"./slot.types\";\nimport { composeRefs, mergeProps } from \"./utils\";\n\n// --------------------------------------------------\n\nconst Pressable = forwardRef, RNPressableProps>(\n (props, forwardedRef) => {\n const { children, ...pressableSlotProps } = props;\n\n if (!isValidElement(children)) {\n console.log(\"Slot.Pressable - Invalid asChild element\", children);\n return null;\n }\n\n const child = children as React.ReactElement;\n\n return cloneElement(child, {\n ...mergeProps(pressableSlotProps, children.props as AnyProps),\n ref: forwardedRef ? composeRefs(forwardedRef, (children as any).ref) : (children as any).ref,\n });\n },\n);\n\nPressable.displayName = \"PitsiUINative.Primitive.Slot.Pressable\";\n\n// --------------------------------------------------\n\nconst View = forwardRef, RNViewProps>((props, forwardedRef) => {\n const { children, ...viewSlotProps } = props;\n\n if (!isValidElement(children)) {\n console.log(\"Slot.View - Invalid asChild element\", children);\n return null;\n }\n\n const child = children as React.ReactElement;\n\n return cloneElement(child, {\n ...mergeProps(viewSlotProps, children.props as AnyProps),\n ref: forwardedRef ? composeRefs(forwardedRef, (children as any).ref) : (children as any).ref,\n });\n});\n\nView.displayName = \"PitsiUINative.Primitive.Slot.View\";\n\n// --------------------------------------------------\n\nconst Text = forwardRef, RNTextProps>((props, forwardedRef) => {\n const { children, ...textSlotProps } = props;\n\n if (!isValidElement(children)) {\n console.log(\"Slot.Text - Invalid asChild element\", children);\n return null;\n }\n\n const child = children as React.ReactElement;\n\n return cloneElement(child, {\n ...mergeProps(textSlotProps, children.props as AnyProps),\n ref: forwardedRef ? composeRefs(forwardedRef, (children as any).ref) : (children as any).ref,\n });\n});\n\nText.displayName = \"PitsiUINative.Primitive.Slot.Text\";\n\n// --------------------------------------------------\n\nconst Image = forwardRef, ImageSlotProps>((props, forwardedRef) => {\n const { children, ...imageSlotProps } = props;\n\n if (!isValidElement(children)) {\n console.log(\"Slot.Image - Invalid asChild element\", children);\n return null;\n }\n\n const child = children as React.ReactElement;\n\n return cloneElement(child, {\n ...mergeProps(imageSlotProps, children.props as AnyProps),\n ref: forwardedRef ? composeRefs(forwardedRef, (children as any).ref) : (children as any).ref,\n });\n});\n\nImage.displayName = \"PitsiUINative.Primitive.Slot.Image\";\n\nexport { Image, Pressable, Text, View };\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/primitives/slot/slot.tsx" }, { "path": "registry/native-ui/src/primitives/slot/utils.ts", "content": "import type { PressableStateCallbackType } from \"react-native\";\nimport type { AnyProps, Style } from \"./slot.types\";\n\n// --------------------------------------------------\n\nexport function isTextChildren(\n children: React.ReactNode | ((state: PressableStateCallbackType) => React.ReactNode),\n) {\n return Array.isArray(children)\n ? children.every((child) => typeof child === \"string\")\n : typeof children === \"string\";\n}\n\n// --------------------------------------------------\n\nexport function composeRefs(...refs: (React.Ref | undefined)[]) {\n return (node: T) =>\n refs.forEach((ref) => {\n if (typeof ref === \"function\") {\n ref(node);\n } else if (ref != null) {\n (ref as React.MutableRefObject).current = node;\n }\n });\n}\n\n// --------------------------------------------------\n\nexport function mergeProps(slotProps: AnyProps, childProps: AnyProps) {\n // all child props should override\n const overrideProps = { ...childProps };\n\n for (const propName in childProps) {\n const slotPropValue = slotProps[propName];\n const childPropValue = childProps[propName];\n\n const isHandler = /^on[A-Z]/.test(propName);\n if (isHandler) {\n // if the handler exists on both, we compose them\n if (slotPropValue && childPropValue) {\n overrideProps[propName] = (...args: unknown[]) => {\n childPropValue(...args);\n slotPropValue(...args);\n };\n }\n // but if it exists only on the slot, we use only this one\n else if (slotPropValue) {\n overrideProps[propName] = slotPropValue;\n }\n }\n // if it's `style`, we merge them\n else if (propName === \"style\") {\n overrideProps[propName] = combineStyles(slotPropValue, childPropValue);\n } else if (propName === \"className\") {\n overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(\" \");\n }\n }\n\n return { ...slotProps, ...overrideProps };\n}\n\n// --------------------------------------------------\n\n/**\n * Combines slot and child styles into a style array.\n *\n * Returns a style array instead of flattening via StyleSheet.flatten,\n * because flatten deep-copies style objects into plain objects, which\n * destroys Reanimated animated style bindings (useAnimatedStyle / SharedValues).\n * React Native natively handles nested style arrays, so an array is safe here.\n */\nfunction combineStyles(slotStyle?: Style, childValue?: Style) {\n if (typeof slotStyle === \"function\" && typeof childValue === \"function\") {\n return (state: PressableStateCallbackType) => {\n return [slotStyle(state), childValue(state)];\n };\n }\n if (typeof slotStyle === \"function\") {\n return (state: PressableStateCallbackType) => {\n return childValue ? [slotStyle(state), childValue] : slotStyle(state);\n };\n }\n if (typeof childValue === \"function\") {\n return (state: PressableStateCallbackType) => {\n return slotStyle ? [slotStyle, childValue(state)] : childValue(state);\n };\n }\n\n if (!slotStyle) return childValue;\n if (!childValue) return slotStyle;\n return [slotStyle, childValue];\n}\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/primitives/slot/utils.ts" }, { "path": "registry/native-ui/src/providers/animation-settings/index.ts", "content": "export {\n default as GlobalAnimationSettingsProvider,\n useGlobalAnimationSettings,\n} from \"./provider\";\nexport type {\n GlobalAnimationSettingsContextValue,\n GlobalAnimationSettingsProviderProps,\n} from \"./types\";\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/providers/animation-settings/index.ts" }, { "path": "registry/native-ui/src/providers/animation-settings/provider.tsx", "content": "import type React from \"react\";\nimport { useReducedMotion } from \"react-native-reanimated\";\nimport { createContext } from \"../../helpers/internal/utils\";\nimport type {\n GlobalAnimationSettingsContextValue,\n GlobalAnimationSettingsProviderProps,\n} from \"./types\";\n\nconst [GlobalAnimationSettingsProvider, useGlobalAnimationSettings] =\n createContext({\n name: \"GlobalAnimationSettingsContext\",\n strict: false,\n });\n\nexport { useGlobalAnimationSettings };\n\n/**\n * GlobalAnimationSettingsProvider Component\n *\n * @description\n * Provider component that controls global animation settings across the application.\n * When animation is set to 'disable-all', all animations will be disabled globally.\n * Additionally, if the user has enabled reduce motion in accessibility settings,\n * all animations will be disabled automatically.\n *\n * This provider wraps AnimationSettingsProvider to cascade the global setting\n * down through the component tree.\n *\n * @param {GlobalAnimationSettingsProviderProps} props - Provider props\n * @param {AnimationRootDisableAll} [props.animation] - Global animation setting\n * @param {ReactNode} props.children - Child components to wrap\n */\nexport const GlobalAnimationSettingsProviderComponent: React.FC<\n GlobalAnimationSettingsProviderProps\n> = ({ animation, children }) => {\n const reducedMotion = useReducedMotion();\n const globalIsAllAnimationsDisabled = animation === \"disable-all\" || reducedMotion;\n\n return (\n \n {children}\n \n );\n};\n\nexport default GlobalAnimationSettingsProviderComponent;\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/providers/animation-settings/provider.tsx" }, { "path": "registry/native-ui/src/providers/animation-settings/types.ts", "content": "import type { ReactNode } from \"react\";\nimport type { AnimationRootDisableAll } from \"../../helpers/internal/types/animation\";\n\n/**\n * Props for GlobalAnimationSettingsProvider component\n */\nexport interface GlobalAnimationSettingsProviderProps {\n /**\n * Global animation setting\n * When set to 'disable-all', all animations across the app will be disabled\n */\n animation?: AnimationRootDisableAll;\n /**\n * Child components to render within the provider\n */\n children: ReactNode;\n}\n\n/**\n * Context value for global animation settings\n */\nexport interface GlobalAnimationSettingsContextValue {\n /**\n * Whether all animations should be disabled globally\n */\n globalIsAllAnimationsDisabled: boolean;\n}\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/providers/animation-settings/types.ts" }, { "path": "registry/native-ui/src/providers/text-component/index.ts", "content": "export * from \"./provider\";\nexport * from \"./types\";\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/providers/text-component/index.ts" }, { "path": "registry/native-ui/src/providers/text-component/provider.tsx", "content": "import { createContext } from \"../../helpers/internal/utils\";\nimport type { TextComponentContextValue } from \"./types\";\n\nconst [TextComponentProvider, useTextComponent] = createContext({\n name: \"TextComponentContext\",\n});\n\nexport { TextComponentProvider, useTextComponent };\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/providers/text-component/provider.tsx" }, { "path": "registry/native-ui/src/providers/text-component/types.ts", "content": "import type { TextProps } from \"react-native\";\n\n/**\n * Global text component configuration props.\n * These props are carefully selected to include only those that make sense\n * to configure globally across all Text components in the application.\n *\n * @description\n * Includes accessibility and font scaling settings that typically\n * should be consistent throughout the app for better UX.\n */\nexport type TextComponentProps = {\n /**\n * Specifies whether fonts should be scaled down automatically to fit given style constraints.\n *\n * @default false\n */\n adjustsFontSizeToFit?: TextProps[\"adjustsFontSizeToFit\"];\n /**\n * Specifies whether fonts should scale to respect Text Size accessibility settings.\n *\n * @default true\n */\n allowFontScaling?: TextProps[\"allowFontScaling\"];\n /**\n * Specifies the largest possible scale a font can reach when `allowFontScaling` is enabled.\n *\n * Possible values:\n *\n * - `null` or `undefined`: inherit from the parent node or the global default (0)\n * - `0`: no max, ignore parent/global default\n * - `>= 1`: sets the `maxFontSizeMultiplier` of this node to this value\n *\n * @default `undefined`\n */\n maxFontSizeMultiplier?: TextProps[\"maxFontSizeMultiplier\"];\n /**\n * Specifies the smallest possible scale a font can reach when adjustsFontSizeToFit is enabled. (values 0.01-1.0).\n *\n * iOS only\n *\n * @default `undefined`\n */\n minimumFontScale?: TextProps[\"minimumFontScale\"];\n};\n\n/**\n * Context value for text component configuration\n */\nexport interface TextComponentContextValue {\n textProps?: TextComponentProps;\n}\n", "type": "registry:ui", "target": "@components/pitsi-ui/native-ui/src/providers/text-component/types.ts" } ], "categories": [ "native", "react-native", "ui" ], "meta": { "package": "@pitsi-ui/native", "packageSlug": "native-ui", "platform": "native" } }