storytellurx-v1/app/components/utils/irregular-text-container-gemini.tsx
Elias Rhouzlane 465651640e feat(chat-metrics): add chat metrics components for various personas with dynamic arousal and consent levels
feat(fish-eye): implement fisheye effect for text with customizable scale and frequency

feat(irregular-text): create irregular text container components for dynamic shape wrapping

feat(positional-scroller): add positional scroller component to track child elements' positions during scroll

feat(scroll-progress-tracker): implement scroll progress tracker to monitor scroll position and update CSS variables
2025-06-26 11:44:05 +02:00

69 lines
2.2 KiB
TypeScript

import cn from "@bureaudouble/outils/cn.ts";
import type { ElementType, ReactNode } from "react";
type IrregularShapeTextProps<T extends ElementType> = {
/** The content to be wrapped inside the shape. */
children: ReactNode;
/**
* The name of the CSS variable defining the left-side polygon.
* @default --shape-polygon-left
*/
leftShapeVar?: string;
/**
* The name of the CSS variable defining the right-side polygon.
* @default --shape-polygon-right
*/
rightShapeVar?: string;
/** Optional custom className for the wrapper element. */
className?: string;
/**
* The HTML tag to use for the wrapper element.
* @default div
*/
as?: T;
};
// This allows for passing component-specific props like `onClick` for a `button` etc.
type PolymorphicProps<T extends ElementType> =
& IrregularShapeTextProps<T>
& Omit<React.ComponentPropsWithoutRef<T>, keyof IrregularShapeTextProps<T>>;
export function IrregularShapeText<T extends ElementType = "div">({
children,
leftShapeVar = "--shape-polygon-left",
rightShapeVar = "--shape-polygon-right",
className,
as,
}: PolymorphicProps<T>) {
const Component = as || "div";
// These classes use Tailwind's arbitrary property syntax `[...]`.
// This is how you use CSS variables directly in your class names.
// We include the `-webkit-` prefix for maximum compatibility with older Safari.
const leftShapeClasses = cn(
"float-left",
"w-1/2", // The shaper div takes up the left half of the container
"h-full",
`[shape-outside:var(${leftShapeVar})]`,
`[-webkit-shape-outside:var(${leftShapeVar})]`,
);
const rightShapeClasses = cn(
"float-right",
"w-1/2", // The shaper div takes up the right half of the container
"h-full",
`[shape-outside:var(${rightShapeVar})]`,
`[-webkit-shape-outside:var(${rightShapeVar})]`,
);
return (
<Component className={cn("relative", className)}>
{/* These two divs are invisible but define the text flow boundaries */}
<div className={leftShapeClasses} />
<div className={rightShapeClasses} />
{/* The actual text content flows in the space between the floated divs */}
{children}
</Component>
);
}