@kushagradhawan/kookie-ui 0.1.30 → 0.1.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- "use strict";var U=Object.create;var l=Object.defineProperty;var V=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var Y=Object.getPrototypeOf,Z=Object.prototype.hasOwnProperty;var _=(o,t)=>{for(var r in t)l(o,r,{get:t[r],enumerable:!0})},D=(o,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of X(t))!Z.call(o,i)&&i!==r&&l(o,i,{get:()=>t[i],enumerable:!(s=V(t,i))||s.enumerable});return o};var C=(o,t,r)=>(r=o!=null?U(Y(o)):{},D(t||!o||!o.__esModule?l(r,"default",{value:o,enumerable:!0}):r,o)),$=o=>D(l({},"__esModule",{value:!0}),o);var ee={};_(ee,{Image:()=>y});module.exports=$(ee);var e=C(require("react")),h=C(require("classnames")),N=require("./image.props.js"),H=require("../helpers/extract-props.js"),k=require("../props/margin.props.js"),M=require("../props/width.props.js"),T=require("../props/height.props.js"),j=require("../props/layout.props.js"),W=require("./skeleton.js"),z=require("./slot.js");const y=e.forwardRef((o,t)=>{const{asChild:r,className:s,style:i,loading:O="lazy",alt:u,src:p,placeholder:m,showSkeleton:R=!1,fadeIn:P=!0,errorAriaLabel:q="Failed to load image",radius:G,caption:n,onLoad:I,onError:v,children:A,...E}=(0,H.extractProps)(o,N.imagePropDefs,k.marginPropDefs,M.widthPropDefs,T.heightPropDefs,j.layoutPropDefs),[d,c]=e.useState("loading"),[F,g]=e.useState(!!m),S=e.useRef(null),B=e.useCallback(a=>{c("loaded"),g(!1),I?.(a)},[I]),J=e.useCallback(a=>{c("error"),g(!1),v?.(a)},[v]);if(e.useEffect(()=>{const a=S.current;a&&a.complete&&a.naturalWidth>0&&(c("loaded"),g(!1))},[p]),!p)return console.warn("Image component: src prop is required"),null;!r&&u===void 0&&console.warn("Image component: alt prop is required for accessibility when not using asChild");const L=d==="loading",f=d==="error",K=d==="loaded",Q={"aria-busy":L,"aria-invalid":f,"aria-describedby":f?"image-error":void 0},b={width:"100%",height:"100%",display:"block",opacity:P?K?1:0:1,transition:P?"opacity 0.3s ease-out":"none"},w=e.createElement(e.Fragment,null,e.createElement("div",{style:{position:"relative",flex:n?"1 1 0%":void 0,height:n?void 0:"100%",minHeight:0}},f&&e.createElement("div",{id:"image-error",className:"rt-sr-only","aria-live":"polite"},q),R&&L&&e.createElement(W.Skeleton,{width:"100%",height:"100%",style:{position:"absolute",inset:0}}),m&&F&&e.createElement("img",{style:{...b,position:"absolute",inset:0,filter:"blur(4px)",opacity:.7,zIndex:0},className:(0,h.default)("rt-reset","rt-Image","rt-Image--placeholder"),alt:"",src:m}),e.createElement("img",{ref:a=>{S.current=a,typeof t=="function"?t(a):t&&(t.current=a)},loading:O,style:{...b,position:"relative",zIndex:1},className:(0,h.default)("rt-reset","rt-Image",s),alt:u,src:p,"data-radius":G,onLoad:B,onError:J,...Q})),n&&e.createElement("div",{className:"rt-Image-caption",style:{flex:"0 0 auto"}},n)),x={display:n?"flex":"block",flexDirection:n?"column":void 0,...i};return r?e.createElement(z.Slot,{className:s,style:x,...E},e.cloneElement(A,{},w)):e.createElement("div",{className:s,style:x,...E},w)});y.displayName="Image";
1
+ "use strict";var U=Object.create;var l=Object.defineProperty;var V=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var Y=Object.getPrototypeOf,Z=Object.prototype.hasOwnProperty;var _=(o,t)=>{for(var r in t)l(o,r,{get:t[r],enumerable:!0})},D=(o,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of X(t))!Z.call(o,i)&&i!==r&&l(o,i,{get:()=>t[i],enumerable:!(s=V(t,i))||s.enumerable});return o};var C=(o,t,r)=>(r=o!=null?U(Y(o)):{},D(t||!o||!o.__esModule?l(r,"default",{value:o,enumerable:!0}):r,o)),$=o=>D(l({},"__esModule",{value:!0}),o);var ee={};_(ee,{Image:()=>y});module.exports=$(ee);var e=C(require("react")),h=C(require("classnames")),N=require("./image.props.js"),H=require("../helpers/extract-props.js"),k=require("../props/margin.props.js"),M=require("../props/width.props.js"),T=require("../props/height.props.js"),j=require("../props/layout.props.js"),W=require("./skeleton.js"),z=require("./slot.js");const y=e.forwardRef((o,t)=>{const{asChild:r,className:s,style:i,loading:O="lazy",alt:u,src:p,placeholder:m,showSkeleton:R=!1,fadeIn:P=!0,loadingAriaLabel:oe,errorAriaLabel:q="Failed to load image",radius:A,caption:n,onLoad:I,onError:v,children:G,...E}=(0,H.extractProps)(o,N.imagePropDefs,k.marginPropDefs,M.widthPropDefs,T.heightPropDefs,j.layoutPropDefs),[d,c]=e.useState("loading"),[F,g]=e.useState(!!m),S=e.useRef(null),B=e.useCallback(a=>{c("loaded"),g(!1),I?.(a)},[I]),J=e.useCallback(a=>{c("error"),g(!1),v?.(a)},[v]);if(e.useEffect(()=>{const a=S.current;a&&a.complete&&a.naturalWidth>0&&(c("loaded"),g(!1))},[p]),!p)return console.warn("Image component: src prop is required"),null;!r&&u===void 0&&console.warn("Image component: alt prop is required for accessibility when not using asChild");const L=d==="loading",f=d==="error",K=d==="loaded",Q={"aria-busy":L,"aria-invalid":f,"aria-describedby":f?"image-error":void 0},b={width:"100%",height:"100%",display:"block",opacity:P?K?1:0:1,transition:P?"opacity 0.3s ease-out":"none"},w=e.createElement(e.Fragment,null,e.createElement("div",{style:{position:"relative",flex:n?"1 1 0%":void 0,height:n?void 0:"100%",minHeight:0}},f&&e.createElement("div",{id:"image-error",className:"rt-sr-only","aria-live":"polite"},q),R&&L&&e.createElement(W.Skeleton,{width:"100%",height:"100%",style:{position:"absolute",inset:0}}),m&&F&&e.createElement("img",{style:{...b,position:"absolute",inset:0,filter:"blur(4px)",opacity:.7,zIndex:0},className:(0,h.default)("rt-reset","rt-Image","rt-Image--placeholder"),alt:"",src:m}),e.createElement("img",{ref:a=>{S.current=a,typeof t=="function"?t(a):t&&(t.current=a)},loading:O,style:{...b,position:"relative",zIndex:1},className:(0,h.default)("rt-reset","rt-Image",s),alt:u,src:p,"data-radius":A,onLoad:B,onError:J,...Q})),n&&e.createElement("div",{className:"rt-Image-caption",style:{flex:"0 0 auto"}},n)),x={display:n?"flex":"block",flexDirection:n?"column":void 0,...i};return r?e.createElement(z.Slot,{className:s,style:x,...E},e.cloneElement(G,{},w)):e.createElement("div",{className:s,style:x,...E},w)});y.displayName="Image";
2
2
  //# sourceMappingURL=image.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/image.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nimport classNames from 'classnames';\n\nimport { imagePropDefs } from './image.props.js';\nimport { extractProps } from '../helpers/extract-props.js';\nimport { marginPropDefs } from '../props/margin.props.js';\nimport { widthPropDefs } from '../props/width.props.js';\nimport { heightPropDefs } from '../props/height.props.js';\nimport { layoutPropDefs } from '../props/layout.props.js';\nimport { Skeleton } from './skeleton.js';\nimport { Slot } from './slot.js';\n\nimport type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';\nimport type { MarginProps } from '../props/margin.props.js';\nimport type { WidthProps } from '../props/width.props.js';\nimport type { HeightProps } from '../props/height.props.js';\nimport type { LayoutProps } from '../props/layout.props.js';\nimport type { GetPropDefTypes } from '../props/prop-def.js';\n\ntype ImageElement = React.ElementRef<'img'>;\n\n/**\n * Core Image props that extend the base image prop definitions\n * These props provide enhanced functionality beyond standard HTML img attributes\n */\ntype ImageOwnProps = GetPropDefTypes<typeof imagePropDefs> & {\n /**\n * Native loading behavior for the image\n * 'lazy' defers loading until the image is near the viewport\n * 'eager' loads the image immediately\n */\n loading?: 'eager' | 'lazy';\n /**\n * Placeholder image URL to show while the main image is loading\n *\n * Best practices:\n * - Use a low-quality/blurred version of the main image\n * - Keep file size small (under 10KB recommended)\n * - Use same aspect ratio as main image\n * - Consider using base64 data URLs for inline placeholders\n *\n * @example\n * ```tsx\n * <Image\n * src=\"/high-res-image.jpg\"\n * placeholder=\"/low-res-placeholder.jpg\"\n * alt=\"Product photo\"\n * />\n * ```\n */\n placeholder?: string;\n /**\n * Shows a skeleton placeholder while loading instead of a blank space\n *\n * Use this when:\n * - You don't have a placeholder image\n * - You want consistent loading states across your interface\n * - The image is part of a content layout that needs stable dimensions\n */\n showSkeleton?: boolean;\n /**\n * Whether the image should fade in when loaded\n *\n * Set to false for:\n * - Background images where immediate visibility is important\n * - Images that need to appear instantly for UX reasons\n * - When you're implementing custom loading animations\n */\n fadeIn?: boolean;\n /**\n * Callback fired when the image successfully loads\n *\n * Use this to:\n * - Track image loading performance\n * - Trigger layout adjustments after load\n * - Implement custom loading state management\n */\n onLoad?: (event: React.SyntheticEvent<HTMLImageElement>) => void;\n /**\n * Callback fired when the image fails to load\n *\n * Use this to:\n * - Log errors for monitoring\n * - Show fallback content\n * - Implement retry logic\n */\n onError?: (event: React.SyntheticEvent<HTMLImageElement>) => void;\n};\n\n/**\n * Complete Image component props interface\n *\n * Combines HTML img attributes with design system props and enhanced functionality.\n * Excludes conflicting props like 'color', 'width', 'height' that are handled by the design system.\n */\ninterface ImageProps\n extends ComponentPropsWithout<'img', RemovedProps | 'color' | 'width' | 'height' | 'alt'>,\n MarginProps,\n WidthProps,\n HeightProps,\n LayoutProps,\n ImageOwnProps {\n /**\n * Alternative text for the image\n *\n * Required for accessibility when not using asChild pattern.\n * Describes the image content for screen readers and when images fail to load.\n *\n * Guidelines:\n * - Be descriptive but concise\n * - Don't include \"image of\" or \"picture of\"\n * - Use empty string (\"\") for purely decorative images\n * - Describe the content and context, not just what you see\n *\n * @example\n * ```tsx\n * // Good alt text\n * <Image src=\"/chart.png\" alt=\"Sales increased 25% from Q1 to Q2\" />\n *\n * // Decorative image\n * <Image src=\"/decoration.png\" alt=\"\" />\n *\n * // Avoid generic descriptions\n * <Image src=\"/photo.jpg\" alt=\"A photo\" /> // \u274C Too generic\n * <Image src=\"/photo.jpg\" alt=\"Team celebrating project launch\" /> // \u2705 Descriptive\n * ```\n */\n alt: string;\n}\n\n/**\n * Image component for displaying images with enhanced loading states and accessibility\n *\n * The Image component extends the standard HTML img element with advanced features\n * including placeholder images, skeleton loading states, fade-in animations, and\n * comprehensive accessibility support. It integrates seamlessly with the design\n * system's layout, spacing, and theming capabilities.\n *\n * Key features:\n * - Progressive loading with placeholder and skeleton states\n * - Fade-in animations with reduced motion support\n * - Comprehensive accessibility with ARIA attributes\n * - Object-fit control for responsive image scaling\n * - Caption support for additional context\n * - AsChild pattern for flexible composition\n * - Error handling with fallback states\n * - Performance optimizations for cached images\n *\n * @example\n * ```tsx\n * // Basic usage\n * <Image src=\"/photo.jpg\" alt=\"Team photo\" />\n *\n * // With placeholder and skeleton\n * <Image\n * src=\"/high-res.jpg\"\n * placeholder=\"/low-res.jpg\"\n * showSkeleton\n * alt=\"Product showcase\"\n * />\n *\n * // With caption and custom fit\n * <Image\n * src=\"/chart.png\"\n * alt=\"Sales data visualization\"\n * caption=\"Q3 2024 Sales Performance\"\n * fit=\"contain\"\n * width=\"400px\"\n * height=\"300px\"\n * />\n *\n * // As clickable element\n * <Image\n * asChild\n * src=\"/thumbnail.jpg\"\n * alt=\"View full gallery\"\n * >\n * <a href=\"/gallery\">\n * View Gallery\n * </a>\n * </Image>\n * ```\n */\nconst Image = React.forwardRef<ImageElement, ImageProps>((props, forwardedRef) => {\n // Extract and organize props for different purposes\n const {\n asChild,\n className,\n style,\n loading = 'lazy', // Default to lazy loading for performance\n alt,\n src,\n placeholder,\n showSkeleton = false, // Default to no skeleton for simpler UX\n fadeIn = true, // Default to fade-in for smooth loading experience\n\n errorAriaLabel = 'Failed to load image',\n radius,\n caption,\n onLoad: userOnLoad,\n onError: userOnError,\n children,\n ...wrapperProps\n } = extractProps(\n props,\n imagePropDefs,\n marginPropDefs,\n widthPropDefs,\n heightPropDefs,\n layoutPropDefs,\n );\n\n // State management for loading, error, and placeholder states\n const [loadingState, setLoadingState] = React.useState<'loading' | 'loaded' | 'error'>('loading');\n const [showPlaceholder, setShowPlaceholder] = React.useState(!!placeholder);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n /**\n * Handle successful image load\n * Updates state and triggers user callback for load event\n */\n const handleLoad = React.useCallback(\n (event: React.SyntheticEvent<HTMLImageElement>) => {\n setLoadingState('loaded');\n setShowPlaceholder(false);\n // Call user's onLoad handler if provided\n userOnLoad?.(event);\n },\n [userOnLoad],\n );\n\n /**\n * Handle image load error\n * Updates state and triggers user callback for error event\n */\n const handleError = React.useCallback(\n (event: React.SyntheticEvent<HTMLImageElement>) => {\n setLoadingState('error');\n setShowPlaceholder(false);\n // Call user's onError handler if provided\n userOnError?.(event);\n },\n [userOnError],\n );\n\n /**\n * Check if image is already loaded (optimization for cached images)\n * This prevents unnecessary loading states for images that are already available\n */\n React.useEffect(() => {\n const img = imgRef.current;\n if (img && img.complete && img.naturalWidth > 0) {\n setLoadingState('loaded');\n setShowPlaceholder(false);\n }\n }, [src]);\n\n // Validate required props and provide helpful development warnings\n if (!src) {\n console.warn('Image component: src prop is required');\n return null;\n }\n\n if (!asChild && alt === undefined) {\n console.warn('Image component: alt prop is required for accessibility when not using asChild');\n }\n\n // Derive loading state flags for cleaner conditional rendering\n const isLoading = loadingState === 'loading';\n const isError = loadingState === 'error';\n const isLoaded = loadingState === 'loaded';\n\n /**\n * ARIA attributes for comprehensive accessibility support\n * These attributes help screen readers understand the image state\n */\n const ariaProps = {\n 'aria-busy': isLoading,\n 'aria-invalid': isError,\n 'aria-describedby': isError ? 'image-error' : undefined,\n };\n\n /**\n * Image styling that handles fade-in animation and responsive behavior\n * Respects user's motion preferences through CSS media queries\n */\n const imgStyle: React.CSSProperties = {\n width: '100%',\n height: '100%',\n display: 'block',\n // Conditional opacity for fade-in effect\n opacity: fadeIn ? (isLoaded ? 1 : 0) : 1,\n // Smooth transition for fade-in, respects reduced motion preferences\n transition: fadeIn ? 'opacity 0.3s ease-out' : 'none',\n };\n\n /**\n * Create the complete image content structure\n * This includes the main image, placeholder, skeleton, caption, and error states\n */\n const imageContent = (\n <>\n {/*\n * Image container - handles layout and positioning\n * Uses flex layout when caption is present for proper space distribution\n */}\n <div\n style={{\n position: 'relative',\n flex: caption ? '1 1 0%' : undefined,\n height: caption ? undefined : '100%',\n minHeight: 0, // Important for flex shrinking in constrained layouts\n }}\n >\n {/*\n * Error message for screen readers\n * Hidden visually but announced by assistive technology\n */}\n {isError && (\n <div id=\"image-error\" className=\"rt-sr-only\" aria-live=\"polite\">\n {errorAriaLabel}\n </div>\n )}\n\n {/*\n * Skeleton placeholder during loading\n * Provides visual feedback and prevents layout shift\n */}\n {showSkeleton && isLoading && (\n <Skeleton width=\"100%\" height=\"100%\" style={{ position: 'absolute', inset: 0 }} />\n )}\n\n {/*\n * Placeholder image with blur effect\n * Shows a low-quality version while the main image loads\n */}\n {placeholder && showPlaceholder && (\n <img\n style={{\n ...imgStyle,\n position: 'absolute',\n inset: 0,\n filter: 'blur(4px)', // Creates the blur effect for LQIP (Low Quality Image Placeholder)\n opacity: 0.7, // Subtle opacity to indicate it's a placeholder\n zIndex: 0, // Behind the main image\n }}\n className={classNames('rt-reset', 'rt-Image', 'rt-Image--placeholder')}\n alt=\"\" // Decorative placeholder, no alt text needed\n src={placeholder}\n />\n )}\n\n {/*\n * Main image element\n * Handles all the core functionality and user interactions\n */}\n <img\n ref={(node) => {\n // Handle both internal ref and forwarded ref\n imgRef.current = node;\n if (typeof forwardedRef === 'function') {\n forwardedRef(node);\n } else if (forwardedRef) {\n forwardedRef.current = node;\n }\n }}\n loading={loading}\n style={{ ...imgStyle, position: 'relative', zIndex: 1 }}\n className={classNames('rt-reset', 'rt-Image', className)}\n alt={alt}\n src={src}\n data-radius={radius}\n onLoad={handleLoad}\n onError={handleError}\n {...ariaProps}\n />\n </div>\n\n {/*\n * Caption element - positioned below the image\n * Takes only the space it needs, doesn't interfere with image sizing\n */}\n {caption && (\n <div className=\"rt-Image-caption\" style={{ flex: '0 0 auto' }}>\n {caption}\n </div>\n )}\n </>\n );\n\n /**\n * Container styling that adapts based on caption presence\n * Uses flexbox when caption is present for proper layout control\n */\n const containerStyle: React.CSSProperties = {\n display: caption ? 'flex' : 'block',\n flexDirection: caption ? 'column' : undefined,\n ...style, // Allow user styles to override defaults\n };\n\n /**\n * Render with asChild pattern for composition\n * This allows the Image to be rendered as a child of another element\n * while maintaining all its functionality and styling\n */\n if (asChild) {\n return (\n <Slot className={className} style={containerStyle} {...wrapperProps}>\n {React.cloneElement(children as React.ReactElement, {}, imageContent)}\n </Slot>\n );\n }\n\n /**\n * Regular rendering as a standalone div container\n * This is the default rendering mode for most use cases\n */\n return (\n <div className={className} style={containerStyle} {...wrapperProps}>\n {imageContent}\n </div>\n );\n});\n\nImage.displayName = 'Image';\n\nexport { Image };\nexport type { ImageProps };\n"],
