@appforgeapps/uiforge 0.5.5 → 0.5.6
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.
- package/README.md +20 -1
- package/dist/index.d.ts +432 -0
- package/dist/uiforge.cjs +4 -4
- package/dist/uiforge.css +1 -1
- package/dist/uiforge.js +1113 -939
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1711,8 +1711,25 @@ UIForge components support comprehensive theming through CSS variables. See [THE
|
|
|
1711
1711
|
- CSS variable reference
|
|
1712
1712
|
- System preference detection
|
|
1713
1713
|
- Advanced customization techniques
|
|
1714
|
+
- **Example app themes** - Learn from real-world examples like the NexaLive music streaming app theme
|
|
1714
1715
|
|
|
1715
|
-
|
|
1716
|
+
### Example App Themes
|
|
1717
|
+
|
|
1718
|
+
UIForge provides concrete example themes in `examples/themes/` to demonstrate how to create custom themes for real applications:
|
|
1719
|
+
|
|
1720
|
+
- **NexaLive Theme** (`examples/themes/nexalive-theme.css`) - A purple/pink themed music streaming app example based on the [chriscase/nexalive](https://github.com/chriscase/nexalive) project
|
|
1721
|
+
|
|
1722
|
+
**Important:** Example themes are for **demonstration only**. Copy them into your own application and customize the colors to match your brand. See [THEMING.md - Example App Themes](./THEMING.md#example-app-themes) for detailed adoption instructions.
|
|
1723
|
+
|
|
1724
|
+
Quick example of import order:
|
|
1725
|
+
|
|
1726
|
+
```tsx
|
|
1727
|
+
// Import UIForge core styles FIRST, then your custom theme
|
|
1728
|
+
import '@appforgeapps/uiforge/styles.css'
|
|
1729
|
+
import './my-custom-theme.css' // Your customized copy of an example theme
|
|
1730
|
+
```
|
|
1731
|
+
|
|
1732
|
+
Quick component theming example:
|
|
1716
1733
|
|
|
1717
1734
|
```tsx
|
|
1718
1735
|
import { useState } from 'react'
|
|
@@ -1817,6 +1834,8 @@ Simply open this repository in GitHub Codespaces to get started immediately with
|
|
|
1817
1834
|
|
|
1818
1835
|
Contributions are welcome! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed guidelines.
|
|
1819
1836
|
|
|
1837
|
+
**Important for Component Contributors:** UIForge is a library-first project. Before contributing a component, review the [Component Design Guidelines](./COMPONENT_GUIDELINES.md) to ensure your component remains generic, reusable, and composable.
|
|
1838
|
+
|
|
1820
1839
|
Quick start:
|
|
1821
1840
|
|
|
1822
1841
|
1. Fork the repository
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { default as default_2 } from 'react';
|
|
2
2
|
import { FC } from 'react';
|
|
3
|
+
import { ImgHTMLAttributes } from 'react';
|
|
3
4
|
import { JSX } from 'react/jsx-runtime';
|
|
4
5
|
import { RefObject } from 'react';
|
|
5
6
|
|
|
@@ -571,6 +572,263 @@ export declare function isAdultContent(url: string): boolean;
|
|
|
571
572
|
|
|
572
573
|
export declare const IssueIcon: default_2.FC<IconProps>;
|
|
573
574
|
|
|
575
|
+
/**
|
|
576
|
+
* A generic, reusable MediaCard component for displaying media-driven content items.
|
|
577
|
+
*
|
|
578
|
+
* Features:
|
|
579
|
+
* - Responsive layout: media left + body right (desktop), stacked (mobile)
|
|
580
|
+
* - Theme token integration for consistent spacing, typography, and elevation
|
|
581
|
+
* - Full accessibility support (alt text, focus states, ARIA labels, keyboard navigation)
|
|
582
|
+
* - Flexible customization via render props and slots
|
|
583
|
+
* - Multiple variants for different use cases
|
|
584
|
+
*
|
|
585
|
+
* @example
|
|
586
|
+
* ```tsx
|
|
587
|
+
* <MediaCard
|
|
588
|
+
* title="Song Title"
|
|
589
|
+
* subtitle="Artist Name"
|
|
590
|
+
* mediaUrl="/album-art.jpg"
|
|
591
|
+
* mediaAlt="Album artwork"
|
|
592
|
+
* meta={{ duration: "3:45", year: "2024" }}
|
|
593
|
+
* actions={<button>Play</button>}
|
|
594
|
+
* />
|
|
595
|
+
* ```
|
|
596
|
+
*/
|
|
597
|
+
export declare const MediaCard: default_2.FC<MediaCardProps>;
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Props for the MediaCard component
|
|
601
|
+
*/
|
|
602
|
+
export declare interface MediaCardProps {
|
|
603
|
+
/**
|
|
604
|
+
* Main title text displayed prominently
|
|
605
|
+
*/
|
|
606
|
+
title: string;
|
|
607
|
+
/**
|
|
608
|
+
* Secondary subtitle text
|
|
609
|
+
*/
|
|
610
|
+
subtitle?: string;
|
|
611
|
+
/**
|
|
612
|
+
* URL or path to the media (image/video)
|
|
613
|
+
*/
|
|
614
|
+
mediaUrl: string;
|
|
615
|
+
/**
|
|
616
|
+
* Alt text for the media (required for accessibility)
|
|
617
|
+
*/
|
|
618
|
+
mediaAlt: string;
|
|
619
|
+
/**
|
|
620
|
+
* Optional metadata as key-value pairs
|
|
621
|
+
*/
|
|
622
|
+
meta?: Record<string, string>;
|
|
623
|
+
/**
|
|
624
|
+
* Optional action buttons or elements to display
|
|
625
|
+
*/
|
|
626
|
+
actions?: default_2.ReactNode;
|
|
627
|
+
/**
|
|
628
|
+
* Visual variant of the card
|
|
629
|
+
*/
|
|
630
|
+
variant?: 'default' | 'compact' | 'featured';
|
|
631
|
+
/**
|
|
632
|
+
* Custom className for additional styling
|
|
633
|
+
*/
|
|
634
|
+
className?: string;
|
|
635
|
+
/**
|
|
636
|
+
* Theme variant ('light' or 'dark')
|
|
637
|
+
*/
|
|
638
|
+
theme?: 'light' | 'dark';
|
|
639
|
+
/**
|
|
640
|
+
* Optional custom body content (render prop)
|
|
641
|
+
*/
|
|
642
|
+
renderBody?: () => default_2.ReactNode;
|
|
643
|
+
/**
|
|
644
|
+
* Optional custom footer content (render prop)
|
|
645
|
+
*/
|
|
646
|
+
renderFooter?: () => default_2.ReactNode;
|
|
647
|
+
/**
|
|
648
|
+
* Click handler for the entire card
|
|
649
|
+
*/
|
|
650
|
+
onClick?: () => void;
|
|
651
|
+
/**
|
|
652
|
+
* Makes the card focusable and keyboard-navigable
|
|
653
|
+
*/
|
|
654
|
+
tabIndex?: number;
|
|
655
|
+
/**
|
|
656
|
+
* ARIA label for the card
|
|
657
|
+
*/
|
|
658
|
+
ariaLabel?: string;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* MediaListSkeleton - A loading skeleton component for lists of MediaCard components
|
|
663
|
+
*
|
|
664
|
+
* Features:
|
|
665
|
+
* - Configurable number of skeleton items
|
|
666
|
+
* - CSS shimmer animation for visual feedback
|
|
667
|
+
* - Respects `prefers-reduced-motion` for accessibility
|
|
668
|
+
* - Uses UIForge design tokens for consistent sizing
|
|
669
|
+
* - Theme support (light/dark)
|
|
670
|
+
* - SSR-friendly (no client-side JavaScript required)
|
|
671
|
+
*
|
|
672
|
+
* Perfect for:
|
|
673
|
+
* - Loading states while fetching media lists
|
|
674
|
+
* - Progressive loading experiences
|
|
675
|
+
* - Skeleton screens for any MediaCard-based lists
|
|
676
|
+
*
|
|
677
|
+
* @example
|
|
678
|
+
* ```tsx
|
|
679
|
+
* // Basic usage
|
|
680
|
+
* <MediaListSkeleton count={5} />
|
|
681
|
+
*
|
|
682
|
+
* // Dark theme
|
|
683
|
+
* <MediaListSkeleton count={3} theme="dark" />
|
|
684
|
+
*
|
|
685
|
+
* // In a conditional render
|
|
686
|
+
* {isLoading ? (
|
|
687
|
+
* <MediaListSkeleton count={6} />
|
|
688
|
+
* ) : (
|
|
689
|
+
* songList.map(song => <SongCard key={song.id} {...song} />)
|
|
690
|
+
* )}
|
|
691
|
+
* ```
|
|
692
|
+
*/
|
|
693
|
+
export declare const MediaListSkeleton: default_2.FC<MediaListSkeletonProps>;
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Props for the MediaListSkeleton component
|
|
697
|
+
*/
|
|
698
|
+
export declare interface MediaListSkeletonProps {
|
|
699
|
+
/**
|
|
700
|
+
* Number of skeleton placeholders to render
|
|
701
|
+
* @default 3
|
|
702
|
+
*/
|
|
703
|
+
count?: number;
|
|
704
|
+
/**
|
|
705
|
+
* Theme variant ('light' or 'dark')
|
|
706
|
+
* @default 'light'
|
|
707
|
+
*/
|
|
708
|
+
theme?: 'light' | 'dark';
|
|
709
|
+
/**
|
|
710
|
+
* Custom className for additional styling
|
|
711
|
+
*/
|
|
712
|
+
className?: string;
|
|
713
|
+
/**
|
|
714
|
+
* ARIA label for accessibility
|
|
715
|
+
* @default 'Loading media items'
|
|
716
|
+
*/
|
|
717
|
+
ariaLabel?: string;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* MediaPlaceholder - A placeholder component for missing or loading media
|
|
722
|
+
*
|
|
723
|
+
* Features:
|
|
724
|
+
* - Three display modes: icon, initials, gradient
|
|
725
|
+
* - Multiple size options
|
|
726
|
+
* - Customizable border radius
|
|
727
|
+
* - Theme support (light/dark)
|
|
728
|
+
* - Accessibility support with alt text
|
|
729
|
+
*
|
|
730
|
+
* Perfect for:
|
|
731
|
+
* - Missing profile pictures
|
|
732
|
+
* - Loading states for images
|
|
733
|
+
* - Default avatars
|
|
734
|
+
* - Fallback media for MediaCard
|
|
735
|
+
*
|
|
736
|
+
* @example
|
|
737
|
+
* ```tsx
|
|
738
|
+
* // Icon placeholder (default)
|
|
739
|
+
* <MediaPlaceholder alt="Profile picture" />
|
|
740
|
+
*
|
|
741
|
+
* // Initials placeholder
|
|
742
|
+
* <MediaPlaceholder
|
|
743
|
+
* type="initials"
|
|
744
|
+
* name="John Doe"
|
|
745
|
+
* size="large"
|
|
746
|
+
* borderRadius="full"
|
|
747
|
+
* alt="John Doe's avatar"
|
|
748
|
+
* />
|
|
749
|
+
*
|
|
750
|
+
* // Gradient placeholder
|
|
751
|
+
* <MediaPlaceholder
|
|
752
|
+
* type="gradient"
|
|
753
|
+
* gradientColor="purple"
|
|
754
|
+
* size="medium"
|
|
755
|
+
* alt="Album artwork placeholder"
|
|
756
|
+
* />
|
|
757
|
+
*
|
|
758
|
+
* // Custom icon
|
|
759
|
+
* <MediaPlaceholder
|
|
760
|
+
* type="icon"
|
|
761
|
+
* icon={<MusicIcon />}
|
|
762
|
+
* alt="Music placeholder"
|
|
763
|
+
* />
|
|
764
|
+
* ```
|
|
765
|
+
*/
|
|
766
|
+
export declare const MediaPlaceholder: default_2.FC<MediaPlaceholderProps>;
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Props for the MediaPlaceholder component
|
|
770
|
+
*/
|
|
771
|
+
export declare interface MediaPlaceholderProps {
|
|
772
|
+
/**
|
|
773
|
+
* Type of placeholder to display
|
|
774
|
+
* - 'icon': Shows an icon (default)
|
|
775
|
+
* - 'initials': Shows initials from a name
|
|
776
|
+
* - 'gradient': Shows a gradient background
|
|
777
|
+
*/
|
|
778
|
+
type?: 'icon' | 'initials' | 'gradient';
|
|
779
|
+
/**
|
|
780
|
+
* Icon to display (only used when type='icon')
|
|
781
|
+
* Can be any React node (e.g., SVG, emoji, or icon component)
|
|
782
|
+
*/
|
|
783
|
+
icon?: default_2.ReactNode;
|
|
784
|
+
/**
|
|
785
|
+
* Name to extract initials from (only used when type='initials')
|
|
786
|
+
* Examples: "John Doe" → "JD", "Taylor Swift" → "TS"
|
|
787
|
+
*/
|
|
788
|
+
name?: string;
|
|
789
|
+
/**
|
|
790
|
+
* Custom initials text (overrides automatic extraction from name)
|
|
791
|
+
*/
|
|
792
|
+
initials?: string;
|
|
793
|
+
/**
|
|
794
|
+
* Gradient color scheme (only used when type='gradient')
|
|
795
|
+
* - 'blue': Blue gradient
|
|
796
|
+
* - 'purple': Purple gradient
|
|
797
|
+
* - 'green': Green gradient
|
|
798
|
+
* - 'orange': Orange gradient
|
|
799
|
+
* - 'pink': Pink gradient
|
|
800
|
+
*/
|
|
801
|
+
gradientColor?: 'blue' | 'purple' | 'green' | 'orange' | 'pink';
|
|
802
|
+
/**
|
|
803
|
+
* Size of the placeholder
|
|
804
|
+
* - 'small': 64px
|
|
805
|
+
* - 'medium': 84px (default)
|
|
806
|
+
* - 'large': 120px
|
|
807
|
+
* - 'xlarge': 160px
|
|
808
|
+
*/
|
|
809
|
+
size?: 'small' | 'medium' | 'large' | 'xlarge';
|
|
810
|
+
/**
|
|
811
|
+
* Border radius style
|
|
812
|
+
* - 'small': 4px
|
|
813
|
+
* - 'medium': 8px (default)
|
|
814
|
+
* - 'large': 12px
|
|
815
|
+
* - 'full': 50% (circular)
|
|
816
|
+
*/
|
|
817
|
+
borderRadius?: 'small' | 'medium' | 'large' | 'full';
|
|
818
|
+
/**
|
|
819
|
+
* Custom className for additional styling
|
|
820
|
+
*/
|
|
821
|
+
className?: string;
|
|
822
|
+
/**
|
|
823
|
+
* Alt text for accessibility (required for screen readers)
|
|
824
|
+
*/
|
|
825
|
+
alt?: string;
|
|
826
|
+
/**
|
|
827
|
+
* Theme variant ('light' or 'dark')
|
|
828
|
+
*/
|
|
829
|
+
theme?: 'light' | 'dark';
|
|
830
|
+
}
|
|
831
|
+
|
|
574
832
|
export declare const MeditationIcon: default_2.FC<IconProps>;
|
|
575
833
|
|
|
576
834
|
export declare const MeetingIcon: default_2.FC<IconProps>;
|
|
@@ -1714,6 +1972,180 @@ export declare interface UseDynamicPageCountOptions {
|
|
|
1714
1972
|
approxItemHeight?: number;
|
|
1715
1973
|
}
|
|
1716
1974
|
|
|
1975
|
+
/**
|
|
1976
|
+
* useOptimizedImage - A hook that provides optimized image attributes
|
|
1977
|
+
*
|
|
1978
|
+
* This hook helps you implement best practices for image loading and performance:
|
|
1979
|
+
*
|
|
1980
|
+
* **Performance Best Practices:**
|
|
1981
|
+
* 1. **Lazy Loading**: Use `loading="lazy"` for images below the fold
|
|
1982
|
+
* 2. **Async Decoding**: Use `decoding="async"` to avoid blocking the main thread
|
|
1983
|
+
* 3. **Responsive Images**: Use `srcSet` and `sizes` for different screen sizes
|
|
1984
|
+
* 4. **Aspect Ratio**: Use `aspectRatio` to prevent layout shift (CLS)
|
|
1985
|
+
* 5. **LQIP (Low Quality Image Placeholder)**: Consider using a blur-up technique
|
|
1986
|
+
*
|
|
1987
|
+
* **Recommended Image Sizes:**
|
|
1988
|
+
* - Thumbnails: 64px, 84px, 120px
|
|
1989
|
+
* - Cards: 320px, 480px, 640px
|
|
1990
|
+
* - Hero images: 1024px, 1280px, 1920px
|
|
1991
|
+
* - Always provide WebP/AVIF formats when possible
|
|
1992
|
+
*
|
|
1993
|
+
* **Accessibility:**
|
|
1994
|
+
* - Always provide meaningful `alt` text
|
|
1995
|
+
* - Use empty `alt=""` for decorative images
|
|
1996
|
+
* - Consider adding `title` for additional context
|
|
1997
|
+
*
|
|
1998
|
+
* **LQIP Guidance:**
|
|
1999
|
+
* For optimal user experience, consider implementing a Low Quality Image Placeholder (LQIP):
|
|
2000
|
+
* 1. Generate a tiny version of the image (e.g., 20px wide, base64 encoded)
|
|
2001
|
+
* 2. Display it as background while the full image loads
|
|
2002
|
+
* 3. Blur it with CSS `filter: blur(10px)` for a smooth appearance
|
|
2003
|
+
* 4. Fade in the full image when loaded
|
|
2004
|
+
*
|
|
2005
|
+
* @example
|
|
2006
|
+
* ```tsx
|
|
2007
|
+
* // Basic usage
|
|
2008
|
+
* function BasicImage() {
|
|
2009
|
+
* const { imgProps } = useOptimizedImage({
|
|
2010
|
+
* src: '/image.jpg',
|
|
2011
|
+
* alt: 'Product photo',
|
|
2012
|
+
* loading: 'lazy',
|
|
2013
|
+
* decoding: 'async'
|
|
2014
|
+
* })
|
|
2015
|
+
* return <img {...imgProps} />
|
|
2016
|
+
* }
|
|
2017
|
+
*
|
|
2018
|
+
* // Responsive images with srcSet
|
|
2019
|
+
* function ResponsiveImage() {
|
|
2020
|
+
* const { imgProps } = useOptimizedImage({
|
|
2021
|
+
* src: '/image-800w.jpg',
|
|
2022
|
+
* alt: 'Responsive image',
|
|
2023
|
+
* srcSet: '/image-400w.jpg 400w, /image-800w.jpg 800w, /image-1200w.jpg 1200w',
|
|
2024
|
+
* sizes: '(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw',
|
|
2025
|
+
* loading: 'lazy',
|
|
2026
|
+
* decoding: 'async'
|
|
2027
|
+
* })
|
|
2028
|
+
* return <img {...imgProps} />
|
|
2029
|
+
* }
|
|
2030
|
+
*
|
|
2031
|
+
* // With aspect ratio (prevents layout shift)
|
|
2032
|
+
* function AspectRatioImage() {
|
|
2033
|
+
* const { imgProps, containerProps } = useOptimizedImage({
|
|
2034
|
+
* src: '/image.jpg',
|
|
2035
|
+
* alt: 'Fixed aspect ratio',
|
|
2036
|
+
* aspectRatio: '16/9',
|
|
2037
|
+
* loading: 'lazy'
|
|
2038
|
+
* })
|
|
2039
|
+
* return (
|
|
2040
|
+
* <div {...containerProps}>
|
|
2041
|
+
* <img {...imgProps} />
|
|
2042
|
+
* </div>
|
|
2043
|
+
* )
|
|
2044
|
+
* }
|
|
2045
|
+
*
|
|
2046
|
+
* // Complete example with all options
|
|
2047
|
+
* function CompleteExample() {
|
|
2048
|
+
* const { imgProps, containerProps } = useOptimizedImage({
|
|
2049
|
+
* src: '/hero-1200w.jpg',
|
|
2050
|
+
* alt: 'Hero image with mountains',
|
|
2051
|
+
* srcSet: '/hero-640w.jpg 640w, /hero-1200w.jpg 1200w, /hero-1920w.jpg 1920w',
|
|
2052
|
+
* sizes: '(max-width: 640px) 100vw, (max-width: 1200px) 80vw, 1200px',
|
|
2053
|
+
* aspectRatio: '16/9',
|
|
2054
|
+
* loading: 'lazy',
|
|
2055
|
+
* decoding: 'async',
|
|
2056
|
+
* width: 1200,
|
|
2057
|
+
* className: 'hero-image'
|
|
2058
|
+
* })
|
|
2059
|
+
*
|
|
2060
|
+
* return (
|
|
2061
|
+
* <div {...containerProps}>
|
|
2062
|
+
* <img {...imgProps} />
|
|
2063
|
+
* </div>
|
|
2064
|
+
* )
|
|
2065
|
+
* }
|
|
2066
|
+
* ```
|
|
2067
|
+
*
|
|
2068
|
+
* @param options - Configuration options for the optimized image
|
|
2069
|
+
* @returns Object containing imgProps (and optionally containerProps)
|
|
2070
|
+
*/
|
|
2071
|
+
export declare function useOptimizedImage(options: UseOptimizedImageOptions): UseOptimizedImageResult;
|
|
2072
|
+
|
|
2073
|
+
/**
|
|
2074
|
+
* Options for the useOptimizedImage hook
|
|
2075
|
+
*/
|
|
2076
|
+
export declare interface UseOptimizedImageOptions {
|
|
2077
|
+
/**
|
|
2078
|
+
* Source URL for the image
|
|
2079
|
+
*/
|
|
2080
|
+
src: string;
|
|
2081
|
+
/**
|
|
2082
|
+
* Alt text for accessibility (required)
|
|
2083
|
+
*/
|
|
2084
|
+
alt: string;
|
|
2085
|
+
/**
|
|
2086
|
+
* Source set for responsive images
|
|
2087
|
+
* @example "image-320w.jpg 320w, image-640w.jpg 640w, image-1024w.jpg 1024w"
|
|
2088
|
+
*/
|
|
2089
|
+
srcSet?: string;
|
|
2090
|
+
/**
|
|
2091
|
+
* Sizes attribute for responsive images
|
|
2092
|
+
* @example "(max-width: 640px) 100vw, 50vw"
|
|
2093
|
+
*/
|
|
2094
|
+
sizes?: string;
|
|
2095
|
+
/**
|
|
2096
|
+
* Loading strategy
|
|
2097
|
+
* - 'lazy': Load when near viewport (default, recommended for most images)
|
|
2098
|
+
* - 'eager': Load immediately
|
|
2099
|
+
*/
|
|
2100
|
+
loading?: 'lazy' | 'eager';
|
|
2101
|
+
/**
|
|
2102
|
+
* Decoding strategy
|
|
2103
|
+
* - 'async': Decode asynchronously (default, recommended for performance)
|
|
2104
|
+
* - 'sync': Decode synchronously
|
|
2105
|
+
* - 'auto': Browser decides
|
|
2106
|
+
*/
|
|
2107
|
+
decoding?: 'async' | 'sync' | 'auto';
|
|
2108
|
+
/**
|
|
2109
|
+
* Aspect ratio for placeholder (prevents layout shift)
|
|
2110
|
+
* @example "16/9" or "1/1" or "4/3"
|
|
2111
|
+
*/
|
|
2112
|
+
aspectRatio?: string;
|
|
2113
|
+
/**
|
|
2114
|
+
* Width of the image (used with aspectRatio to calculate height)
|
|
2115
|
+
*/
|
|
2116
|
+
width?: number;
|
|
2117
|
+
/**
|
|
2118
|
+
* Height of the image (used with aspectRatio or standalone)
|
|
2119
|
+
*/
|
|
2120
|
+
height?: number;
|
|
2121
|
+
/**
|
|
2122
|
+
* Additional CSS class names
|
|
2123
|
+
*/
|
|
2124
|
+
className?: string;
|
|
2125
|
+
/**
|
|
2126
|
+
* Inline styles
|
|
2127
|
+
*/
|
|
2128
|
+
style?: React.CSSProperties;
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
/**
|
|
2132
|
+
* Return type for useOptimizedImage hook
|
|
2133
|
+
*/
|
|
2134
|
+
export declare interface UseOptimizedImageResult {
|
|
2135
|
+
/**
|
|
2136
|
+
* Props to spread onto an <img> element
|
|
2137
|
+
*/
|
|
2138
|
+
imgProps: ImgHTMLAttributes<HTMLImageElement>;
|
|
2139
|
+
/**
|
|
2140
|
+
* Container props (if aspectRatio is used)
|
|
2141
|
+
* Apply these to a wrapper div for proper aspect ratio handling
|
|
2142
|
+
*/
|
|
2143
|
+
containerProps?: {
|
|
2144
|
+
style: React.CSSProperties;
|
|
2145
|
+
className?: string;
|
|
2146
|
+
};
|
|
2147
|
+
}
|
|
2148
|
+
|
|
1717
2149
|
/**
|
|
1718
2150
|
* A hook that determines whether a container element is "compact" by measuring its width.
|
|
1719
2151
|
* Uses ResizeObserver to respond to container size changes.
|