5
- "mappings": "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",
6
- "names": ["image_exports", "__export", "Image", "__toCommonJS", "React", "import_classnames", "import_image_props", "import_extract_props", "import_margin_props", "import_width_props", "import_height_props", "import_layout_props", "import_skeleton", "import_slot", "props", "forwardedRef", "asChild", "className", "style", "loading", "alt", "src", "placeholder", "showSkeleton", "fadeIn", "errorAriaLabel", "radius", "caption", "userOnLoad", "userOnError", "children", "wrapperProps", "loadingState", "setLoadingState", "showPlaceholder", "setShowPlaceholder", "imgRef", "handleLoad", "event", "handleError", "img", "isLoading", "isError", "isLoaded", "ariaProps", "imgStyle", "imageContent", "classNames", "node", "containerStyle"]
4
+ "sourcesContent": ["import * as React from 'react';\nimport classNames from 'classnames';\n\nimport { imagePropDefs } from './image.props.js';\nimport { extractProps } from '../helpers/extract-props.js';\nimport { marginPropDefs } from '../props/margin.props.js';\nimport { widthPropDefs } from '../props/width.props.js';\nimport { heightPropDefs } from '../props/height.props.js';\nimport { layoutPropDefs } from '../props/layout.props.js';\nimport { Skeleton } from './skeleton.js';\nimport { Slot } from './slot.js';\n\nimport type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';\nimport type { MarginProps } from '../props/margin.props.js';\nimport type { WidthProps } from '../props/width.props.js';\nimport type { HeightProps } from '../props/height.props.js';\nimport type { LayoutProps } from '../props/layout.props.js';\nimport type { GetPropDefTypes } from '../props/prop-def.js';\n\ntype ImageElement = React.ElementRef<'img'>;\n\n/**\n * Core Image props that extend the base image prop definitions\n * These props provide enhanced functionality beyond standard HTML img attributes\n */\ntype ImageOwnProps = GetPropDefTypes<typeof imagePropDefs> & {\n /**\n * Native loading behavior for the image\n * 'lazy' defers loading until the image is near the viewport\n * 'eager' loads the image immediately\n */\n loading?: 'eager' | 'lazy';\n /**\n * Placeholder image URL to show while the main image is loading\n *\n * Best practices:\n * - Use a low-quality/blurred version of the main image\n * - Keep file size small (under 10KB recommended)\n * - Use same aspect ratio as main image\n * - Consider using base64 data URLs for inline placeholders\n *\n * @example\n * ```tsx\n * <Image\n * src=\"/high-res-image.jpg\"\n * placeholder=\"/low-res-placeholder.jpg\"\n * alt=\"Product photo\"\n * />\n * ```\n */\n placeholder?: string;\n /**\n * Shows a skeleton placeholder while loading instead of a blank space\n *\n * Use this when:\n * - You don't have a placeholder image\n * - You want consistent loading states across your interface\n * - The image is part of a content layout that needs stable dimensions\n */\n showSkeleton?: boolean;\n /**\n * Whether the image should fade in when loaded\n *\n * Set to false for:\n * - Background images where immediate visibility is important\n * - Images that need to appear instantly for UX reasons\n * - When you're implementing custom loading animations\n */\n fadeIn?: boolean;\n /**\n * Callback fired when the image successfully loads\n *\n * Use this to:\n * - Track image loading performance\n * - Trigger layout adjustments after load\n * - Implement custom loading state management\n */\n onLoad?: (event: React.SyntheticEvent<HTMLImageElement>) => void;\n /**\n * Callback fired when the image fails to load\n *\n * Use this to:\n * - Log errors for monitoring\n * - Show fallback content\n * - Implement retry logic\n */\n onError?: (event: React.SyntheticEvent<HTMLImageElement>) => void;\n};\n\n/**\n * Complete Image component props interface\n *\n * Combines HTML img attributes with design system props and enhanced functionality.\n * Excludes conflicting props like 'color', 'width', 'height' that are handled by the design system.\n */\ninterface ImageProps\n extends ComponentPropsWithout<'img', RemovedProps | 'color' | 'width' | 'height' | 'alt'>,\n MarginProps,\n WidthProps,\n HeightProps,\n LayoutProps,\n ImageOwnProps {\n /**\n * Alternative text for the image\n *\n * Required for accessibility when not using asChild pattern.\n * Describes the image content for screen readers and when images fail to load.\n *\n * Guidelines:\n * - Be descriptive but concise\n * - Don't include \"image of\" or \"picture of\"\n * - Use empty string (\"\") for purely decorative images\n * - Describe the content and context, not just what you see\n *\n * @example\n * ```tsx\n * // Good alt text\n * <Image src=\"/chart.png\" alt=\"Sales increased 25% from Q1 to Q2\" />\n *\n * // Decorative image\n * <Image src=\"/decoration.png\" alt=\"\" />\n *\n * // Avoid generic descriptions\n * <Image src=\"/photo.jpg\" alt=\"A photo\" /> // \u274C Too generic\n * <Image src=\"/photo.jpg\" alt=\"Team celebrating project launch\" /> // \u2705 Descriptive\n * ```\n */\n alt: string;\n}\n\n/**\n * Image component for displaying images with enhanced loading states and accessibility\n *\n * The Image component extends the standard HTML img element with advanced features\n * including placeholder images, skeleton loading states, fade-in animations, and\n * comprehensive accessibility support. It integrates seamlessly with the design\n * system's layout, spacing, and theming capabilities.\n *\n * Key features:\n * - Progressive loading with placeholder and skeleton states\n * - Fade-in animations with reduced motion support\n * - Comprehensive accessibility with ARIA attributes\n * - Object-fit control for responsive image scaling\n * - Caption support for additional context\n * - AsChild pattern for flexible composition\n * - Error handling with fallback states\n * - Performance optimizations for cached images\n *\n * @example\n * ```tsx\n * // Basic usage\n * <Image src=\"/photo.jpg\" alt=\"Team photo\" />\n *\n * // With placeholder and skeleton\n * <Image\n * src=\"/high-res.jpg\"\n * placeholder=\"/low-res.jpg\"\n * showSkeleton\n * alt=\"Product showcase\"\n * />\n *\n * // With caption and custom fit\n * <Image\n * src=\"/chart.png\"\n * alt=\"Sales data visualization\"\n * caption=\"Q3 2024 Sales Performance\"\n * fit=\"contain\"\n * width=\"400px\"\n * height=\"300px\"\n * />\n *\n * // As clickable element\n * <Image\n * asChild\n * src=\"/thumbnail.jpg\"\n * alt=\"View full gallery\"\n * >\n * <a href=\"/gallery\">\n * View Gallery\n * </a>\n * </Image>\n * ```\n */\nconst Image = React.forwardRef<ImageElement, ImageProps>((props, forwardedRef) => {\n // Extract and organize props for different purposes\n const {\n asChild,\n className,\n style,\n loading = 'lazy', // Default to lazy loading for performance\n alt,\n src,\n placeholder,\n showSkeleton = false, // Default to no skeleton for simpler UX\n fadeIn = true, // Default to fade-in for smooth loading experience\n loadingAriaLabel, // Extract but don't use\n errorAriaLabel = 'Failed to load image',\n radius,\n caption,\n onLoad: userOnLoad,\n onError: userOnError,\n children,\n ...wrapperProps\n } = extractProps(\n props,\n imagePropDefs,\n marginPropDefs,\n widthPropDefs,\n heightPropDefs,\n layoutPropDefs,\n );\n\n // State management for loading, error, and placeholder states\n const [loadingState, setLoadingState] = React.useState<'loading' | 'loaded' | 'error'>('loading');\n const [showPlaceholder, setShowPlaceholder] = React.useState(!!placeholder);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n /**\n * Handle successful image load\n * Updates state and triggers user callback for load event\n */\n const handleLoad = React.useCallback(\n (event: React.SyntheticEvent<HTMLImageElement>) => {\n setLoadingState('loaded');\n setShowPlaceholder(false);\n // Call user's onLoad handler if provided\n userOnLoad?.(event);\n },\n [userOnLoad],\n );\n\n /**\n * Handle image load error\n * Updates state and triggers user callback for error event\n */\n const handleError = React.useCallback(\n (event: React.SyntheticEvent<HTMLImageElement>) => {\n setLoadingState('error');\n setShowPlaceholder(false);\n // Call user's onError handler if provided\n userOnError?.(event);\n },\n [userOnError],\n );\n\n /**\n * Check if image is already loaded (optimization for cached images)\n * This prevents unnecessary loading states for images that are already available\n */\n React.useEffect(() => {\n const img = imgRef.current;\n if (img && img.complete && img.naturalWidth > 0) {\n setLoadingState('loaded');\n setShowPlaceholder(false);\n }\n }, [src]);\n\n // Validate required props and provide helpful development warnings\n if (!src) {\n console.warn('Image component: src prop is required');\n return null;\n }\n\n if (!asChild && alt === undefined) {\n console.warn('Image component: alt prop is required for accessibility when not using asChild');\n }\n\n // Derive loading state flags for cleaner conditional rendering\n const isLoading = loadingState === 'loading';\n const isError = loadingState === 'error';\n const isLoaded = loadingState === 'loaded';\n\n /**\n * ARIA attributes for comprehensive accessibility support\n * These attributes help screen readers understand the image state\n */\n const ariaProps = {\n 'aria-busy': isLoading,\n 'aria-invalid': isError,\n 'aria-describedby': isError ? 'image-error' : undefined,\n };\n\n /**\n * Image styling that handles fade-in animation and responsive behavior\n * Respects user's motion preferences through CSS media queries\n */\n const imgStyle: React.CSSProperties = {\n width: '100%',\n height: '100%',\n display: 'block',\n // Conditional opacity for fade-in effect\n opacity: fadeIn ? (isLoaded ? 1 : 0) : 1,\n // Smooth transition for fade-in, respects reduced motion preferences\n transition: fadeIn ? 'opacity 0.3s ease-out' : 'none',\n };\n\n /**\n * Create the complete image content structure\n * This includes the main image, placeholder, skeleton, caption, and error states\n */\n const imageContent = (\n <>\n {/*\n * Image container - handles layout and positioning\n * Uses flex layout when caption is present for proper space distribution\n */}\n <div\n style={{\n position: 'relative',\n flex: caption ? '1 1 0%' : undefined,\n height: caption ? undefined : '100%',\n minHeight: 0, // Important for flex shrinking in constrained layouts\n }}\n >\n {/*\n * Error message for screen readers\n * Hidden visually but announced by assistive technology\n */}\n {isError && (\n <div id=\"image-error\" className=\"rt-sr-only\" aria-live=\"polite\">\n {errorAriaLabel}\n </div>\n )}\n\n {/*\n * Skeleton placeholder during loading\n * Provides visual feedback and prevents layout shift\n */}\n {showSkeleton && isLoading && (\n <Skeleton width=\"100%\" height=\"100%\" style={{ position: 'absolute', inset: 0 }} />\n )}\n\n {/*\n * Placeholder image with blur effect\n * Shows a low-quality version while the main image loads\n */}\n {placeholder && showPlaceholder && (\n <img\n style={{\n ...imgStyle,\n position: 'absolute',\n inset: 0,\n filter: 'blur(4px)', // Creates the blur effect for LQIP (Low Quality Image Placeholder)\n opacity: 0.7, // Subtle opacity to indicate it's a placeholder\n zIndex: 0, // Behind the main image\n }}\n className={classNames('rt-reset', 'rt-Image', 'rt-Image--placeholder')}\n alt=\"\" // Decorative placeholder, no alt text needed\n src={placeholder}\n />\n )}\n\n {/*\n * Main image element\n * Handles all the core functionality and user interactions\n */}\n <img\n ref={(node) => {\n // Handle both internal ref and forwarded ref\n imgRef.current = node;\n if (typeof forwardedRef === 'function') {\n forwardedRef(node);\n } else if (forwardedRef) {\n forwardedRef.current = node;\n }\n }}\n loading={loading}\n style={{ ...imgStyle, position: 'relative', zIndex: 1 }}\n className={classNames('rt-reset', 'rt-Image', className)}\n alt={alt}\n src={src}\n data-radius={radius}\n onLoad={handleLoad}\n onError={handleError}\n {...ariaProps}\n />\n </div>\n\n {/*\n * Caption element - positioned below the image\n * Takes only the space it needs, doesn't interfere with image sizing\n */}\n {caption && (\n <div className=\"rt-Image-caption\" style={{ flex: '0 0 auto' }}>\n {caption}\n </div>\n )}\n </>\n );\n\n /**\n * Container styling that adapts based on caption presence\n * Uses flexbox when caption is present for proper layout control\n */\n const containerStyle: React.CSSProperties = {\n display: caption ? 'flex' : 'block',\n flexDirection: caption ? 'column' : undefined,\n ...style, // Allow user styles to override defaults\n };\n\n /**\n * Render with asChild pattern for composition\n * This allows the Image to be rendered as a child of another element\n * while maintaining all its functionality and styling\n */\n if (asChild) {\n return (\n <Slot className={className} style={containerStyle} {...wrapperProps}>\n {React.cloneElement(children as React.ReactElement, {}, imageContent)}\n </Slot>\n );\n }\n\n /**\n * Regular rendering as a standalone div container\n * This is the default rendering mode for most use cases\n */\n return (\n <div className={className} style={containerStyle} {...wrapperProps}>\n {imageContent}\n </div>\n );\n});\n\nImage.displayName = 'Image';\n\nexport { Image };\nexport type { ImageProps };\n"],
5
+ "mappings": "0jBAAA,IAAAA,GAAA,GAAAC,EAAAD,GAAA,WAAAE,IAAA,eAAAC,EAAAH,IAAA,IAAAI,EAAuB,oBACvBC,EAAuB,yBAEvBC,EAA8B,4BAC9BC,EAA6B,uCAC7BC,EAA+B,oCAC/BC,EAA8B,mCAC9BC,EAA+B,oCAC/BC,EAA+B,oCAC/BC,EAAyB,yBACzBC,EAAqB,qBA6KrB,MAAMX,EAAQE,EAAM,WAAqC,CAACU,EAAOC,IAAiB,CAEhF,KAAM,CACJ,QAAAC,EACA,UAAAC,EACA,MAAAC,EACA,QAAAC,EAAU,OACV,IAAAC,EACA,IAAAC,EACA,YAAAC,EACA,aAAAC,EAAe,GACf,OAAAC,EAAS,GACT,iBAAAC,GACA,eAAAC,EAAiB,uBACjB,OAAAC,EACA,QAAAC,EACA,OAAQC,EACR,QAASC,EACT,SAAAC,EACA,GAAGC,CACL,KAAI,gBACFlB,EACA,gBACA,iBACA,gBACA,iBACA,gBACF,EAGM,CAACmB,EAAcC,CAAe,EAAI9B,EAAM,SAAyC,SAAS,EAC1F,CAAC+B,EAAiBC,CAAkB,EAAIhC,EAAM,SAAS,CAAC,CAACkB,CAAW,EACpEe,EAASjC,EAAM,OAAyB,IAAI,EAM5CkC,EAAalC,EAAM,YACtBmC,GAAkD,CACjDL,EAAgB,QAAQ,EACxBE,EAAmB,EAAK,EAExBP,IAAaU,CAAK,CACpB,EACA,CAACV,CAAU,CACb,EAMMW,EAAcpC,EAAM,YACvBmC,GAAkD,CACjDL,EAAgB,OAAO,EACvBE,EAAmB,EAAK,EAExBN,IAAcS,CAAK,CACrB,EACA,CAACT,CAAW,CACd,EAeA,GATA1B,EAAM,UAAU,IAAM,CACpB,MAAMqC,EAAMJ,EAAO,QACfI,GAAOA,EAAI,UAAYA,EAAI,aAAe,IAC5CP,EAAgB,QAAQ,EACxBE,EAAmB,EAAK,EAE5B,EAAG,CAACf,CAAG,CAAC,EAGJ,CAACA,EACH,eAAQ,KAAK,uCAAuC,EAC7C,KAGL,CAACL,GAAWI,IAAQ,QACtB,QAAQ,KAAK,gFAAgF,EAI/F,MAAMsB,EAAYT,IAAiB,UAC7BU,EAAUV,IAAiB,QAC3BW,EAAWX,IAAiB,SAM5BY,EAAY,CAChB,YAAaH,EACb,eAAgBC,EAChB,mBAAoBA,EAAU,cAAgB,MAChD,EAMMG,EAAgC,CACpC,MAAO,OACP,OAAQ,OACR,QAAS,QAET,QAAStB,EAAUoB,EAAW,EAAI,EAAK,EAEvC,WAAYpB,EAAS,wBAA0B,MACjD,EAMMuB,EACJ3C,EAAA,cAAAA,EAAA,cAKEA,EAAA,cAAC,OACC,MAAO,CACL,SAAU,WACV,KAAMwB,EAAU,SAAW,OAC3B,OAAQA,EAAU,OAAY,OAC9B,UAAW,CACb,GAMCe,GACCvC,EAAA,cAAC,OAAI,GAAG,cAAc,UAAU,aAAa,YAAU,UACpDsB,CACH,EAODH,GAAgBmB,GACftC,EAAA,cAAC,YAAS,MAAM,OAAO,OAAO,OAAO,MAAO,CAAE,SAAU,WAAY,MAAO,CAAE,EAAG,EAOjFkB,GAAea,GACd/B,EAAA,cAAC,OACC,MAAO,CACL,GAAG0C,EACH,SAAU,WACV,MAAO,EACP,OAAQ,YACR,QAAS,GACT,OAAQ,CACV,EACA,aAAW,EAAAE,SAAW,WAAY,WAAY,uBAAuB,EACrE,IAAI,GACJ,IAAK1B,EACP,EAOFlB,EAAA,cAAC,OACC,IAAM6C,GAAS,CAEbZ,EAAO,QAAUY,EACb,OAAOlC,GAAiB,WAC1BA,EAAakC,CAAI,EACRlC,IACTA,EAAa,QAAUkC,EAE3B,EACA,QAAS9B,EACT,MAAO,CAAE,GAAG2B,EAAU,SAAU,WAAY,OAAQ,CAAE,EACtD,aAAW,EAAAE,SAAW,WAAY,WAAY/B,CAAS,EACvD,IAAKG,EACL,IAAKC,EACL,cAAaM,EACb,OAAQW,EACR,QAASE,EACR,GAAGK,EACN,CACF,EAMCjB,GACCxB,EAAA,cAAC,OAAI,UAAU,mBAAmB,MAAO,CAAE,KAAM,UAAW,GACzDwB,CACH,CAEJ,EAOIsB,EAAsC,CAC1C,QAAStB,EAAU,OAAS,QAC5B,cAAeA,EAAU,SAAW,OACpC,GAAGV,CACL,EAOA,OAAIF,EAEAZ,EAAA,cAAC,QAAK,UAAWa,EAAW,MAAOiC,EAAiB,GAAGlB,GACpD5B,EAAM,aAAa2B,EAAgC,CAAC,EAAGgB,CAAY,CACtE,EASF3C,EAAA,cAAC,OAAI,UAAWa,EAAW,MAAOiC,EAAiB,GAAGlB,GACnDe,CACH,CAEJ,CAAC,EAED7C,EAAM,YAAc",
6
+ "names": ["image_exports", "__export", "Image", "__toCommonJS", "React", "import_classnames", "import_image_props", "import_extract_props", "import_margin_props", "import_width_props", "import_height_props", "import_layout_props", "import_skeleton", "import_slot", "props", "forwardedRef", "asChild", "className", "style", "loading", "alt", "src", "placeholder", "showSkeleton", "fadeIn", "loadingAriaLabel", "errorAriaLabel", "radius", "caption", "userOnLoad", "userOnError", "children", "wrapperProps", "loadingState", "setLoadingState", "showPlaceholder", "setShowPlaceholder", "imgRef", "handleLoad", "event", "handleError", "img", "isLoading", "isError", "isLoaded", "ariaProps", "imgStyle", "imageContent", "classNames", "node", "containerStyle"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/text-area.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nimport classNames from 'classnames';\n\nimport { textAreaPropDefs } from './text-area.props.js';\nimport { extractProps } from '../helpers/extract-props.js';\nimport { marginPropDefs } from '../props/margin.props.js';\n\nimport type { MarginProps } from '../props/margin.props.js';\nimport type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';\nimport type { GetPropDefTypes } from '../props/prop-def.js';\n\ntype TextAreaElement = React.ElementRef<'textarea'>;\ntype TextAreaOwnProps = GetPropDefTypes<typeof textAreaPropDefs> & {\n defaultValue?: string;\n value?: string;\n};\ninterface TextAreaProps\n extends ComponentPropsWithout<'textarea', RemovedProps | 'size' | 'value'>,\n MarginProps,\n TextAreaOwnProps {}\n\nconst TextArea = React.forwardRef<TextAreaElement, TextAreaProps>((props, forwardedRef) => {\n const { className, color, radius, panelBackground, material, style, ...textAreaProps } =\n extractProps(props, textAreaPropDefs, marginPropDefs);\n const effectiveMaterial = material || panelBackground;\n\n // Generate unique IDs for accessibility\n const errorId = React.useId();\n\n const { 'aria-describedby': ariaDescribedby, 'aria-labelledby': ariaLabelledby } = textAreaProps;\n \n // Determine invalid state\n const isInvalid = textAreaProps.error || textAreaProps.isInvalid;\n\n // Build aria-describedby string\n const describedBy = React.useMemo(() => {\n const parts = [];\n if (textAreaProps.errorMessage) parts.push(errorId);\n if (ariaDescribedby) parts.push(ariaDescribedby);\n return parts.length > 0 ? parts.join(' ') : undefined;\n }, [textAreaProps.errorMessage, ariaDescribedby, errorId]);\n\n // Build aria attributes\n const ariaProps = React.useMemo(\n () => ({\n 'aria-invalid': isInvalid,\n 'aria-describedby': describedBy,\n 'aria-labelledby': ariaLabelledby,\n }),\n [isInvalid, describedBy, ariaLabelledby],\n );\n\n // Filter out our custom props to avoid DOM warnings\n const {\n error,\n errorMessage,\n isInvalid: _isInvalid,\n required,\n 'aria-describedby': _ariaDescribedby,\n 'aria-labelledby': _ariaLabelledby,\n ...nativeTextAreaProps\n } = textAreaProps;\n\n return (\n <div\n data-accent-color={color}\n data-radius={radius}\n data-panel-background={effectiveMaterial}\n data-material={effectiveMaterial}\n className={classNames('rt-TextAreaRoot', className, {\n 'rt-error': isInvalid,\n })}\n style={style}\n >\n <textarea\n className=\"rt-reset rt-TextAreaInput\"\n ref={forwardedRef}\n {...nativeTextAreaProps}\n {...ariaProps}\n />\n {textAreaProps.errorMessage && (\n <div id={errorId} className=\"rt-TextAreaErrorMessage\" role=\"alert\" aria-live=\"polite\">\n {textAreaProps.errorMessage}\n </div>\n )}\n </div>\n );\n});\n\nTextArea.displayName = 'TextArea';\n\nexport { TextArea };\nexport type { TextAreaProps };\n"],
4
+ "sourcesContent": ["import * as React from 'react';\nimport classNames from 'classnames';\n\nimport { textAreaPropDefs } from './text-area.props.js';\nimport { extractProps } from '../helpers/extract-props.js';\nimport { marginPropDefs } from '../props/margin.props.js';\n\nimport type { MarginProps } from '../props/margin.props.js';\nimport type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';\nimport type { GetPropDefTypes } from '../props/prop-def.js';\n\ntype TextAreaElement = React.ElementRef<'textarea'>;\ntype TextAreaOwnProps = GetPropDefTypes<typeof textAreaPropDefs> & {\n defaultValue?: string;\n value?: string;\n};\ninterface TextAreaProps\n extends ComponentPropsWithout<'textarea', RemovedProps | 'size' | 'value'>,\n MarginProps,\n TextAreaOwnProps {}\n\nconst TextArea = React.forwardRef<TextAreaElement, TextAreaProps>((props, forwardedRef) => {\n const { className, color, radius, panelBackground, material, style, ...textAreaProps } =\n extractProps(props, textAreaPropDefs, marginPropDefs);\n const effectiveMaterial = material || panelBackground;\n\n // Generate unique IDs for accessibility\n const errorId = React.useId();\n\n const { 'aria-describedby': ariaDescribedby, 'aria-labelledby': ariaLabelledby } = textAreaProps;\n\n // Determine invalid state\n const isInvalid = textAreaProps.error || textAreaProps.isInvalid;\n\n // Build aria-describedby string\n const describedBy = React.useMemo(() => {\n const parts = [];\n if (textAreaProps.errorMessage) parts.push(errorId);\n if (ariaDescribedby) parts.push(ariaDescribedby);\n return parts.length > 0 ? parts.join(' ') : undefined;\n }, [textAreaProps.errorMessage, ariaDescribedby, errorId]);\n\n // Build aria attributes\n const ariaProps = React.useMemo(\n () => ({\n 'aria-invalid': isInvalid,\n 'aria-describedby': describedBy,\n 'aria-labelledby': ariaLabelledby,\n }),\n [isInvalid, describedBy, ariaLabelledby],\n );\n\n // Filter out our custom props to avoid DOM warnings\n const {\n error,\n errorMessage,\n isInvalid: _isInvalid,\n required,\n 'aria-describedby': _ariaDescribedby,\n 'aria-labelledby': _ariaLabelledby,\n ...nativeTextAreaProps\n } = textAreaProps;\n\n return (\n <div\n data-accent-color={color}\n data-radius={radius}\n data-panel-background={effectiveMaterial}\n data-material={effectiveMaterial}\n className={classNames('rt-TextAreaRoot', className, {\n 'rt-error': isInvalid,\n })}\n style={style}\n >\n <textarea\n className=\"rt-reset rt-TextAreaInput\"\n ref={forwardedRef}\n {...nativeTextAreaProps}\n {...ariaProps}\n />\n {textAreaProps.errorMessage && (\n <div id={errorId} className=\"rt-TextAreaErrorMessage\" role=\"alert\" aria-live=\"polite\">\n {textAreaProps.errorMessage}\n </div>\n )}\n </div>\n );\n});\n\nTextArea.displayName = 'TextArea';\n\nexport { TextArea };\nexport type { TextAreaProps };\n"],
5
5
  "mappings": "0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,cAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAuB,oBACvBC,EAAuB,yBAEvBC,EAAiC,gCACjCC,EAA6B,uCAC7BC,EAA+B,oCAgB/B,MAAMN,EAAWE,EAAM,WAA2C,CAACK,EAAOC,IAAiB,CACzF,KAAM,CAAE,UAAAC,EAAW,MAAAC,EAAO,OAAAC,EAAQ,gBAAAC,EAAiB,SAAAC,EAAU,MAAAC,EAAO,GAAGC,CAAc,KACnF,gBAAaR,EAAO,mBAAkB,gBAAc,EAChDS,EAAoBH,GAAYD,EAGhCK,EAAUf,EAAM,MAAM,EAEtB,CAAE,mBAAoBgB,EAAiB,kBAAmBC,CAAe,EAAIJ,EAG7EK,EAAYL,EAAc,OAASA,EAAc,UAGjDM,EAAcnB,EAAM,QAAQ,IAAM,CACtC,MAAMoB,EAAQ,CAAC,EACf,OAAIP,EAAc,cAAcO,EAAM,KAAKL,CAAO,EAC9CC,GAAiBI,EAAM,KAAKJ,CAAe,EACxCI,EAAM,OAAS,EAAIA,EAAM,KAAK,GAAG,EAAI,MAC9C,EAAG,CAACP,EAAc,aAAcG,EAAiBD,CAAO,CAAC,EAGnDM,EAAYrB,EAAM,QACtB,KAAO,CACL,eAAgBkB,EAChB,mBAAoBC,EACpB,kBAAmBF,CACrB,GACA,CAACC,EAAWC,EAAaF,CAAc,CACzC,EAGM,CACJ,MAAAK,EACA,aAAAC,EACA,UAAWC,EACX,SAAAC,EACA,mBAAoBC,EACpB,kBAAmBC,EACnB,GAAGC,CACL,EAAIf,EAEJ,OACEb,EAAA,cAAC,OACC,oBAAmBQ,EACnB,cAAaC,EACb,wBAAuBK,EACvB,gBAAeA,EACf,aAAW,EAAAe,SAAW,kBAAmBtB,EAAW,CAClD,WAAYW,CACd,CAAC,EACD,MAAON,GAEPZ,EAAA,cAAC,YACC,UAAU,4BACV,IAAKM,EACJ,GAAGsB,EACH,GAAGP,EACN,EACCR,EAAc,cACbb,EAAA,cAAC,OAAI,GAAIe,EAAS,UAAU,0BAA0B,KAAK,QAAQ,YAAU,UAC1EF,EAAc,YACjB,CAEJ,CAEJ,CAAC,EAEDf,EAAS,YAAc",
6
6
  "names": ["text_area_exports", "__export", "TextArea", "__toCommonJS", "React", "import_classnames", "import_text_area_props", "import_extract_props", "import_margin_props", "props", "forwardedRef", "className", "color", "radius", "panelBackground", "material", "style", "textAreaProps", "effectiveMaterial", "errorId", "ariaDescribedby", "ariaLabelledby", "isInvalid", "describedBy", "parts", "ariaProps", "error", "errorMessage", "_isInvalid", "required", "_ariaDescribedby", "_ariaLabelledby", "nativeTextAreaProps", "classNames"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/text-field.tsx"],
4
- "sourcesContent": ["'use client';\n\nimport * as React from 'react';\nimport classNames from 'classnames';\nimport { composeRefs } from 'radix-ui/internal';\n\nimport { textFieldRootPropDefs, textFieldSlotPropDefs } from './text-field.props.js';\nimport { extractProps } from '../helpers/extract-props.js';\nimport { marginPropDefs } from '../props/margin.props.js';\n\nimport type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';\nimport type { NotInputTextualAttributes } from '../helpers/input-attributes.js';\nimport type { MarginProps } from '../props/margin.props.js';\nimport type { GetPropDefTypes } from '../props/prop-def.js';\n\ntype TextFieldRootElement = React.ElementRef<'input'>;\ntype TextFieldRootOwnProps = GetPropDefTypes<typeof textFieldRootPropDefs> & {\n defaultValue?: string | number;\n value?: string | number;\n type?:\n | 'date'\n | 'datetime-local'\n | 'email'\n | 'hidden'\n | 'month'\n | 'number'\n | 'password'\n | 'search'\n | 'tel'\n | 'text'\n | 'time'\n | 'url'\n | 'week';\n};\ntype TextFieldInputProps = ComponentPropsWithout<\n 'input',\n NotInputTextualAttributes | 'color' | 'defaultValue' | 'size' | 'type' | 'value'\n>;\ninterface TextFieldRootProps extends TextFieldInputProps, MarginProps, TextFieldRootOwnProps {}\nconst TextFieldRoot = React.forwardRef<TextFieldRootElement, TextFieldRootProps>(\n (props, forwardedRef) => {\n const inputRef = React.useRef<HTMLInputElement>(null);\n const { children, className, color, radius, panelBackground, material, style, ...inputProps } =\n extractProps(props, textFieldRootPropDefs, marginPropDefs);\n const effectiveMaterial = material || panelBackground;\n\n // Generate unique IDs for accessibility\n const errorId = React.useId();\n\n // Determine invalid state\n const isInvalid = inputProps.error || inputProps.isInvalid;\n\n const { 'aria-describedby': ariaDescribedby, 'aria-labelledby': ariaLabelledby } = inputProps;\n \n // Build aria-describedby string\n const describedBy = React.useMemo(() => {\n const parts = [];\n if (inputProps.errorMessage) parts.push(errorId);\n if (ariaDescribedby) parts.push(ariaDescribedby);\n return parts.length > 0 ? parts.join(' ') : undefined;\n }, [inputProps.errorMessage, ariaDescribedby, errorId]);\n\n // Build aria attributes\n const ariaProps = React.useMemo(\n () => ({\n 'aria-invalid': isInvalid,\n 'aria-describedby': describedBy,\n 'aria-labelledby': ariaLabelledby,\n }),\n [isInvalid, describedBy, ariaLabelledby],\n );\n\n // Filter out our custom props to avoid DOM warnings\n const {\n error,\n errorMessage,\n isInvalid: _isInvalid,\n required,\n 'aria-describedby': _ariaDescribedby,\n 'aria-labelledby': _ariaLabelledby,\n ...nativeInputProps\n } = inputProps;\n\n // Memoized pointer event handler\n const handlePointerDown = React.useCallback((event: React.PointerEvent) => {\n const target = event.target as HTMLElement;\n if (target.closest('input, button, a')) return;\n\n const input = inputRef.current;\n if (!input) return;\n\n // Same selector as in the CSS to find the right slot\n const isRightSlot = target.closest(`\n .rt-TextFieldSlot[data-side='right'],\n .rt-TextFieldSlot:not([data-side='right']) ~ .rt-TextFieldSlot:not([data-side='left'])\n `);\n\n const cursorPosition = isRightSlot ? input.value.length : 0;\n\n requestAnimationFrame(() => {\n // Only some input types support this, browsers will throw an error if not supported\n // See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange#:~:text=Note%20that%20according,not%20support%20selection%22.\n try {\n input.setSelectionRange(cursorPosition, cursorPosition);\n } catch {}\n input.focus();\n });\n }, []);\n\n return (\n <div\n data-accent-color={color}\n data-radius={radius}\n data-panel-background={effectiveMaterial}\n data-material={effectiveMaterial}\n style={style}\n className={classNames('rt-TextFieldRoot', className, {\n 'rt-error': isInvalid,\n })}\n onPointerDown={handlePointerDown}\n >\n <input\n spellCheck=\"false\"\n {...nativeInputProps}\n {...ariaProps}\n ref={composeRefs(inputRef, forwardedRef)}\n className=\"rt-reset rt-TextFieldInput\"\n />\n {children}\n {inputProps.errorMessage && (\n <div id={errorId} className=\"rt-TextFieldErrorMessage\" role=\"alert\" aria-live=\"polite\">\n {inputProps.errorMessage}\n </div>\n )}\n </div>\n );\n },\n);\nTextFieldRoot.displayName = 'TextField.Root';\n\ntype TextFieldSlotElement = React.ElementRef<'div'>;\ntype TextFieldSlotOwnProps = GetPropDefTypes<typeof textFieldSlotPropDefs>;\ninterface TextFieldSlotProps\n extends ComponentPropsWithout<'div', RemovedProps>,\n TextFieldSlotOwnProps {}\nconst TextFieldSlot = React.forwardRef<TextFieldSlotElement, TextFieldSlotProps>(\n (props, forwardedRef) => {\n const { className, color, side, ...slotProps } = extractProps(props, textFieldSlotPropDefs);\n return (\n <div\n data-accent-color={color}\n data-side={side}\n {...slotProps}\n ref={forwardedRef}\n className={classNames('rt-TextFieldSlot', className)}\n />\n );\n },\n);\nTextFieldSlot.displayName = 'TextField.Slot';\n\nexport { TextFieldRoot as Root, TextFieldSlot as Slot };\nexport type { TextFieldRootProps as RootProps, TextFieldSlotProps as SlotProps };\n"],
4
+ "sourcesContent": ["'use client';\n\nimport * as React from 'react';\nimport classNames from 'classnames';\nimport { composeRefs } from 'radix-ui/internal';\n\nimport { textFieldRootPropDefs, textFieldSlotPropDefs } from './text-field.props.js';\nimport { extractProps } from '../helpers/extract-props.js';\nimport { marginPropDefs } from '../props/margin.props.js';\n\nimport type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';\nimport type { NotInputTextualAttributes } from '../helpers/input-attributes.js';\nimport type { MarginProps } from '../props/margin.props.js';\nimport type { GetPropDefTypes } from '../props/prop-def.js';\n\ntype TextFieldRootElement = React.ElementRef<'input'>;\ntype TextFieldRootOwnProps = GetPropDefTypes<typeof textFieldRootPropDefs> & {\n defaultValue?: string | number;\n value?: string | number;\n type?:\n | 'date'\n | 'datetime-local'\n | 'email'\n | 'hidden'\n | 'month'\n | 'number'\n | 'password'\n | 'search'\n | 'tel'\n | 'text'\n | 'time'\n | 'url'\n | 'week';\n};\ntype TextFieldInputProps = ComponentPropsWithout<\n 'input',\n NotInputTextualAttributes | 'color' | 'defaultValue' | 'size' | 'type' | 'value'\n>;\ninterface TextFieldRootProps extends TextFieldInputProps, MarginProps, TextFieldRootOwnProps {}\nconst TextFieldRoot = React.forwardRef<TextFieldRootElement, TextFieldRootProps>(\n (props, forwardedRef) => {\n const inputRef = React.useRef<HTMLInputElement>(null);\n const { children, className, color, radius, panelBackground, material, style, ...inputProps } =\n extractProps(props, textFieldRootPropDefs, marginPropDefs);\n const effectiveMaterial = material || panelBackground;\n\n // Generate unique IDs for accessibility\n const errorId = React.useId();\n\n // Determine invalid state\n const isInvalid = inputProps.error || inputProps.isInvalid;\n\n const { 'aria-describedby': ariaDescribedby, 'aria-labelledby': ariaLabelledby } = inputProps;\n\n // Build aria-describedby string\n const describedBy = React.useMemo(() => {\n const parts = [];\n if (inputProps.errorMessage) parts.push(errorId);\n if (ariaDescribedby) parts.push(ariaDescribedby);\n return parts.length > 0 ? parts.join(' ') : undefined;\n }, [inputProps.errorMessage, ariaDescribedby, errorId]);\n\n // Build aria attributes\n const ariaProps = React.useMemo(\n () => ({\n 'aria-invalid': isInvalid,\n 'aria-describedby': describedBy,\n 'aria-labelledby': ariaLabelledby,\n }),\n [isInvalid, describedBy, ariaLabelledby],\n );\n\n // Filter out our custom props to avoid DOM warnings\n const {\n error,\n errorMessage,\n isInvalid: _isInvalid,\n required,\n 'aria-describedby': _ariaDescribedby,\n 'aria-labelledby': _ariaLabelledby,\n ...nativeInputProps\n } = inputProps;\n\n // Memoized pointer event handler\n const handlePointerDown = React.useCallback((event: React.PointerEvent) => {\n const target = event.target as HTMLElement;\n if (target.closest('input, button, a')) return;\n\n const input = inputRef.current;\n if (!input) return;\n\n // Same selector as in the CSS to find the right slot\n const isRightSlot = target.closest(`\n .rt-TextFieldSlot[data-side='right'],\n .rt-TextFieldSlot:not([data-side='right']) ~ .rt-TextFieldSlot:not([data-side='left'])\n `);\n\n const cursorPosition = isRightSlot ? input.value.length : 0;\n\n requestAnimationFrame(() => {\n // Only some input types support this, browsers will throw an error if not supported\n // See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange#:~:text=Note%20that%20according,not%20support%20selection%22.\n try {\n input.setSelectionRange(cursorPosition, cursorPosition);\n } catch {}\n input.focus();\n });\n }, []);\n\n return (\n <div\n data-accent-color={color}\n data-radius={radius}\n data-panel-background={effectiveMaterial}\n data-material={effectiveMaterial}\n style={style}\n className={classNames('rt-TextFieldRoot', className, {\n 'rt-error': isInvalid,\n })}\n onPointerDown={handlePointerDown}\n >\n <input\n spellCheck=\"false\"\n {...nativeInputProps}\n {...ariaProps}\n ref={composeRefs(inputRef, forwardedRef)}\n className=\"rt-reset rt-TextFieldInput\"\n />\n {children}\n {inputProps.errorMessage && (\n <div id={errorId} className=\"rt-TextFieldErrorMessage\" role=\"alert\" aria-live=\"polite\">\n {inputProps.errorMessage}\n </div>\n )}\n </div>\n );\n },\n);\nTextFieldRoot.displayName = 'TextField.Root';\n\ntype TextFieldSlotElement = React.ElementRef<'div'>;\ntype TextFieldSlotOwnProps = GetPropDefTypes<typeof textFieldSlotPropDefs>;\ninterface TextFieldSlotProps\n extends ComponentPropsWithout<'div', RemovedProps>,\n TextFieldSlotOwnProps {}\nconst TextFieldSlot = React.forwardRef<TextFieldSlotElement, TextFieldSlotProps>(\n (props, forwardedRef) => {\n const { className, color, side, ...slotProps } = extractProps(props, textFieldSlotPropDefs);\n return (\n <div\n data-accent-color={color}\n data-side={side}\n {...slotProps}\n ref={forwardedRef}\n className={classNames('rt-TextFieldSlot', className)}\n />\n );\n },\n);\nTextFieldSlot.displayName = 'TextField.Slot';\n\nexport { TextFieldRoot as Root, TextFieldSlot as Slot };\nexport type { TextFieldRootProps as RootProps, TextFieldSlotProps as SlotProps };\n"],
5
5
  "mappings": "ukBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,UAAAE,EAAA,SAAAC,IAAA,eAAAC,EAAAJ,GAEA,IAAAK,EAAuB,oBACvBC,EAAuB,yBACvBC,EAA4B,6BAE5BC,EAA6D,iCAC7DC,EAA6B,uCAC7BC,EAA+B,oCA+B/B,MAAMR,EAAgBG,EAAM,WAC1B,CAACM,EAAOC,IAAiB,CACvB,MAAMC,EAAWR,EAAM,OAAyB,IAAI,EAC9C,CAAE,SAAAS,EAAU,UAAAC,EAAW,MAAAC,EAAO,OAAAC,EAAQ,gBAAAC,EAAiB,SAAAC,EAAU,MAAAC,EAAO,GAAGC,CAAW,KAC1F,gBAAaV,EAAO,wBAAuB,gBAAc,EACrDW,EAAoBH,GAAYD,EAGhCK,EAAUlB,EAAM,MAAM,EAGtBmB,EAAYH,EAAW,OAASA,EAAW,UAE3C,CAAE,mBAAoBI,EAAiB,kBAAmBC,CAAe,EAAIL,EAG7EM,EAActB,EAAM,QAAQ,IAAM,CACtC,MAAMuB,EAAQ,CAAC,EACf,OAAIP,EAAW,cAAcO,EAAM,KAAKL,CAAO,EAC3CE,GAAiBG,EAAM,KAAKH,CAAe,EACxCG,EAAM,OAAS,EAAIA,EAAM,KAAK,GAAG,EAAI,MAC9C,EAAG,CAACP,EAAW,aAAcI,EAAiBF,CAAO,CAAC,EAGhDM,EAAYxB,EAAM,QACtB,KAAO,CACL,eAAgBmB,EAChB,mBAAoBG,EACpB,kBAAmBD,CACrB,GACA,CAACF,EAAWG,EAAaD,CAAc,CACzC,EAGM,CACJ,MAAAI,EACA,aAAAC,EACA,UAAWC,EACX,SAAAC,EACA,mBAAoBC,EACpB,kBAAmBC,EACnB,GAAGC,CACL,EAAIf,EAGEgB,EAAoBhC,EAAM,YAAaiC,GAA8B,CACzE,MAAMC,EAASD,EAAM,OACrB,GAAIC,EAAO,QAAQ,kBAAkB,EAAG,OAExC,MAAMC,EAAQ3B,EAAS,QACvB,GAAI,CAAC2B,EAAO,OAQZ,MAAMC,EALcF,EAAO,QAAQ;AAAA;AAAA;AAAA,OAGlC,EAEoCC,EAAM,MAAM,OAAS,EAE1D,sBAAsB,IAAM,CAG1B,GAAI,CACFA,EAAM,kBAAkBC,EAAgBA,CAAc,CACxD,MAAQ,CAAC,CACTD,EAAM,MAAM,CACd,CAAC,CACH,EAAG,CAAC,CAAC,EAEL,OACEnC,EAAA,cAAC,OACC,oBAAmBW,EACnB,cAAaC,EACb,wBAAuBK,EACvB,gBAAeA,EACf,MAAOF,EACP,aAAW,EAAAsB,SAAW,mBAAoB3B,EAAW,CACnD,WAAYS,CACd,CAAC,EACD,cAAea,GAEfhC,EAAA,cAAC,SACC,WAAW,QACV,GAAG+B,EACH,GAAGP,EACJ,OAAK,eAAYhB,EAAUD,CAAY,EACvC,UAAU,6BACZ,EACCE,EACAO,EAAW,cACVhB,EAAA,cAAC,OAAI,GAAIkB,EAAS,UAAU,2BAA2B,KAAK,QAAQ,YAAU,UAC3EF,EAAW,YACd,CAEJ,CAEJ,CACF,EACAnB,EAAc,YAAc,iBAO5B,MAAMC,EAAgBE,EAAM,WAC1B,CAACM,EAAOC,IAAiB,CACvB,KAAM,CAAE,UAAAG,EAAW,MAAAC,EAAO,KAAA2B,EAAM,GAAGC,CAAU,KAAI,gBAAajC,EAAO,uBAAqB,EAC1F,OACEN,EAAA,cAAC,OACC,oBAAmBW,EACnB,YAAW2B,EACV,GAAGC,EACJ,IAAKhC,EACL,aAAW,EAAA8B,SAAW,mBAAoB3B,CAAS,EACrD,CAEJ,CACF,EACAZ,EAAc,YAAc",
6
6
  "names": ["text_field_exports", "__export", "TextFieldRoot", "TextFieldSlot", "__toCommonJS", "React", "import_classnames", "import_internal", "import_text_field_props", "import_extract_props", "import_margin_props", "props", "forwardedRef", "inputRef", "children", "className", "color", "radius", "panelBackground", "material", "style", "inputProps", "effectiveMaterial", "errorId", "isInvalid", "ariaDescribedby", "ariaLabelledby", "describedBy", "parts", "ariaProps", "error", "errorMessage", "_isInvalid", "required", "_ariaDescribedby", "_ariaLabelledby", "nativeInputProps", "handlePointerDown", "event", "target", "input", "cursorPosition", "classNames", "side", "slotProps"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import*as e from"react";import S from"classnames";import{imagePropDefs as z}from"./image.props.js";import{extractProps as O}from"../helpers/extract-props.js";import{marginPropDefs as R}from"../props/margin.props.js";import{widthPropDefs as q}from"../props/width.props.js";import{heightPropDefs as G}from"../props/height.props.js";import{layoutPropDefs as A}from"../props/layout.props.js";import{Skeleton as F}from"./skeleton.js";import{Slot as B}from"./slot.js";const L=e.forwardRef((b,r)=>{const{asChild:d,className:a,style:w,loading:x="lazy",alt:c,src:i,placeholder:s,showSkeleton:D=!1,fadeIn:g=!0,errorAriaLabel:C="Failed to load image",radius:N,caption:t,onLoad:f,onError:h,children:H,...y}=O(b,z,R,q,G,A),[n,l]=e.useState("loading"),[k,p]=e.useState(!!s),u=e.useRef(null),M=e.useCallback(o=>{l("loaded"),p(!1),f?.(o)},[f]),T=e.useCallback(o=>{l("error"),p(!1),h?.(o)},[h]);if(e.useEffect(()=>{const o=u.current;o&&o.complete&&o.naturalWidth>0&&(l("loaded"),p(!1))},[i]),!i)return console.warn("Image component: src prop is required"),null;!d&&c===void 0&&console.warn("Image component: alt prop is required for accessibility when not using asChild");const P=n==="loading",m=n==="error",j=n==="loaded",W={"aria-busy":P,"aria-invalid":m,"aria-describedby":m?"image-error":void 0},I={width:"100%",height:"100%",display:"block",opacity:g?j?1:0:1,transition:g?"opacity 0.3s ease-out":"none"},v=e.createElement(e.Fragment,null,e.createElement("div",{style:{position:"relative",flex:t?"1 1 0%":void 0,height:t?void 0:"100%",minHeight:0}},m&&e.createElement("div",{id:"image-error",className:"rt-sr-only","aria-live":"polite"},C),D&&P&&e.createElement(F,{width:"100%",height:"100%",style:{position:"absolute",inset:0}}),s&&k&&e.createElement("img",{style:{...I,position:"absolute",inset:0,filter:"blur(4px)",opacity:.7,zIndex:0},className:S("rt-reset","rt-Image","rt-Image--placeholder"),alt:"",src:s}),e.createElement("img",{ref:o=>{u.current=o,typeof r=="function"?r(o):r&&(r.current=o)},loading:x,style:{...I,position:"relative",zIndex:1},className:S("rt-reset","rt-Image",a),alt:c,src:i,"data-radius":N,onLoad:M,onError:T,...W})),t&&e.createElement("div",{className:"rt-Image-caption",style:{flex:"0 0 auto"}},t)),E={display:t?"flex":"block",flexDirection:t?"column":void 0,...w};return d?e.createElement(B,{className:a,style:E,...y},e.cloneElement(H,{},v)):e.createElement("div",{className:a,style:E,...y},v)});L.displayName="Image";export{L as Image};
1
+ import*as e from"react";import S from"classnames";import{imagePropDefs as z}from"./image.props.js";import{extractProps as O}from"../helpers/extract-props.js";import{marginPropDefs as R}from"../props/margin.props.js";import{widthPropDefs as q}from"../props/width.props.js";import{heightPropDefs as A}from"../props/height.props.js";import{layoutPropDefs as G}from"../props/layout.props.js";import{Skeleton as F}from"./skeleton.js";import{Slot as B}from"./slot.js";const L=e.forwardRef((b,r)=>{const{asChild:d,className:a,style:w,loading:x="lazy",alt:c,src:i,placeholder:s,showSkeleton:D=!1,fadeIn:g=!0,loadingAriaLabel:J,errorAriaLabel:C="Failed to load image",radius:N,caption:t,onLoad:f,onError:h,children:H,...y}=O(b,z,R,q,A,G),[n,l]=e.useState("loading"),[k,p]=e.useState(!!s),u=e.useRef(null),M=e.useCallback(o=>{l("loaded"),p(!1),f?.(o)},[f]),T=e.useCallback(o=>{l("error"),p(!1),h?.(o)},[h]);if(e.useEffect(()=>{const o=u.current;o&&o.complete&&o.naturalWidth>0&&(l("loaded"),p(!1))},[i]),!i)return console.warn("Image component: src prop is required"),null;!d&&c===void 0&&console.warn("Image component: alt prop is required for accessibility when not using asChild");const P=n==="loading",m=n==="error",j=n==="loaded",W={"aria-busy":P,"aria-invalid":m,"aria-describedby":m?"image-error":void 0},I={width:"100%",height:"100%",display:"block",opacity:g?j?1:0:1,transition:g?"opacity 0.3s ease-out":"none"},v=e.createElement(e.Fragment,null,e.createElement("div",{style:{position:"relative",flex:t?"1 1 0%":void 0,height:t?void 0:"100%",minHeight:0}},m&&e.createElement("div",{id:"image-error",className:"rt-sr-only","aria-live":"polite"},C),D&&P&&e.createElement(F,{width:"100%",height:"100%",style:{position:"absolute",inset:0}}),s&&k&&e.createElement("img",{style:{...I,position:"absolute",inset:0,filter:"blur(4px)",opacity:.7,zIndex:0},className:S("rt-reset","rt-Image","rt-Image--placeholder"),alt:"",src:s}),e.createElement("img",{ref:o=>{u.current=o,typeof r=="function"?r(o):r&&(r.current=o)},loading:x,style:{...I,position:"relative",zIndex:1},className:S("rt-reset","rt-Image",a),alt:c,src:i,"data-radius":N,onLoad:M,onError:T,...W})),t&&e.createElement("div",{className:"rt-Image-caption",style:{flex:"0 0 auto"}},t)),E={display:t?"flex":"block",flexDirection:t?"column":void 0,...w};return d?e.createElement(B,{className:a,style:E,...y},e.cloneElement(H,{},v)):e.createElement("div",{className:a,style:E,...y},v)});L.displayName="Image";export{L as Image};
2
2
  //# sourceMappingURL=image.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/image.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nimport classNames from 'classnames';\n\nimport { imagePropDefs } from './image.props.js';\nimport { extractProps } from '../helpers/extract-props.js';\nimport { marginPropDefs } from '../props/margin.props.js';\nimport { widthPropDefs } from '../props/width.props.js';\nimport { heightPropDefs } from '../props/height.props.js';\nimport { layoutPropDefs } from '../props/layout.props.js';\nimport { Skeleton } from './skeleton.js';\nimport { Slot } from './slot.js';\n\nimport type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';\nimport type { MarginProps } from '../props/margin.props.js';\nimport type { WidthProps } from '../props/width.props.js';\nimport type { HeightProps } from '../props/height.props.js';\nimport type { LayoutProps } from '../props/layout.props.js';\nimport type { GetPropDefTypes } from '../props/prop-def.js';\n\ntype ImageElement = React.ElementRef<'img'>;\n\n/**\n * Core Image props that extend the base image prop definitions\n * These props provide enhanced functionality beyond standard HTML img attributes\n */\ntype ImageOwnProps = GetPropDefTypes<typeof imagePropDefs> & {\n /**\n * Native loading behavior for the image\n * 'lazy' defers loading until the image is near the viewport\n * 'eager' loads the image immediately\n */\n loading?: 'eager' | 'lazy';\n /**\n * Placeholder image URL to show while the main image is loading\n *\n * Best practices:\n * - Use a low-quality/blurred version of the main image\n * - Keep file size small (under 10KB recommended)\n * - Use same aspect ratio as main image\n * - Consider using base64 data URLs for inline placeholders\n *\n * @example\n * ```tsx\n * <Image\n * src=\"/high-res-image.jpg\"\n * placeholder=\"/low-res-placeholder.jpg\"\n * alt=\"Product photo\"\n * />\n * ```\n */\n placeholder?: string;\n /**\n * Shows a skeleton placeholder while loading instead of a blank space\n *\n * Use this when:\n * - You don't have a placeholder image\n * - You want consistent loading states across your interface\n * - The image is part of a content layout that needs stable dimensions\n */\n showSkeleton?: boolean;\n /**\n * Whether the image should fade in when loaded\n *\n * Set to false for:\n * - Background images where immediate visibility is important\n * - Images that need to appear instantly for UX reasons\n * - When you're implementing custom loading animations\n */\n fadeIn?: boolean;\n /**\n * Callback fired when the image successfully loads\n *\n * Use this to:\n * - Track image loading performance\n * - Trigger layout adjustments after load\n * - Implement custom loading state management\n */\n onLoad?: (event: React.SyntheticEvent<HTMLImageElement>) => void;\n /**\n * Callback fired when the image fails to load\n *\n * Use this to:\n * - Log errors for monitoring\n * - Show fallback content\n * - Implement retry logic\n */\n onError?: (event: React.SyntheticEvent<HTMLImageElement>) => void;\n};\n\n/**\n * Complete Image component props interface\n *\n * Combines HTML img attributes with design system props and enhanced functionality.\n * Excludes conflicting props like 'color', 'width', 'height' that are handled by the design system.\n */\ninterface ImageProps\n extends ComponentPropsWithout<'img', RemovedProps | 'color' | 'width' | 'height' | 'alt'>,\n MarginProps,\n WidthProps,\n HeightProps,\n LayoutProps,\n ImageOwnProps {\n /**\n * Alternative text for the image\n *\n * Required for accessibility when not using asChild pattern.\n * Describes the image content for screen readers and when images fail to load.\n *\n * Guidelines:\n * - Be descriptive but concise\n * - Don't include \"image of\" or \"picture of\"\n * - Use empty string (\"\") for purely decorative images\n * - Describe the content and context, not just what you see\n *\n * @example\n * ```tsx\n * // Good alt text\n * <Image src=\"/chart.png\" alt=\"Sales increased 25% from Q1 to Q2\" />\n *\n * // Decorative image\n * <Image src=\"/decoration.png\" alt=\"\" />\n *\n * // Avoid generic descriptions\n * <Image src=\"/photo.jpg\" alt=\"A photo\" /> // \u274C Too generic\n * <Image src=\"/photo.jpg\" alt=\"Team celebrating project launch\" /> // \u2705 Descriptive\n * ```\n */\n alt: string;\n}\n\n/**\n * Image component for displaying images with enhanced loading states and accessibility\n *\n * The Image component extends the standard HTML img element with advanced features\n * including placeholder images, skeleton loading states, fade-in animations, and\n * comprehensive accessibility support. It integrates seamlessly with the design\n * system's layout, spacing, and theming capabilities.\n *\n * Key features:\n * - Progressive loading with placeholder and skeleton states\n * - Fade-in animations with reduced motion support\n * - Comprehensive accessibility with ARIA attributes\n * - Object-fit control for responsive image scaling\n * - Caption support for additional context\n * - AsChild pattern for flexible composition\n * - Error handling with fallback states\n * - Performance optimizations for cached images\n *\n * @example\n * ```tsx\n * // Basic usage\n * <Image src=\"/photo.jpg\" alt=\"Team photo\" />\n *\n * // With placeholder and skeleton\n * <Image\n * src=\"/high-res.jpg\"\n * placeholder=\"/low-res.jpg\"\n * showSkeleton\n * alt=\"Product showcase\"\n * />\n *\n * // With caption and custom fit\n * <Image\n * src=\"/chart.png\"\n * alt=\"Sales data visualization\"\n * caption=\"Q3 2024 Sales Performance\"\n * fit=\"contain\"\n * width=\"400px\"\n * height=\"300px\"\n * />\n *\n * // As clickable element\n * <Image\n * asChild\n * src=\"/thumbnail.jpg\"\n * alt=\"View full gallery\"\n * >\n * <a href=\"/gallery\">\n * View Gallery\n * </a>\n * </Image>\n * ```\n */\nconst Image = React.forwardRef<ImageElement, ImageProps>((props, forwardedRef) => {\n // Extract and organize props for different purposes\n const {\n asChild,\n className,\n style,\n loading = 'lazy', // Default to lazy loading for performance\n alt,\n src,\n placeholder,\n showSkeleton = false, // Default to no skeleton for simpler UX\n fadeIn = true, // Default to fade-in for smooth loading experience\n\n errorAriaLabel = 'Failed to load image',\n radius,\n caption,\n onLoad: userOnLoad,\n onError: userOnError,\n children,\n ...wrapperProps\n } = extractProps(\n props,\n imagePropDefs,\n marginPropDefs,\n widthPropDefs,\n heightPropDefs,\n layoutPropDefs,\n );\n\n // State management for loading, error, and placeholder states\n const [loadingState, setLoadingState] = React.useState<'loading' | 'loaded' | 'error'>('loading');\n const [showPlaceholder, setShowPlaceholder] = React.useState(!!placeholder);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n /**\n * Handle successful image load\n * Updates state and triggers user callback for load event\n */\n const handleLoad = React.useCallback(\n (event: React.SyntheticEvent<HTMLImageElement>) => {\n setLoadingState('loaded');\n setShowPlaceholder(false);\n // Call user's onLoad handler if provided\n userOnLoad?.(event);\n },\n [userOnLoad],\n );\n\n /**\n * Handle image load error\n * Updates state and triggers user callback for error event\n */\n const handleError = React.useCallback(\n (event: React.SyntheticEvent<HTMLImageElement>) => {\n setLoadingState('error');\n setShowPlaceholder(false);\n // Call user's onError handler if provided\n userOnError?.(event);\n },\n [userOnError],\n );\n\n /**\n * Check if image is already loaded (optimization for cached images)\n * This prevents unnecessary loading states for images that are already available\n */\n React.useEffect(() => {\n const img = imgRef.current;\n if (img && img.complete && img.naturalWidth > 0) {\n setLoadingState('loaded');\n setShowPlaceholder(false);\n }\n }, [src]);\n\n // Validate required props and provide helpful development warnings\n if (!src) {\n console.warn('Image component: src prop is required');\n return null;\n }\n\n if (!asChild && alt === undefined) {\n console.warn('Image component: alt prop is required for accessibility when not using asChild');\n }\n\n // Derive loading state flags for cleaner conditional rendering\n const isLoading = loadingState === 'loading';\n const isError = loadingState === 'error';\n const isLoaded = loadingState === 'loaded';\n\n /**\n * ARIA attributes for comprehensive accessibility support\n * These attributes help screen readers understand the image state\n */\n const ariaProps = {\n 'aria-busy': isLoading,\n 'aria-invalid': isError,\n 'aria-describedby': isError ? 'image-error' : undefined,\n };\n\n /**\n * Image styling that handles fade-in animation and responsive behavior\n * Respects user's motion preferences through CSS media queries\n */\n const imgStyle: React.CSSProperties = {\n width: '100%',\n height: '100%',\n display: 'block',\n // Conditional opacity for fade-in effect\n opacity: fadeIn ? (isLoaded ? 1 : 0) : 1,\n // Smooth transition for fade-in, respects reduced motion preferences\n transition: fadeIn ? 'opacity 0.3s ease-out' : 'none',\n };\n\n /**\n * Create the complete image content structure\n * This includes the main image, placeholder, skeleton, caption, and error states\n */\n const imageContent = (\n <>\n {/*\n * Image container - handles layout and positioning\n * Uses flex layout when caption is present for proper space distribution\n */}\n <div\n style={{\n position: 'relative',\n flex: caption ? '1 1 0%' : undefined,\n height: caption ? undefined : '100%',\n minHeight: 0, // Important for flex shrinking in constrained layouts\n }}\n >\n {/*\n * Error message for screen readers\n * Hidden visually but announced by assistive technology\n */}\n {isError && (\n <div id=\"image-error\" className=\"rt-sr-only\" aria-live=\"polite\">\n {errorAriaLabel}\n </div>\n )}\n\n {/*\n * Skeleton placeholder during loading\n * Provides visual feedback and prevents layout shift\n */}\n {showSkeleton && isLoading && (\n <Skeleton width=\"100%\" height=\"100%\" style={{ position: 'absolute', inset: 0 }} />\n )}\n\n {/*\n * Placeholder image with blur effect\n * Shows a low-quality version while the main image loads\n */}\n {placeholder && showPlaceholder && (\n <img\n style={{\n ...imgStyle,\n position: 'absolute',\n inset: 0,\n filter: 'blur(4px)', // Creates the blur effect for LQIP (Low Quality Image Placeholder)\n opacity: 0.7, // Subtle opacity to indicate it's a placeholder\n zIndex: 0, // Behind the main image\n }}\n className={classNames('rt-reset', 'rt-Image', 'rt-Image--placeholder')}\n alt=\"\" // Decorative placeholder, no alt text needed\n src={placeholder}\n />\n )}\n\n {/*\n * Main image element\n * Handles all the core functionality and user interactions\n */}\n <img\n ref={(node) => {\n // Handle both internal ref and forwarded ref\n imgRef.current = node;\n if (typeof forwardedRef === 'function') {\n forwardedRef(node);\n } else if (forwardedRef) {\n forwardedRef.current = node;\n }\n }}\n loading={loading}\n style={{ ...imgStyle, position: 'relative', zIndex: 1 }}\n className={classNames('rt-reset', 'rt-Image', className)}\n alt={alt}\n src={src}\n data-radius={radius}\n onLoad={handleLoad}\n onError={handleError}\n {...ariaProps}\n />\n </div>\n\n {/*\n * Caption element - positioned below the image\n * Takes only the space it needs, doesn't interfere with image sizing\n */}\n {caption && (\n <div className=\"rt-Image-caption\" style={{ flex: '0 0 auto' }}>\n {caption}\n </div>\n )}\n </>\n );\n\n /**\n * Container styling that adapts based on caption presence\n * Uses flexbox when caption is present for proper layout control\n */\n const containerStyle: React.CSSProperties = {\n display: caption ? 'flex' : 'block',\n flexDirection: caption ? 'column' : undefined,\n ...style, // Allow user styles to override defaults\n };\n\n /**\n * Render with asChild pattern for composition\n * This allows the Image to be rendered as a child of another element\n * while maintaining all its functionality and styling\n */\n if (asChild) {\n return (\n <Slot className={className} style={containerStyle} {...wrapperProps}>\n {React.cloneElement(children as React.ReactElement, {}, imageContent)}\n </Slot>\n );\n }\n\n /**\n * Regular rendering as a standalone div container\n * This is the default rendering mode for most use cases\n */\n return (\n <div className={className} style={containerStyle} {...wrapperProps}>\n {imageContent}\n </div>\n );\n});\n\nImage.displayName = 'Image';\n\nexport { Image };\nexport type { ImageProps };\n"],
5
- "mappings": "AAAA,UAAYA,MAAW,QACvB,OAAOC,MAAgB,aAEvB,OAAS,iBAAAC,MAAqB,mBAC9B,OAAS,gBAAAC,MAAoB,8BAC7B,OAAS,kBAAAC,MAAsB,2BAC/B,OAAS,iBAAAC,MAAqB,0BAC9B,OAAS,kBAAAC,MAAsB,2BAC/B,OAAS,kBAAAC,MAAsB,2BAC/B,OAAS,YAAAC,MAAgB,gBACzB,OAAS,QAAAC,MAAY,YA6KrB,MAAMC,EAAQV,EAAM,WAAqC,CAACW,EAAOC,IAAiB,CAEhF,KAAM,CACJ,QAAAC,EACA,UAAAC,EACA,MAAAC,EACA,QAAAC,EAAU,OACV,IAAAC,EACA,IAAAC,EACA,YAAAC,EACA,aAAAC,EAAe,GACf,OAAAC,EAAS,GAET,eAAAC,EAAiB,uBACjB,OAAAC,EACA,QAAAC,EACA,OAAQC,EACR,QAASC,EACT,SAAAC,EACA,GAAGC,CACL,EAAIzB,EACFQ,EACAT,EACAE,EACAC,EACAC,EACAC,CACF,EAGM,CAACsB,EAAcC,CAAe,EAAI9B,EAAM,SAAyC,SAAS,EAC1F,CAAC+B,EAAiBC,CAAkB,EAAIhC,EAAM,SAAS,CAAC,CAACmB,CAAW,EACpEc,EAASjC,EAAM,OAAyB,IAAI,EAM5CkC,EAAalC,EAAM,YACtBmC,GAAkD,CACjDL,EAAgB,QAAQ,EACxBE,EAAmB,EAAK,EAExBP,IAAaU,CAAK,CACpB,EACA,CAACV,CAAU,CACb,EAMMW,EAAcpC,EAAM,YACvBmC,GAAkD,CACjDL,EAAgB,OAAO,EACvBE,EAAmB,EAAK,EAExBN,IAAcS,CAAK,CACrB,EACA,CAACT,CAAW,CACd,EAeA,GATA1B,EAAM,UAAU,IAAM,CACpB,MAAMqC,EAAMJ,EAAO,QACfI,GAAOA,EAAI,UAAYA,EAAI,aAAe,IAC5CP,EAAgB,QAAQ,EACxBE,EAAmB,EAAK,EAE5B,EAAG,CAACd,CAAG,CAAC,EAGJ,CAACA,EACH,eAAQ,KAAK,uCAAuC,EAC7C,KAGL,CAACL,GAAWI,IAAQ,QACtB,QAAQ,KAAK,gFAAgF,EAI/F,MAAMqB,EAAYT,IAAiB,UAC7BU,EAAUV,IAAiB,QAC3BW,EAAWX,IAAiB,SAM5BY,EAAY,CAChB,YAAaH,EACb,eAAgBC,EAChB,mBAAoBA,EAAU,cAAgB,MAChD,EAMMG,EAAgC,CACpC,MAAO,OACP,OAAQ,OACR,QAAS,QAET,QAASrB,EAAUmB,EAAW,EAAI,EAAK,EAEvC,WAAYnB,EAAS,wBAA0B,MACjD,EAMMsB,EACJ3C,EAAA,cAAAA,EAAA,cAKEA,EAAA,cAAC,OACC,MAAO,CACL,SAAU,WACV,KAAMwB,EAAU,SAAW,OAC3B,OAAQA,EAAU,OAAY,OAC9B,UAAW,CACb,GAMCe,GACCvC,EAAA,cAAC,OAAI,GAAG,cAAc,UAAU,aAAa,YAAU,UACpDsB,CACH,EAODF,GAAgBkB,GACftC,EAAA,cAACQ,EAAA,CAAS,MAAM,OAAO,OAAO,OAAO,MAAO,CAAE,SAAU,WAAY,MAAO,CAAE,EAAG,EAOjFW,GAAeY,GACd/B,EAAA,cAAC,OACC,MAAO,CACL,GAAG0C,EACH,SAAU,WACV,MAAO,EACP,OAAQ,YACR,QAAS,GACT,OAAQ,CACV,EACA,UAAWzC,EAAW,WAAY,WAAY,uBAAuB,EACrE,IAAI,GACJ,IAAKkB,EACP,EAOFnB,EAAA,cAAC,OACC,IAAM4C,GAAS,CAEbX,EAAO,QAAUW,EACb,OAAOhC,GAAiB,WAC1BA,EAAagC,CAAI,EACRhC,IACTA,EAAa,QAAUgC,EAE3B,EACA,QAAS5B,EACT,MAAO,CAAE,GAAG0B,EAAU,SAAU,WAAY,OAAQ,CAAE,EACtD,UAAWzC,EAAW,WAAY,WAAYa,CAAS,EACvD,IAAKG,EACL,IAAKC,EACL,cAAaK,EACb,OAAQW,EACR,QAASE,EACR,GAAGK,EACN,CACF,EAMCjB,GACCxB,EAAA,cAAC,OAAI,UAAU,mBAAmB,MAAO,CAAE,KAAM,UAAW,GACzDwB,CACH,CAEJ,EAOIqB,EAAsC,CAC1C,QAASrB,EAAU,OAAS,QAC5B,cAAeA,EAAU,SAAW,OACpC,GAAGT,CACL,EAOA,OAAIF,EAEAb,EAAA,cAACS,EAAA,CAAK,UAAWK,EAAW,MAAO+B,EAAiB,GAAGjB,GACpD5B,EAAM,aAAa2B,EAAgC,CAAC,EAAGgB,CAAY,CACtE,EASF3C,EAAA,cAAC,OAAI,UAAWc,EAAW,MAAO+B,EAAiB,GAAGjB,GACnDe,CACH,CAEJ,CAAC,EAEDjC,EAAM,YAAc",
6
- "names": ["React", "classNames", "imagePropDefs", "extractProps", "marginPropDefs", "widthPropDefs", "heightPropDefs", "layoutPropDefs", "Skeleton", "Slot", "Image", "props", "forwardedRef", "asChild", "className", "style", "loading", "alt", "src", "placeholder", "showSkeleton", "fadeIn", "errorAriaLabel", "radius", "caption", "userOnLoad", "userOnError", "children", "wrapperProps", "loadingState", "setLoadingState", "showPlaceholder", "setShowPlaceholder", "imgRef", "handleLoad", "event", "handleError", "img", "isLoading", "isError", "isLoaded", "ariaProps", "imgStyle", "imageContent", "node", "containerStyle"]
4
+ "sourcesContent": ["import * as React from 'react';\nimport classNames from 'classnames';\n\nimport { imagePropDefs } from './image.props.js';\nimport { extractProps } from '../helpers/extract-props.js';\nimport { marginPropDefs } from '../props/margin.props.js';\nimport { widthPropDefs } from '../props/width.props.js';\nimport { heightPropDefs } from '../props/height.props.js';\nimport { layoutPropDefs } from '../props/layout.props.js';\nimport { Skeleton } from './skeleton.js';\nimport { Slot } from './slot.js';\n\nimport type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';\nimport type { MarginProps } from '../props/margin.props.js';\nimport type { WidthProps } from '../props/width.props.js';\nimport type { HeightProps } from '../props/height.props.js';\nimport type { LayoutProps } from '../props/layout.props.js';\nimport type { GetPropDefTypes } from '../props/prop-def.js';\n\ntype ImageElement = React.ElementRef<'img'>;\n\n/**\n * Core Image props that extend the base image prop definitions\n * These props provide enhanced functionality beyond standard HTML img attributes\n */\ntype ImageOwnProps = GetPropDefTypes<typeof imagePropDefs> & {\n /**\n * Native loading behavior for the image\n * 'lazy' defers loading until the image is near the viewport\n * 'eager' loads the image immediately\n */\n loading?: 'eager' | 'lazy';\n /**\n * Placeholder image URL to show while the main image is loading\n *\n * Best practices:\n * - Use a low-quality/blurred version of the main image\n * - Keep file size small (under 10KB recommended)\n * - Use same aspect ratio as main image\n * - Consider using base64 data URLs for inline placeholders\n *\n * @example\n * ```tsx\n * <Image\n * src=\"/high-res-image.jpg\"\n * placeholder=\"/low-res-placeholder.jpg\"\n * alt=\"Product photo\"\n * />\n * ```\n */\n placeholder?: string;\n /**\n * Shows a skeleton placeholder while loading instead of a blank space\n *\n * Use this when:\n * - You don't have a placeholder image\n * - You want consistent loading states across your interface\n * - The image is part of a content layout that needs stable dimensions\n */\n showSkeleton?: boolean;\n /**\n * Whether the image should fade in when loaded\n *\n * Set to false for:\n * - Background images where immediate visibility is important\n * - Images that need to appear instantly for UX reasons\n * - When you're implementing custom loading animations\n */\n fadeIn?: boolean;\n /**\n * Callback fired when the image successfully loads\n *\n * Use this to:\n * - Track image loading performance\n * - Trigger layout adjustments after load\n * - Implement custom loading state management\n */\n onLoad?: (event: React.SyntheticEvent<HTMLImageElement>) => void;\n /**\n * Callback fired when the image fails to load\n *\n * Use this to:\n * - Log errors for monitoring\n * - Show fallback content\n * - Implement retry logic\n */\n onError?: (event: React.SyntheticEvent<HTMLImageElement>) => void;\n};\n\n/**\n * Complete Image component props interface\n *\n * Combines HTML img attributes with design system props and enhanced functionality.\n * Excludes conflicting props like 'color', 'width', 'height' that are handled by the design system.\n */\ninterface ImageProps\n extends ComponentPropsWithout<'img', RemovedProps | 'color' | 'width' | 'height' | 'alt'>,\n MarginProps,\n WidthProps,\n HeightProps,\n LayoutProps,\n ImageOwnProps {\n /**\n * Alternative text for the image\n *\n * Required for accessibility when not using asChild pattern.\n * Describes the image content for screen readers and when images fail to load.\n *\n * Guidelines:\n * - Be descriptive but concise\n * - Don't include \"image of\" or \"picture of\"\n * - Use empty string (\"\") for purely decorative images\n * - Describe the content and context, not just what you see\n *\n * @example\n * ```tsx\n * // Good alt text\n * <Image src=\"/chart.png\" alt=\"Sales increased 25% from Q1 to Q2\" />\n *\n * // Decorative image\n * <Image src=\"/decoration.png\" alt=\"\" />\n *\n * // Avoid generic descriptions\n * <Image src=\"/photo.jpg\" alt=\"A photo\" /> // \u274C Too generic\n * <Image src=\"/photo.jpg\" alt=\"Team celebrating project launch\" /> // \u2705 Descriptive\n * ```\n */\n alt: string;\n}\n\n/**\n * Image component for displaying images with enhanced loading states and accessibility\n *\n * The Image component extends the standard HTML img element with advanced features\n * including placeholder images, skeleton loading states, fade-in animations, and\n * comprehensive accessibility support. It integrates seamlessly with the design\n * system's layout, spacing, and theming capabilities.\n *\n * Key features:\n * - Progressive loading with placeholder and skeleton states\n * - Fade-in animations with reduced motion support\n * - Comprehensive accessibility with ARIA attributes\n * - Object-fit control for responsive image scaling\n * - Caption support for additional context\n * - AsChild pattern for flexible composition\n * - Error handling with fallback states\n * - Performance optimizations for cached images\n *\n * @example\n * ```tsx\n * // Basic usage\n * <Image src=\"/photo.jpg\" alt=\"Team photo\" />\n *\n * // With placeholder and skeleton\n * <Image\n * src=\"/high-res.jpg\"\n * placeholder=\"/low-res.jpg\"\n * showSkeleton\n * alt=\"Product showcase\"\n * />\n *\n * // With caption and custom fit\n * <Image\n * src=\"/chart.png\"\n * alt=\"Sales data visualization\"\n * caption=\"Q3 2024 Sales Performance\"\n * fit=\"contain\"\n * width=\"400px\"\n * height=\"300px\"\n * />\n *\n * // As clickable element\n * <Image\n * asChild\n * src=\"/thumbnail.jpg\"\n * alt=\"View full gallery\"\n * >\n * <a href=\"/gallery\">\n * View Gallery\n * </a>\n * </Image>\n * ```\n */\nconst Image = React.forwardRef<ImageElement, ImageProps>((props, forwardedRef) => {\n // Extract and organize props for different purposes\n const {\n asChild,\n className,\n style,\n loading = 'lazy', // Default to lazy loading for performance\n alt,\n src,\n placeholder,\n showSkeleton = false, // Default to no skeleton for simpler UX\n fadeIn = true, // Default to fade-in for smooth loading experience\n loadingAriaLabel, // Extract but don't use\n errorAriaLabel = 'Failed to load image',\n radius,\n caption,\n onLoad: userOnLoad,\n onError: userOnError,\n children,\n ...wrapperProps\n } = extractProps(\n props,\n imagePropDefs,\n marginPropDefs,\n widthPropDefs,\n heightPropDefs,\n layoutPropDefs,\n );\n\n // State management for loading, error, and placeholder states\n const [loadingState, setLoadingState] = React.useState<'loading' | 'loaded' | 'error'>('loading');\n const [showPlaceholder, setShowPlaceholder] = React.useState(!!placeholder);\n const imgRef = React.useRef<HTMLImageElement>(null);\n\n /**\n * Handle successful image load\n * Updates state and triggers user callback for load event\n */\n const handleLoad = React.useCallback(\n (event: React.SyntheticEvent<HTMLImageElement>) => {\n setLoadingState('loaded');\n setShowPlaceholder(false);\n // Call user's onLoad handler if provided\n userOnLoad?.(event);\n },\n [userOnLoad],\n );\n\n /**\n * Handle image load error\n * Updates state and triggers user callback for error event\n */\n const handleError = React.useCallback(\n (event: React.SyntheticEvent<HTMLImageElement>) => {\n setLoadingState('error');\n setShowPlaceholder(false);\n // Call user's onError handler if provided\n userOnError?.(event);\n },\n [userOnError],\n );\n\n /**\n * Check if image is already loaded (optimization for cached images)\n * This prevents unnecessary loading states for images that are already available\n */\n React.useEffect(() => {\n const img = imgRef.current;\n if (img && img.complete && img.naturalWidth > 0) {\n setLoadingState('loaded');\n setShowPlaceholder(false);\n }\n }, [src]);\n\n // Validate required props and provide helpful development warnings\n if (!src) {\n console.warn('Image component: src prop is required');\n return null;\n }\n\n if (!asChild && alt === undefined) {\n console.warn('Image component: alt prop is required for accessibility when not using asChild');\n }\n\n // Derive loading state flags for cleaner conditional rendering\n const isLoading = loadingState === 'loading';\n const isError = loadingState === 'error';\n const isLoaded = loadingState === 'loaded';\n\n /**\n * ARIA attributes for comprehensive accessibility support\n * These attributes help screen readers understand the image state\n */\n const ariaProps = {\n 'aria-busy': isLoading,\n 'aria-invalid': isError,\n 'aria-describedby': isError ? 'image-error' : undefined,\n };\n\n /**\n * Image styling that handles fade-in animation and responsive behavior\n * Respects user's motion preferences through CSS media queries\n */\n const imgStyle: React.CSSProperties = {\n width: '100%',\n height: '100%',\n display: 'block',\n // Conditional opacity for fade-in effect\n opacity: fadeIn ? (isLoaded ? 1 : 0) : 1,\n // Smooth transition for fade-in, respects reduced motion preferences\n transition: fadeIn ? 'opacity 0.3s ease-out' : 'none',\n };\n\n /**\n * Create the complete image content structure\n * This includes the main image, placeholder, skeleton, caption, and error states\n */\n const imageContent = (\n <>\n {/*\n * Image container - handles layout and positioning\n * Uses flex layout when caption is present for proper space distribution\n */}\n <div\n style={{\n position: 'relative',\n flex: caption ? '1 1 0%' : undefined,\n height: caption ? undefined : '100%',\n minHeight: 0, // Important for flex shrinking in constrained layouts\n }}\n >\n {/*\n * Error message for screen readers\n * Hidden visually but announced by assistive technology\n */}\n {isError && (\n <div id=\"image-error\" className=\"rt-sr-only\" aria-live=\"polite\">\n {errorAriaLabel}\n </div>\n )}\n\n {/*\n * Skeleton placeholder during loading\n * Provides visual feedback and prevents layout shift\n */}\n {showSkeleton && isLoading && (\n <Skeleton width=\"100%\" height=\"100%\" style={{ position: 'absolute', inset: 0 }} />\n )}\n\n {/*\n * Placeholder image with blur effect\n * Shows a low-quality version while the main image loads\n */}\n {placeholder && showPlaceholder && (\n <img\n style={{\n ...imgStyle,\n position: 'absolute',\n inset: 0,\n filter: 'blur(4px)', // Creates the blur effect for LQIP (Low Quality Image Placeholder)\n opacity: 0.7, // Subtle opacity to indicate it's a placeholder\n zIndex: 0, // Behind the main image\n }}\n className={classNames('rt-reset', 'rt-Image', 'rt-Image--placeholder')}\n alt=\"\" // Decorative placeholder, no alt text needed\n src={placeholder}\n />\n )}\n\n {/*\n * Main image element\n * Handles all the core functionality and user interactions\n */}\n <img\n ref={(node) => {\n // Handle both internal ref and forwarded ref\n imgRef.current = node;\n if (typeof forwardedRef === 'function') {\n forwardedRef(node);\n } else if (forwardedRef) {\n forwardedRef.current = node;\n }\n }}\n loading={loading}\n style={{ ...imgStyle, position: 'relative', zIndex: 1 }}\n className={classNames('rt-reset', 'rt-Image', className)}\n alt={alt}\n src={src}\n data-radius={radius}\n onLoad={handleLoad}\n onError={handleError}\n {...ariaProps}\n />\n </div>\n\n {/*\n * Caption element - positioned below the image\n * Takes only the space it needs, doesn't interfere with image sizing\n */}\n {caption && (\n <div className=\"rt-Image-caption\" style={{ flex: '0 0 auto' }}>\n {caption}\n </div>\n )}\n </>\n );\n\n /**\n * Container styling that adapts based on caption presence\n * Uses flexbox when caption is present for proper layout control\n */\n const containerStyle: React.CSSProperties = {\n display: caption ? 'flex' : 'block',\n flexDirection: caption ? 'column' : undefined,\n ...style, // Allow user styles to override defaults\n };\n\n /**\n * Render with asChild pattern for composition\n * This allows the Image to be rendered as a child of another element\n * while maintaining all its functionality and styling\n */\n if (asChild) {\n return (\n <Slot className={className} style={containerStyle} {...wrapperProps}>\n {React.cloneElement(children as React.ReactElement, {}, imageContent)}\n </Slot>\n );\n }\n\n /**\n * Regular rendering as a standalone div container\n * This is the default rendering mode for most use cases\n */\n return (\n <div className={className} style={containerStyle} {...wrapperProps}>\n {imageContent}\n </div>\n );\n});\n\nImage.displayName = 'Image';\n\nexport { Image };\nexport type { ImageProps };\n"],
5
+ "mappings": "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",
6
+ "names": ["React", "classNames", "imagePropDefs", "extractProps", "marginPropDefs", "widthPropDefs", "heightPropDefs", "layoutPropDefs", "Skeleton", "Slot", "Image", "props", "forwardedRef", "asChild", "className", "style", "loading", "alt", "src", "placeholder", "showSkeleton", "fadeIn", "loadingAriaLabel", "errorAriaLabel", "radius", "caption", "userOnLoad", "userOnError", "children", "wrapperProps", "loadingState", "setLoadingState", "showPlaceholder", "setShowPlaceholder", "imgRef", "handleLoad", "event", "handleError", "img", "isLoading", "isError", "isLoaded", "ariaProps", "imgStyle", "imageContent", "node", "containerStyle"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/text-area.tsx"],
4
- "sourcesContent": ["import * as React from 'react';\nimport classNames from 'classnames';\n\nimport { textAreaPropDefs } from './text-area.props.js';\nimport { extractProps } from '../helpers/extract-props.js';\nimport { marginPropDefs } from '../props/margin.props.js';\n\nimport type { MarginProps } from '../props/margin.props.js';\nimport type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';\nimport type { GetPropDefTypes } from '../props/prop-def.js';\n\ntype TextAreaElement = React.ElementRef<'textarea'>;\ntype TextAreaOwnProps = GetPropDefTypes<typeof textAreaPropDefs> & {\n defaultValue?: string;\n value?: string;\n};\ninterface TextAreaProps\n extends ComponentPropsWithout<'textarea', RemovedProps | 'size' | 'value'>,\n MarginProps,\n TextAreaOwnProps {}\n\nconst TextArea = React.forwardRef<TextAreaElement, TextAreaProps>((props, forwardedRef) => {\n const { className, color, radius, panelBackground, material, style, ...textAreaProps } =\n extractProps(props, textAreaPropDefs, marginPropDefs);\n const effectiveMaterial = material || panelBackground;\n\n // Generate unique IDs for accessibility\n const errorId = React.useId();\n\n const { 'aria-describedby': ariaDescribedby, 'aria-labelledby': ariaLabelledby } = textAreaProps;\n \n // Determine invalid state\n const isInvalid = textAreaProps.error || textAreaProps.isInvalid;\n\n // Build aria-describedby string\n const describedBy = React.useMemo(() => {\n const parts = [];\n if (textAreaProps.errorMessage) parts.push(errorId);\n if (ariaDescribedby) parts.push(ariaDescribedby);\n return parts.length > 0 ? parts.join(' ') : undefined;\n }, [textAreaProps.errorMessage, ariaDescribedby, errorId]);\n\n // Build aria attributes\n const ariaProps = React.useMemo(\n () => ({\n 'aria-invalid': isInvalid,\n 'aria-describedby': describedBy,\n 'aria-labelledby': ariaLabelledby,\n }),\n [isInvalid, describedBy, ariaLabelledby],\n );\n\n // Filter out our custom props to avoid DOM warnings\n const {\n error,\n errorMessage,\n isInvalid: _isInvalid,\n required,\n 'aria-describedby': _ariaDescribedby,\n 'aria-labelledby': _ariaLabelledby,\n ...nativeTextAreaProps\n } = textAreaProps;\n\n return (\n <div\n data-accent-color={color}\n data-radius={radius}\n data-panel-background={effectiveMaterial}\n data-material={effectiveMaterial}\n className={classNames('rt-TextAreaRoot', className, {\n 'rt-error': isInvalid,\n })}\n style={style}\n >\n <textarea\n className=\"rt-reset rt-TextAreaInput\"\n ref={forwardedRef}\n {...nativeTextAreaProps}\n {...ariaProps}\n />\n {textAreaProps.errorMessage && (\n <div id={errorId} className=\"rt-TextAreaErrorMessage\" role=\"alert\" aria-live=\"polite\">\n {textAreaProps.errorMessage}\n </div>\n )}\n </div>\n );\n});\n\nTextArea.displayName = 'TextArea';\n\nexport { TextArea };\nexport type { TextAreaProps };\n"],
4
+ "sourcesContent": ["import * as React from 'react';\nimport classNames from 'classnames';\n\nimport { textAreaPropDefs } from './text-area.props.js';\nimport { extractProps } from '../helpers/extract-props.js';\nimport { marginPropDefs } from '../props/margin.props.js';\n\nimport type { MarginProps } from '../props/margin.props.js';\nimport type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';\nimport type { GetPropDefTypes } from '../props/prop-def.js';\n\ntype TextAreaElement = React.ElementRef<'textarea'>;\ntype TextAreaOwnProps = GetPropDefTypes<typeof textAreaPropDefs> & {\n defaultValue?: string;\n value?: string;\n};\ninterface TextAreaProps\n extends ComponentPropsWithout<'textarea', RemovedProps | 'size' | 'value'>,\n MarginProps,\n TextAreaOwnProps {}\n\nconst TextArea = React.forwardRef<TextAreaElement, TextAreaProps>((props, forwardedRef) => {\n const { className, color, radius, panelBackground, material, style, ...textAreaProps } =\n extractProps(props, textAreaPropDefs, marginPropDefs);\n const effectiveMaterial = material || panelBackground;\n\n // Generate unique IDs for accessibility\n const errorId = React.useId();\n\n const { 'aria-describedby': ariaDescribedby, 'aria-labelledby': ariaLabelledby } = textAreaProps;\n\n // Determine invalid state\n const isInvalid = textAreaProps.error || textAreaProps.isInvalid;\n\n // Build aria-describedby string\n const describedBy = React.useMemo(() => {\n const parts = [];\n if (textAreaProps.errorMessage) parts.push(errorId);\n if (ariaDescribedby) parts.push(ariaDescribedby);\n return parts.length > 0 ? parts.join(' ') : undefined;\n }, [textAreaProps.errorMessage, ariaDescribedby, errorId]);\n\n // Build aria attributes\n const ariaProps = React.useMemo(\n () => ({\n 'aria-invalid': isInvalid,\n 'aria-describedby': describedBy,\n 'aria-labelledby': ariaLabelledby,\n }),\n [isInvalid, describedBy, ariaLabelledby],\n );\n\n // Filter out our custom props to avoid DOM warnings\n const {\n error,\n errorMessage,\n isInvalid: _isInvalid,\n required,\n 'aria-describedby': _ariaDescribedby,\n 'aria-labelledby': _ariaLabelledby,\n ...nativeTextAreaProps\n } = textAreaProps;\n\n return (\n <div\n data-accent-color={color}\n data-radius={radius}\n data-panel-background={effectiveMaterial}\n data-material={effectiveMaterial}\n className={classNames('rt-TextAreaRoot', className, {\n 'rt-error': isInvalid,\n })}\n style={style}\n >\n <textarea\n className=\"rt-reset rt-TextAreaInput\"\n ref={forwardedRef}\n {...nativeTextAreaProps}\n {...ariaProps}\n />\n {textAreaProps.errorMessage && (\n <div id={errorId} className=\"rt-TextAreaErrorMessage\" role=\"alert\" aria-live=\"polite\">\n {textAreaProps.errorMessage}\n </div>\n )}\n </div>\n );\n});\n\nTextArea.displayName = 'TextArea';\n\nexport { TextArea };\nexport type { TextAreaProps };\n"],
5
5
  "mappings": "AAAA,UAAYA,MAAW,QACvB,OAAOC,MAAgB,aAEvB,OAAS,oBAAAC,MAAwB,uBACjC,OAAS,gBAAAC,MAAoB,8BAC7B,OAAS,kBAAAC,MAAsB,2BAgB/B,MAAMC,EAAWL,EAAM,WAA2C,CAACM,EAAOC,IAAiB,CACzF,KAAM,CAAE,UAAAC,EAAW,MAAAC,EAAO,OAAAC,EAAQ,gBAAAC,EAAiB,SAAAC,EAAU,MAAAC,EAAO,GAAGC,CAAc,EACnFX,EAAaG,EAAOJ,EAAkBE,CAAc,EAChDW,EAAoBH,GAAYD,EAGhCK,EAAUhB,EAAM,MAAM,EAEtB,CAAE,mBAAoBiB,EAAiB,kBAAmBC,CAAe,EAAIJ,EAG7EK,EAAYL,EAAc,OAASA,EAAc,UAGjDM,EAAcpB,EAAM,QAAQ,IAAM,CACtC,MAAMqB,EAAQ,CAAC,EACf,OAAIP,EAAc,cAAcO,EAAM,KAAKL,CAAO,EAC9CC,GAAiBI,EAAM,KAAKJ,CAAe,EACxCI,EAAM,OAAS,EAAIA,EAAM,KAAK,GAAG,EAAI,MAC9C,EAAG,CAACP,EAAc,aAAcG,EAAiBD,CAAO,CAAC,EAGnDM,EAAYtB,EAAM,QACtB,KAAO,CACL,eAAgBmB,EAChB,mBAAoBC,EACpB,kBAAmBF,CACrB,GACA,CAACC,EAAWC,EAAaF,CAAc,CACzC,EAGM,CACJ,MAAAK,EACA,aAAAC,EACA,UAAWC,EACX,SAAAC,EACA,mBAAoBC,EACpB,kBAAmBC,EACnB,GAAGC,CACL,EAAIf,EAEJ,OACEd,EAAA,cAAC,OACC,oBAAmBS,EACnB,cAAaC,EACb,wBAAuBK,EACvB,gBAAeA,EACf,UAAWd,EAAW,kBAAmBO,EAAW,CAClD,WAAYW,CACd,CAAC,EACD,MAAON,GAEPb,EAAA,cAAC,YACC,UAAU,4BACV,IAAKO,EACJ,GAAGsB,EACH,GAAGP,EACN,EACCR,EAAc,cACbd,EAAA,cAAC,OAAI,GAAIgB,EAAS,UAAU,0BAA0B,KAAK,QAAQ,YAAU,UAC1EF,EAAc,YACjB,CAEJ,CAEJ,CAAC,EAEDT,EAAS,YAAc",
6
6
  "names": ["React", "classNames", "textAreaPropDefs", "extractProps", "marginPropDefs", "TextArea", "props", "forwardedRef", "className", "color", "radius", "panelBackground", "material", "style", "textAreaProps", "effectiveMaterial", "errorId", "ariaDescribedby", "ariaLabelledby", "isInvalid", "describedBy", "parts", "ariaProps", "error", "errorMessage", "_isInvalid", "required", "_ariaDescribedby", "_ariaLabelledby", "nativeTextAreaProps"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/text-field.tsx"],
4
- "sourcesContent": ["'use client';\n\nimport * as React from 'react';\nimport classNames from 'classnames';\nimport { composeRefs } from 'radix-ui/internal';\n\nimport { textFieldRootPropDefs, textFieldSlotPropDefs } from './text-field.props.js';\nimport { extractProps } from '../helpers/extract-props.js';\nimport { marginPropDefs } from '../props/margin.props.js';\n\nimport type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';\nimport type { NotInputTextualAttributes } from '../helpers/input-attributes.js';\nimport type { MarginProps } from '../props/margin.props.js';\nimport type { GetPropDefTypes } from '../props/prop-def.js';\n\ntype TextFieldRootElement = React.ElementRef<'input'>;\ntype TextFieldRootOwnProps = GetPropDefTypes<typeof textFieldRootPropDefs> & {\n defaultValue?: string | number;\n value?: string | number;\n type?:\n | 'date'\n | 'datetime-local'\n | 'email'\n | 'hidden'\n | 'month'\n | 'number'\n | 'password'\n | 'search'\n | 'tel'\n | 'text'\n | 'time'\n | 'url'\n | 'week';\n};\ntype TextFieldInputProps = ComponentPropsWithout<\n 'input',\n NotInputTextualAttributes | 'color' | 'defaultValue' | 'size' | 'type' | 'value'\n>;\ninterface TextFieldRootProps extends TextFieldInputProps, MarginProps, TextFieldRootOwnProps {}\nconst TextFieldRoot = React.forwardRef<TextFieldRootElement, TextFieldRootProps>(\n (props, forwardedRef) => {\n const inputRef = React.useRef<HTMLInputElement>(null);\n const { children, className, color, radius, panelBackground, material, style, ...inputProps } =\n extractProps(props, textFieldRootPropDefs, marginPropDefs);\n const effectiveMaterial = material || panelBackground;\n\n // Generate unique IDs for accessibility\n const errorId = React.useId();\n\n // Determine invalid state\n const isInvalid = inputProps.error || inputProps.isInvalid;\n\n const { 'aria-describedby': ariaDescribedby, 'aria-labelledby': ariaLabelledby } = inputProps;\n \n // Build aria-describedby string\n const describedBy = React.useMemo(() => {\n const parts = [];\n if (inputProps.errorMessage) parts.push(errorId);\n if (ariaDescribedby) parts.push(ariaDescribedby);\n return parts.length > 0 ? parts.join(' ') : undefined;\n }, [inputProps.errorMessage, ariaDescribedby, errorId]);\n\n // Build aria attributes\n const ariaProps = React.useMemo(\n () => ({\n 'aria-invalid': isInvalid,\n 'aria-describedby': describedBy,\n 'aria-labelledby': ariaLabelledby,\n }),\n [isInvalid, describedBy, ariaLabelledby],\n );\n\n // Filter out our custom props to avoid DOM warnings\n const {\n error,\n errorMessage,\n isInvalid: _isInvalid,\n required,\n 'aria-describedby': _ariaDescribedby,\n 'aria-labelledby': _ariaLabelledby,\n ...nativeInputProps\n } = inputProps;\n\n // Memoized pointer event handler\n const handlePointerDown = React.useCallback((event: React.PointerEvent) => {\n const target = event.target as HTMLElement;\n if (target.closest('input, button, a')) return;\n\n const input = inputRef.current;\n if (!input) return;\n\n // Same selector as in the CSS to find the right slot\n const isRightSlot = target.closest(`\n .rt-TextFieldSlot[data-side='right'],\n .rt-TextFieldSlot:not([data-side='right']) ~ .rt-TextFieldSlot:not([data-side='left'])\n `);\n\n const cursorPosition = isRightSlot ? input.value.length : 0;\n\n requestAnimationFrame(() => {\n // Only some input types support this, browsers will throw an error if not supported\n // See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange#:~:text=Note%20that%20according,not%20support%20selection%22.\n try {\n input.setSelectionRange(cursorPosition, cursorPosition);\n } catch {}\n input.focus();\n });\n }, []);\n\n return (\n <div\n data-accent-color={color}\n data-radius={radius}\n data-panel-background={effectiveMaterial}\n data-material={effectiveMaterial}\n style={style}\n className={classNames('rt-TextFieldRoot', className, {\n 'rt-error': isInvalid,\n })}\n onPointerDown={handlePointerDown}\n >\n <input\n spellCheck=\"false\"\n {...nativeInputProps}\n {...ariaProps}\n ref={composeRefs(inputRef, forwardedRef)}\n className=\"rt-reset rt-TextFieldInput\"\n />\n {children}\n {inputProps.errorMessage && (\n <div id={errorId} className=\"rt-TextFieldErrorMessage\" role=\"alert\" aria-live=\"polite\">\n {inputProps.errorMessage}\n </div>\n )}\n </div>\n );\n },\n);\nTextFieldRoot.displayName = 'TextField.Root';\n\ntype TextFieldSlotElement = React.ElementRef<'div'>;\ntype TextFieldSlotOwnProps = GetPropDefTypes<typeof textFieldSlotPropDefs>;\ninterface TextFieldSlotProps\n extends ComponentPropsWithout<'div', RemovedProps>,\n TextFieldSlotOwnProps {}\nconst TextFieldSlot = React.forwardRef<TextFieldSlotElement, TextFieldSlotProps>(\n (props, forwardedRef) => {\n const { className, color, side, ...slotProps } = extractProps(props, textFieldSlotPropDefs);\n return (\n <div\n data-accent-color={color}\n data-side={side}\n {...slotProps}\n ref={forwardedRef}\n className={classNames('rt-TextFieldSlot', className)}\n />\n );\n },\n);\nTextFieldSlot.displayName = 'TextField.Slot';\n\nexport { TextFieldRoot as Root, TextFieldSlot as Slot };\nexport type { TextFieldRootProps as RootProps, TextFieldSlotProps as SlotProps };\n"],
4
+ "sourcesContent": ["'use client';\n\nimport * as React from 'react';\nimport classNames from 'classnames';\nimport { composeRefs } from 'radix-ui/internal';\n\nimport { textFieldRootPropDefs, textFieldSlotPropDefs } from './text-field.props.js';\nimport { extractProps } from '../helpers/extract-props.js';\nimport { marginPropDefs } from '../props/margin.props.js';\n\nimport type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';\nimport type { NotInputTextualAttributes } from '../helpers/input-attributes.js';\nimport type { MarginProps } from '../props/margin.props.js';\nimport type { GetPropDefTypes } from '../props/prop-def.js';\n\ntype TextFieldRootElement = React.ElementRef<'input'>;\ntype TextFieldRootOwnProps = GetPropDefTypes<typeof textFieldRootPropDefs> & {\n defaultValue?: string | number;\n value?: string | number;\n type?:\n | 'date'\n | 'datetime-local'\n | 'email'\n | 'hidden'\n | 'month'\n | 'number'\n | 'password'\n | 'search'\n | 'tel'\n | 'text'\n | 'time'\n | 'url'\n | 'week';\n};\ntype TextFieldInputProps = ComponentPropsWithout<\n 'input',\n NotInputTextualAttributes | 'color' | 'defaultValue' | 'size' | 'type' | 'value'\n>;\ninterface TextFieldRootProps extends TextFieldInputProps, MarginProps, TextFieldRootOwnProps {}\nconst TextFieldRoot = React.forwardRef<TextFieldRootElement, TextFieldRootProps>(\n (props, forwardedRef) => {\n const inputRef = React.useRef<HTMLInputElement>(null);\n const { children, className, color, radius, panelBackground, material, style, ...inputProps } =\n extractProps(props, textFieldRootPropDefs, marginPropDefs);\n const effectiveMaterial = material || panelBackground;\n\n // Generate unique IDs for accessibility\n const errorId = React.useId();\n\n // Determine invalid state\n const isInvalid = inputProps.error || inputProps.isInvalid;\n\n const { 'aria-describedby': ariaDescribedby, 'aria-labelledby': ariaLabelledby } = inputProps;\n\n // Build aria-describedby string\n const describedBy = React.useMemo(() => {\n const parts = [];\n if (inputProps.errorMessage) parts.push(errorId);\n if (ariaDescribedby) parts.push(ariaDescribedby);\n return parts.length > 0 ? parts.join(' ') : undefined;\n }, [inputProps.errorMessage, ariaDescribedby, errorId]);\n\n // Build aria attributes\n const ariaProps = React.useMemo(\n () => ({\n 'aria-invalid': isInvalid,\n 'aria-describedby': describedBy,\n 'aria-labelledby': ariaLabelledby,\n }),\n [isInvalid, describedBy, ariaLabelledby],\n );\n\n // Filter out our custom props to avoid DOM warnings\n const {\n error,\n errorMessage,\n isInvalid: _isInvalid,\n required,\n 'aria-describedby': _ariaDescribedby,\n 'aria-labelledby': _ariaLabelledby,\n ...nativeInputProps\n } = inputProps;\n\n // Memoized pointer event handler\n const handlePointerDown = React.useCallback((event: React.PointerEvent) => {\n const target = event.target as HTMLElement;\n if (target.closest('input, button, a')) return;\n\n const input = inputRef.current;\n if (!input) return;\n\n // Same selector as in the CSS to find the right slot\n const isRightSlot = target.closest(`\n .rt-TextFieldSlot[data-side='right'],\n .rt-TextFieldSlot:not([data-side='right']) ~ .rt-TextFieldSlot:not([data-side='left'])\n `);\n\n const cursorPosition = isRightSlot ? input.value.length : 0;\n\n requestAnimationFrame(() => {\n // Only some input types support this, browsers will throw an error if not supported\n // See: https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange#:~:text=Note%20that%20according,not%20support%20selection%22.\n try {\n input.setSelectionRange(cursorPosition, cursorPosition);\n } catch {}\n input.focus();\n });\n }, []);\n\n return (\n <div\n data-accent-color={color}\n data-radius={radius}\n data-panel-background={effectiveMaterial}\n data-material={effectiveMaterial}\n style={style}\n className={classNames('rt-TextFieldRoot', className, {\n 'rt-error': isInvalid,\n })}\n onPointerDown={handlePointerDown}\n >\n <input\n spellCheck=\"false\"\n {...nativeInputProps}\n {...ariaProps}\n ref={composeRefs(inputRef, forwardedRef)}\n className=\"rt-reset rt-TextFieldInput\"\n />\n {children}\n {inputProps.errorMessage && (\n <div id={errorId} className=\"rt-TextFieldErrorMessage\" role=\"alert\" aria-live=\"polite\">\n {inputProps.errorMessage}\n </div>\n )}\n </div>\n );\n },\n);\nTextFieldRoot.displayName = 'TextField.Root';\n\ntype TextFieldSlotElement = React.ElementRef<'div'>;\ntype TextFieldSlotOwnProps = GetPropDefTypes<typeof textFieldSlotPropDefs>;\ninterface TextFieldSlotProps\n extends ComponentPropsWithout<'div', RemovedProps>,\n TextFieldSlotOwnProps {}\nconst TextFieldSlot = React.forwardRef<TextFieldSlotElement, TextFieldSlotProps>(\n (props, forwardedRef) => {\n const { className, color, side, ...slotProps } = extractProps(props, textFieldSlotPropDefs);\n return (\n <div\n data-accent-color={color}\n data-side={side}\n {...slotProps}\n ref={forwardedRef}\n className={classNames('rt-TextFieldSlot', className)}\n />\n );\n },\n);\nTextFieldSlot.displayName = 'TextField.Slot';\n\nexport { TextFieldRoot as Root, TextFieldSlot as Slot };\nexport type { TextFieldRootProps as RootProps, TextFieldSlotProps as SlotProps };\n"],
5
5
  "mappings": "aAEA,UAAYA,MAAW,QACvB,OAAOC,MAAgB,aACvB,OAAS,eAAAC,MAAmB,oBAE5B,OAAS,yBAAAC,EAAuB,yBAAAC,MAA6B,wBAC7D,OAAS,gBAAAC,MAAoB,8BAC7B,OAAS,kBAAAC,MAAsB,2BA+B/B,MAAMC,EAAgBP,EAAM,WAC1B,CAACQ,EAAOC,IAAiB,CACvB,MAAMC,EAAWV,EAAM,OAAyB,IAAI,EAC9C,CAAE,SAAAW,EAAU,UAAAC,EAAW,MAAAC,EAAO,OAAAC,EAAQ,gBAAAC,EAAiB,SAAAC,EAAU,MAAAC,EAAO,GAAGC,CAAW,EAC1Fb,EAAaG,EAAOL,EAAuBG,CAAc,EACrDa,EAAoBH,GAAYD,EAGhCK,EAAUpB,EAAM,MAAM,EAGtBqB,EAAYH,EAAW,OAASA,EAAW,UAE3C,CAAE,mBAAoBI,EAAiB,kBAAmBC,CAAe,EAAIL,EAG7EM,EAAcxB,EAAM,QAAQ,IAAM,CACtC,MAAMyB,EAAQ,CAAC,EACf,OAAIP,EAAW,cAAcO,EAAM,KAAKL,CAAO,EAC3CE,GAAiBG,EAAM,KAAKH,CAAe,EACxCG,EAAM,OAAS,EAAIA,EAAM,KAAK,GAAG,EAAI,MAC9C,EAAG,CAACP,EAAW,aAAcI,EAAiBF,CAAO,CAAC,EAGhDM,EAAY1B,EAAM,QACtB,KAAO,CACL,eAAgBqB,EAChB,mBAAoBG,EACpB,kBAAmBD,CACrB,GACA,CAACF,EAAWG,EAAaD,CAAc,CACzC,EAGM,CACJ,MAAAI,EACA,aAAAC,EACA,UAAWC,EACX,SAAAC,EACA,mBAAoBC,EACpB,kBAAmBC,EACnB,GAAGC,CACL,EAAIf,EAGEgB,EAAoBlC,EAAM,YAAamC,GAA8B,CACzE,MAAMC,EAASD,EAAM,OACrB,GAAIC,EAAO,QAAQ,kBAAkB,EAAG,OAExC,MAAMC,EAAQ3B,EAAS,QACvB,GAAI,CAAC2B,EAAO,OAQZ,MAAMC,EALcF,EAAO,QAAQ;AAAA;AAAA;AAAA,OAGlC,EAEoCC,EAAM,MAAM,OAAS,EAE1D,sBAAsB,IAAM,CAG1B,GAAI,CACFA,EAAM,kBAAkBC,EAAgBA,CAAc,CACxD,MAAQ,CAAC,CACTD,EAAM,MAAM,CACd,CAAC,CACH,EAAG,CAAC,CAAC,EAEL,OACErC,EAAA,cAAC,OACC,oBAAmBa,EACnB,cAAaC,EACb,wBAAuBK,EACvB,gBAAeA,EACf,MAAOF,EACP,UAAWhB,EAAW,mBAAoBW,EAAW,CACnD,WAAYS,CACd,CAAC,EACD,cAAea,GAEflC,EAAA,cAAC,SACC,WAAW,QACV,GAAGiC,EACH,GAAGP,EACJ,IAAKxB,EAAYQ,EAAUD,CAAY,EACvC,UAAU,6BACZ,EACCE,EACAO,EAAW,cACVlB,EAAA,cAAC,OAAI,GAAIoB,EAAS,UAAU,2BAA2B,KAAK,QAAQ,YAAU,UAC3EF,EAAW,YACd,CAEJ,CAEJ,CACF,EACAX,EAAc,YAAc,iBAO5B,MAAMgC,EAAgBvC,EAAM,WAC1B,CAACQ,EAAOC,IAAiB,CACvB,KAAM,CAAE,UAAAG,EAAW,MAAAC,EAAO,KAAA2B,EAAM,GAAGC,CAAU,EAAIpC,EAAaG,EAAOJ,CAAqB,EAC1F,OACEJ,EAAA,cAAC,OACC,oBAAmBa,EACnB,YAAW2B,EACV,GAAGC,EACJ,IAAKhC,EACL,UAAWR,EAAW,mBAAoBW,CAAS,EACrD,CAEJ,CACF,EACA2B,EAAc,YAAc",
6
6
  "names": ["React", "classNames", "composeRefs", "textFieldRootPropDefs", "textFieldSlotPropDefs", "extractProps", "marginPropDefs", "TextFieldRoot", "props", "forwardedRef", "inputRef", "children", "className", "color", "radius", "panelBackground", "material", "style", "inputProps", "effectiveMaterial", "errorId", "isInvalid", "ariaDescribedby", "ariaLabelledby", "describedBy", "parts", "ariaProps", "error", "errorMessage", "_isInvalid", "required", "_ariaDescribedby", "_ariaLabelledby", "nativeInputProps", "handlePointerDown", "event", "target", "input", "cursorPosition", "TextFieldSlot", "side", "slotProps"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kushagradhawan/kookie-ui",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "description": "A modern React component library with beautiful design tokens, flexible theming, and comprehensive docs",
5
5
  "keywords": [
6
6
  "react",
@@ -193,7 +193,7 @@ const Image = React.forwardRef<ImageElement, ImageProps>((props, forwardedRef) =
193
193
  placeholder,
194
194
  showSkeleton = false, // Default to no skeleton for simpler UX
195
195
  fadeIn = true, // Default to fade-in for smooth loading experience
196
-
196
+ loadingAriaLabel, // Extract but don't use
197
197
  errorAriaLabel = 'Failed to load image',
198
198
  radius,
199
199
  caption,
@@ -28,7 +28,7 @@ const TextArea = React.forwardRef<TextAreaElement, TextAreaProps>((props, forwar
28
28
  const errorId = React.useId();
29
29
 
30
30
  const { 'aria-describedby': ariaDescribedby, 'aria-labelledby': ariaLabelledby } = textAreaProps;
31
-
31
+
32
32
  // Determine invalid state
33
33
  const isInvalid = textAreaProps.error || textAreaProps.isInvalid;
34
34
 
@@ -51,7 +51,7 @@ const TextFieldRoot = React.forwardRef<TextFieldRootElement, TextFieldRootProps>
51
51
  const isInvalid = inputProps.error || inputProps.isInvalid;
52
52
 
53
53
  const { 'aria-describedby': ariaDescribedby, 'aria-labelledby': ariaLabelledby } = inputProps;
54
-
54
+
55
55
  // Build aria-describedby string
56
56
  const describedBy = React.useMemo(() => {
57
57
  const parts = [];