@octaviaflow/core 3.1.0-beta.72 → 3.1.0-beta.73

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Card/Card.tsx","../src/components/Avatar/Avatar.tsx","../src/components/BlogCard/BlogCard.tsx","../src/hooks/useTextareaCommands.ts","../src/hooks/useTextareaSelection.ts","../src/hooks/useTextareaTools.tsx","../src/components/Textarea/Textarea.tsx","../src/components/CountUp/CountUp.tsx","../src/components/TestimonialCard/TestimonialCard.tsx"],"sourcesContent":["\"use client\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport {\n type ComponentPropsWithoutRef,\n type ElementType,\n forwardRef,\n type KeyboardEvent,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Slot } from \"../../utils/Slot\";\n\n/* ---------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\nexport type CardVariant = \"default\" | \"elevated\" | \"outlined\" | \"subtle\" | \"selected\";\nexport type CardPadding = \"none\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\nexport type CardRadius = \"none\" | \"sm\" | \"md\" | \"lg\";\n\nexport interface CardProps\n extends Omit<\n ComponentPropsWithoutRef<\"div\">,\n \"onDrag\" | \"onDragStart\" | \"onDragEnd\" | \"onAnimationStart\"\n > {\n variant?: CardVariant;\n padding?: CardPadding;\n radius?: CardRadius;\n /** Apply hover affordance (lift + tint) without making the card clickable.\n * For purely-visual surfaces that respond to mouse-over. */\n hoverable?: boolean;\n /** Disable a clickable card. Adds `aria-disabled` and suppresses interaction. */\n disabled?: boolean;\n /** Loading skeleton — replaces the card chrome with a shimmer block of\n * the same height. */\n loading?: boolean;\n /** Render Card's styling onto a custom child element (Radix-style Slot).\n *\n * <Card asChild variant=\"elevated\">\n * <NextLink href=\"/blog/post-1\">{...}</NextLink>\n * </Card>\n *\n * When set, Card does NOT wrap the child in motion.div — the consumer's\n * element fully owns content. Use without asChild for the built-in\n * hover / tap motion + keyboard activation. */\n asChild?: boolean;\n children?: ReactNode;\n}\n\n/* ---------------------------------------------------------------------------\n * Card root\n * ------------------------------------------------------------------------- */\n\nexport const Card = forwardRef<HTMLDivElement, CardProps>(function Card(\n {\n variant = \"default\",\n padding = \"md\",\n radius = \"md\",\n hoverable = false,\n disabled = false,\n loading = false,\n asChild = false,\n onClick,\n onKeyDown,\n className,\n children,\n ...rest\n },\n ref,\n) {\n const reducedMotion = useReducedMotion();\n const isInteractive = Boolean(onClick) && !disabled && !loading;\n\n // Keyboard activation for clickable cards. Without this, Enter/Space on a\n // focused card-as-button does nothing — a broken a11y contract that the\n // previous shape silently shipped.\n const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(e);\n if (e.defaultPrevented) return;\n if (!isInteractive) return;\n if ((e.key === \"Enter\" || e.key === \" \") && !e.repeat) {\n e.preventDefault();\n onClick?.(e as unknown as Parameters<NonNullable<typeof onClick>>[0]);\n }\n };\n\n const rootClassName = cn(\n \"ods-card\",\n `ods-card--${variant}`,\n `ods-card--pad-${padding}`,\n `ods-card--radius-${radius}`,\n (hoverable || isInteractive) && !loading && !disabled && \"ods-card--hoverable\",\n isInteractive && \"ods-card--clickable\",\n disabled && \"ods-card--disabled\",\n loading && \"ods-card--loading\",\n className,\n );\n\n // asChild — project Card's chrome onto the consumer's element.\n if (asChild) {\n return (\n <Slot\n {...(rest as ComponentPropsWithoutRef<ElementType>)}\n ref={ref as Ref<HTMLElement>}\n className={rootClassName}\n onClick={isInteractive ? onClick : undefined}\n onKeyDown={isInteractive ? handleKeyDown : onKeyDown}\n aria-disabled={disabled || undefined}\n >\n {children as ReactElement}\n </Slot>\n );\n }\n\n // Loading skeleton — same height-ish slot so layout doesn't jump.\n if (loading) {\n return (\n <div\n {...rest}\n ref={ref}\n className={rootClassName}\n aria-busy=\"true\"\n aria-label=\"Loading\"\n >\n <div className=\"ods-card__skeleton\" data-ods-animate=\"shimmer\" />\n </div>\n );\n }\n\n return (\n <motion.div\n {...(rest as any)}\n ref={ref}\n onClick={isInteractive ? onClick : undefined}\n onKeyDown={isInteractive ? handleKeyDown : onKeyDown}\n className={rootClassName}\n whileHover={\n (hoverable || isInteractive) && !reducedMotion\n ? { y: -2, transition: { duration: 0.15 } }\n : undefined\n }\n whileTap={isInteractive && !reducedMotion ? { scale: 0.99 } : undefined}\n role={isInteractive ? \"button\" : rest.role}\n tabIndex={isInteractive ? (rest.tabIndex ?? 0) : rest.tabIndex}\n aria-disabled={disabled || undefined}\n >\n {children}\n </motion.div>\n );\n}) as React.ForwardRefExoticComponent<\n CardProps & React.RefAttributes<HTMLDivElement>\n> & {\n Header: typeof CardHeader;\n Body: typeof CardBody;\n Footer: typeof CardFooter;\n Title: typeof CardTitle;\n Description: typeof CardDescription;\n};\n\nCard.displayName = \"Card\";\n\n/* ---------------------------------------------------------------------------\n * Subcomponents — `Card.Header`, `Card.Body`, `Card.Footer`, `Card.Title`,\n * `Card.Description`. Optional building blocks for the \"title + content +\n * actions\" pattern. Compose freely — none of them are required.\n * ------------------------------------------------------------------------- */\n\nexport interface CardSectionProps extends ComponentPropsWithoutRef<\"div\"> {\n children?: ReactNode;\n}\n\nexport const CardHeader = forwardRef<HTMLDivElement, CardSectionProps>(\n function CardHeader({ className, children, ...rest }, ref) {\n return (\n <div {...rest} ref={ref} className={cn(\"ods-card__header\", className)}>\n {children}\n </div>\n );\n },\n);\nCardHeader.displayName = \"Card.Header\";\n\nexport const CardBody = forwardRef<HTMLDivElement, CardSectionProps>(\n function CardBody({ className, children, ...rest }, ref) {\n return (\n <div {...rest} ref={ref} className={cn(\"ods-card__body\", className)}>\n {children}\n </div>\n );\n },\n);\nCardBody.displayName = \"Card.Body\";\n\nexport const CardFooter = forwardRef<HTMLDivElement, CardSectionProps>(\n function CardFooter({ className, children, ...rest }, ref) {\n return (\n <div {...rest} ref={ref} className={cn(\"ods-card__footer\", className)}>\n {children}\n </div>\n );\n },\n);\nCardFooter.displayName = \"Card.Footer\";\n\nexport interface CardTitleProps extends ComponentPropsWithoutRef<\"h3\"> {\n /** Override the heading level. Defaults to `<h3>`. */\n as?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\";\n children?: ReactNode;\n}\n\nexport const CardTitle = forwardRef<HTMLHeadingElement, CardTitleProps>(\n function CardTitle({ as: Comp = \"h3\", className, children, ...rest }, ref) {\n return (\n <Comp\n {...(rest as ComponentPropsWithoutRef<typeof Comp>)}\n ref={ref}\n className={cn(\"ods-card__title\", className)}\n >\n {children}\n </Comp>\n );\n },\n);\nCardTitle.displayName = \"Card.Title\";\n\nexport interface CardDescriptionProps extends ComponentPropsWithoutRef<\"p\"> {\n children?: ReactNode;\n}\n\nexport const CardDescription = forwardRef<\n HTMLParagraphElement,\n CardDescriptionProps\n>(function CardDescription({ className, children, ...rest }, ref) {\n return (\n <p {...rest} ref={ref} className={cn(\"ods-card__description\", className)}>\n {children}\n </p>\n );\n});\nCardDescription.displayName = \"Card.Description\";\n\n// Dot-notation API: `Card.Header`, `Card.Body`, etc.\nCard.Header = CardHeader;\nCard.Body = CardBody;\nCard.Footer = CardFooter;\nCard.Title = CardTitle;\nCard.Description = CardDescription;\n","\"use client\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/* ---------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\nexport type AvatarSize = \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\nexport type AvatarShape = \"circle\" | \"square\";\n/** Presence indicator. `online` pulses gently; reduced-motion is respected. */\nexport type AvatarStatus = \"online\" | \"offline\" | \"busy\" | \"away\";\n\nexport interface AvatarProps\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"color\" | \"children\" | \"onClick\" | \"onKeyDown\"> {\n /** Image URL. If loading fails, falls back to `initials` (then `icon`, then `?`). */\n src?: string;\n /** Accessible name for the avatar. Used as the `<img>` alt AND as the\n * wrapping element's accessible name. If you only pass `initials`,\n * this is recommended so AT announces \"Jane Doe avatar\" not \"J D\". */\n alt?: string;\n /** Initials to render when there is no image. Auto-uppercased and\n * truncated to 2 characters so passing a full name stays sane. */\n initials?: string;\n /** Optional icon slot — rendered when neither `src` nor `initials` is\n * available (or used directly when you want a system/bot avatar). */\n icon?: ReactNode;\n /** Override the default `?` fallback content. */\n fallback?: ReactNode;\n /** Stable seed for the persistent palette. Falls back to `initials` /\n * `alt` so the same person consistently gets the same color even if\n * their name changes case or you only have a partial identity. */\n seed?: string;\n /** Pixel/font size variant. */\n size?: AvatarSize;\n /** Shape — `circle` (people, default) or `square` (teams, bots, brands). */\n shape?: AvatarShape;\n /** Presence indicator dot. */\n status?: AvatarStatus;\n /** Human-readable status label folded into the accessible name. Defaults\n * to the capitalized `status` value. */\n statusLabel?: string;\n /** When set, the avatar becomes a button (Enter/Space activated). */\n onClick?: () => void;\n /** Native image attributes — set `loading=\"eager\"` for above-the-fold avatars\n * if you've measured CLS regressions. Defaults to `lazy`. */\n imgLoading?: \"eager\" | \"lazy\";\n /** Native referrerPolicy for cross-origin avatar hosts (Gravatar, etc.). */\n referrerPolicy?: ComponentPropsWithoutRef<\"img\">[\"referrerPolicy\"];\n}\n\n/* ---------------------------------------------------------------------------\n * Persistent palette\n *\n * 12 gradients exposed as CSS custom properties so consumers can theme them\n * (or replace the whole palette) without touching the component. We do NOT\n * hit localStorage — a deterministic djb2 hash gives stable assignment\n * across renders, machines, and SSR/CSR boundaries.\n * ------------------------------------------------------------------------- */\n\nconst PALETTE_SIZE = 12;\n\nfunction djb2(str: string): number {\n let h = 5381;\n for (let i = 0; i < str.length; i++) h = (h << 5) + h + str.charCodeAt(i);\n return h >>> 0;\n}\n\nfunction paletteIndexFor(seed: string): number {\n return djb2(seed) % PALETTE_SIZE;\n}\n\nfunction normalizeInitials(raw: string): string {\n // Take the first character of up to two whitespace-separated tokens —\n // \"Jane Doe\" → \"JD\", \"Postgres\" → \"P\", \"schema-drift\" → \"S\". Falls\n // back to the first two characters of a contiguous run.\n const trimmed = raw.trim();\n if (!trimmed) return \"\";\n const tokens = trimmed.split(/\\s+/).filter(Boolean);\n if (tokens.length >= 2) {\n return (tokens[0]!.charAt(0) + tokens[1]!.charAt(0)).toUpperCase();\n }\n return trimmed.slice(0, 2).toUpperCase();\n}\n\nconst STATUS_DEFAULT_LABEL: Record<AvatarStatus, string> = {\n online: \"Online\",\n offline: \"Offline\",\n busy: \"Busy\",\n away: \"Away\",\n};\n\n/* ---------------------------------------------------------------------------\n * Avatar\n * ------------------------------------------------------------------------- */\n\nexport const Avatar = forwardRef<HTMLDivElement, AvatarProps>(function Avatar(\n {\n src,\n alt,\n initials,\n icon,\n fallback,\n seed,\n size = \"md\",\n shape = \"circle\",\n status,\n statusLabel,\n onClick,\n imgLoading = \"lazy\",\n referrerPolicy,\n className,\n ...rest\n },\n ref,\n) {\n // Image failure is tracked locally so the next render swaps to the\n // initials fallback transparently. Reset key change resets state.\n const [imgFailed, setImgFailed] = useState(false);\n const handleImgError = useCallback(() => setImgFailed(true), []);\n\n const showImage = Boolean(src) && !imgFailed;\n\n const normalizedInitials = useMemo(\n () => (initials ? normalizeInitials(initials) : \"\"),\n [initials],\n );\n\n // Resolve seed once. Stable across renders.\n const paletteIdx = useMemo(() => {\n const resolved = seed ?? initials ?? alt ?? \"?\";\n return paletteIndexFor(resolved);\n }, [seed, initials, alt]);\n\n // Accessible name — fold status into the label so AT announces\n // \"Jane Doe, online\" as a single coherent label, not two separate nodes.\n const baseName = alt || normalizedInitials || \"Avatar\";\n const announcedStatus = status ? (statusLabel ?? STATUS_DEFAULT_LABEL[status]) : \"\";\n const accessibleName = announcedStatus ? `${baseName}, ${announcedStatus}` : baseName;\n\n const isClickable = Boolean(onClick);\n\n const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n if (!isClickable) return;\n if ((e.key === \"Enter\" || e.key === \" \") && !e.repeat) {\n e.preventDefault();\n onClick?.();\n }\n };\n\n const rootClassName = cn(\n \"ods-avatar\",\n `ods-avatar--${size}`,\n `ods-avatar--${shape}`,\n isClickable && \"ods-avatar--clickable\",\n className,\n );\n\n return (\n <div\n {...rest}\n ref={ref}\n className={rootClassName}\n // Only the outer wrapper carries `role=\"img\"` + the merged label. The\n // inner <img> drops out of the AT tree (alt=\"\") so AT doesn't double-\n // announce \"Jane Doe avatar / Jane Doe\".\n role={isClickable ? \"button\" : \"img\"}\n aria-label={accessibleName}\n tabIndex={isClickable ? 0 : undefined}\n onClick={onClick}\n onKeyDown={isClickable ? handleKeyDown : undefined}\n data-status={status}\n >\n <span className=\"ods-avatar__inner\" data-palette={paletteIdx}>\n {showImage ? (\n <img\n src={src}\n alt=\"\"\n className=\"ods-avatar__image\"\n loading={imgLoading}\n decoding=\"async\"\n referrerPolicy={referrerPolicy}\n onError={handleImgError}\n draggable={false}\n />\n ) : icon ? (\n <span className=\"ods-avatar__icon\" aria-hidden=\"true\">\n {icon}\n </span>\n ) : normalizedInitials ? (\n <span className=\"ods-avatar__initials\" aria-hidden=\"true\">\n {normalizedInitials}\n </span>\n ) : (\n <span className=\"ods-avatar__initials\" aria-hidden=\"true\">\n {fallback ?? \"?\"}\n </span>\n )}\n </span>\n {status && (\n // Decorative — the textual status is folded into the wrapper's\n // aria-label above. `aria-hidden` keeps AT from double-announcing.\n <span\n className={cn(\"ods-avatar__status\", `ods-avatar__status--${status}`)}\n aria-hidden=\"true\"\n />\n )}\n </div>\n );\n});\n\nAvatar.displayName = \"Avatar\";\n\n/* ---------------------------------------------------------------------------\n * AvatarStack\n * ------------------------------------------------------------------------- */\n\nexport interface AvatarStackProps\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /** Avatars to display (in left-to-right stacking order). */\n children: ReactNode;\n /** Max avatars to show before collapsing the surplus into `+N`. */\n max?: number;\n /** Size applied to the overflow chip. Defaults to `md`. */\n size?: AvatarSize;\n /** Replace the default `+N` overflow chip. Receives the hidden count. */\n renderOverflow?: (count: number) => ReactNode;\n /** Stacking direction. `ltr` (default) overlaps each successive avatar to\n * the right of the previous one; `rtl` mirrors. */\n direction?: \"ltr\" | \"rtl\";\n}\n\nexport const AvatarStack = forwardRef<HTMLDivElement, AvatarStackProps>(\n function AvatarStack(\n {\n children,\n max,\n size = \"md\",\n renderOverflow,\n direction = \"ltr\",\n className,\n ...rest\n },\n ref,\n ) {\n const arr = Array.isArray(children) ? children : [children];\n const visible = max && arr.length > max ? arr.slice(0, max) : arr;\n const overflow = max && arr.length > max ? arr.length - max : 0;\n\n return (\n <div\n {...rest}\n ref={ref}\n className={cn(\n \"ods-avatar-stack\",\n `ods-avatar-stack--${direction}`,\n className,\n )}\n >\n {visible}\n {overflow > 0 &&\n (renderOverflow ? (\n renderOverflow(overflow)\n ) : (\n <div\n className={cn(\n \"ods-avatar\",\n `ods-avatar--${size}`,\n \"ods-avatar--circle\",\n \"ods-avatar-stack__overflow\",\n )}\n role=\"img\"\n aria-label={`${overflow} more`}\n >\n <span className=\"ods-avatar__inner\">\n <span className=\"ods-avatar__initials\" aria-hidden=\"true\">\n +{overflow}\n </span>\n </span>\n </div>\n ))}\n </div>\n );\n },\n);\n\nAvatarStack.displayName = \"AvatarStack\";\n","\"use client\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type ReactNode,\n useId,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Avatar, type AvatarProps } from \"../Avatar\";\nimport { Card, type CardRadius } from \"../Card\";\n\n/* ---------------------------------------------------------------------------\n * BlogCard — composes on the polished `Card` primitive so it inherits\n * `forwardRef`, native prop spread, keyboard activation, hover/tap\n * microinteractions, and `prefers-reduced-motion` support for free.\n *\n * Adds blog-specific slots on top: cover image with configurable aspect\n * ratio, category chips, author row, reading-time + date meta. Renders\n * as a real `<a>` when `href` is given (via Card.asChild) so the link\n * gets browser semantics (open-in-new-tab, middle-click, etc.).\n * ------------------------------------------------------------------------- */\n\nexport type BlogCardOrientation = \"vertical\" | \"horizontal\";\nexport type BlogCardCoverAspect = \"16/9\" | \"4/3\" | \"1/1\" | \"3/4\" | \"21/9\";\n\nexport interface BlogCardAuthor {\n name: ReactNode;\n /** Optional avatar — passed through to the polished `Avatar` primitive. */\n avatar?: Pick<AvatarProps, \"src\" | \"initials\" | \"alt\">;\n /** Optional role / handle / etc. */\n byline?: ReactNode;\n}\n\nexport interface BlogCardProps\n extends Omit<\n ComponentPropsWithoutRef<\"div\">,\n | \"title\"\n | \"onChange\"\n | \"onDrag\"\n | \"onDragStart\"\n | \"onDragEnd\"\n | \"onAnimationStart\"\n > {\n /** Cover artwork — usually an `<img>` element, but accepts any node. */\n cover?: ReactNode;\n /**\n * Cover aspect ratio. Lets a grid of cards stay visually consistent\n * regardless of source image dimensions. Default `\"16/9\"`.\n */\n coverAspect?: BlogCardCoverAspect;\n /** Single category chip (legacy — prefer `tags`). */\n category?: ReactNode;\n /** Multiple category chips. Rendered before the title. */\n tags?: ReactNode[];\n /** Date / publish info — inline meta. */\n meta?: ReactNode;\n /** Structured reading-time slot. Renders alongside `meta`. */\n readingTime?: ReactNode;\n /** Required title — drives `aria-labelledby` on the card. */\n title: ReactNode;\n /** Heading level for the title. Default `\"h3\"`. */\n titleAs?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\";\n description?: ReactNode;\n /** Structured author block — avatar + name + optional byline. */\n author?: BlogCardAuthor;\n /** Right-aligned footer content (call-to-action / \"Read more\" link). */\n footer?: ReactNode;\n /** Card corner radius. */\n radius?: CardRadius;\n /** Cover on top (default) or cover on left. */\n orientation?: BlogCardOrientation;\n /** When set, the card renders as an `<a>` element. */\n href?: string;\n /** Click handler. Pairing with `href` is fine; both fire. */\n onClick?: () => void;\n}\n\n/* ---------------------------------------------------------------------------\n * Component\n * ------------------------------------------------------------------------- */\n\nexport const BlogCard = forwardRef<HTMLDivElement, BlogCardProps>(\n function BlogCard(\n {\n cover,\n coverAspect = \"16/9\",\n category,\n tags,\n meta,\n readingTime,\n title,\n titleAs = \"h3\",\n description,\n author,\n footer,\n radius = \"md\",\n orientation = \"vertical\",\n href,\n onClick,\n id: providedId,\n className,\n ...rest\n },\n ref,\n ) {\n const reactId = useId();\n const baseId = providedId ?? `ods-blog-card-${reactId}`;\n const titleId = `${baseId}-title`;\n const descId = description ? `${baseId}-desc` : undefined;\n\n // Resolve the tag list — a single `category` is treated as a one-tag\n // list for back-compat with the v1 API.\n const tagList: ReactNode[] = tags ?? (category ? [category] : []);\n\n const body = (\n <>\n {cover && (\n <div\n className={cn(\n \"ods-blog-card__cover\",\n `ods-blog-card__cover--aspect-${coverAspect.replace(\"/\", \"-\")}`,\n )}\n aria-hidden=\"true\"\n >\n {cover}\n </div>\n )}\n\n <div className=\"ods-blog-card__body\">\n {(tagList.length > 0 || meta || readingTime) && (\n <div className=\"ods-blog-card__meta\">\n {tagList.length > 0 && (\n <span className=\"ods-blog-card__tags\">\n {tagList.map((t, i) => (\n <span key={i} className=\"ods-blog-card__tag\">\n {t}\n </span>\n ))}\n </span>\n )}\n {meta && <span className=\"ods-blog-card__date\">{meta}</span>}\n {readingTime && (\n <span className=\"ods-blog-card__reading\">{readingTime}</span>\n )}\n </div>\n )}\n\n <Card.Title\n as={titleAs}\n id={titleId}\n className=\"ods-blog-card__title\"\n >\n {title}\n </Card.Title>\n\n {description && (\n <Card.Description\n id={descId}\n className=\"ods-blog-card__desc\"\n >\n {description}\n </Card.Description>\n )}\n\n {(author || footer) && (\n <div className=\"ods-blog-card__footer\">\n {author && (\n <div className=\"ods-blog-card__author\">\n {author.avatar && (\n <Avatar\n size=\"sm\"\n src={author.avatar.src}\n initials={author.avatar.initials}\n alt={\n author.avatar.alt ??\n (typeof author.name === \"string\"\n ? author.name\n : undefined)\n }\n />\n )}\n <div className=\"ods-blog-card__author-text\">\n <span className=\"ods-blog-card__author-name\">\n {author.name}\n </span>\n {author.byline && (\n <span className=\"ods-blog-card__author-byline\">\n {author.byline}\n </span>\n )}\n </div>\n </div>\n )}\n {footer && <div className=\"ods-blog-card__action\">{footer}</div>}\n </div>\n )}\n </div>\n </>\n );\n\n // `href` → render as a real <a> via Card.asChild for browser-native\n // link semantics (open-in-new-tab, middle-click, copy-link, etc.).\n if (href) {\n return (\n <Card\n asChild\n radius={radius}\n padding=\"none\"\n className={cn(\n \"ods-blog-card\",\n `ods-blog-card--${orientation}`,\n \"ods-blog-card--interactive\",\n className,\n )}\n aria-labelledby={titleId}\n aria-describedby={descId}\n >\n <a\n // `rest` is typed against HTMLDivElement handlers (BlogCardProps\n // extends div). The anchor accepts the same attributes\n // structurally at runtime, but TS sees\n // KeyboardEventHandler<HTMLDivElement> ≠ <HTMLAnchorElement>.\n // Route through `unknown` — TS's recommended escape hatch\n // when we know the runtime is safe.\n {...(rest as unknown as ComponentPropsWithoutRef<\"a\">)}\n ref={ref as unknown as React.Ref<HTMLAnchorElement>}\n href={href}\n id={baseId}\n onClick={onClick}\n >\n {body}\n </a>\n </Card>\n );\n }\n\n return (\n <Card\n {...rest}\n ref={ref}\n id={baseId}\n radius={radius}\n padding=\"none\"\n onClick={onClick}\n className={cn(\n \"ods-blog-card\",\n `ods-blog-card--${orientation}`,\n onClick && \"ods-blog-card--interactive\",\n className,\n )}\n aria-labelledby={titleId}\n aria-describedby={descId}\n >\n {body}\n </Card>\n );\n },\n);\n\nBlogCard.displayName = \"BlogCard\";\n","\"use client\";\nimport type { RefObject } from \"react\";\nimport {\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\n/* ---------------------------------------------------------------------------\n * useTextareaCommands — inline `/command` palette for a textarea.\n *\n * const cmd = useTextareaCommands({\n * textareaRef,\n * value,\n * onChange,\n * commands: [\n * { id: \"today\", label: \"Today\", insert: () => new Date().toDateString() },\n * { id: \"summary\", label: \"AI Summary\", insert: \"{{ai.summary}}\" },\n * ],\n * trigger: \"/\", // default\n * openOnEmptyTrigger: true,\n * });\n *\n * <Textarea ... commands={cmd.props} /> // or wire manually\n *\n * The hook owns: trigger detection, filtering, keyboard nav, caret-aware\n * insertion. The consumer / Textarea owns rendering the popover.\n * ------------------------------------------------------------------------- */\n\nexport interface TextareaCommand {\n id: string;\n label: ReactNode;\n description?: ReactNode;\n icon?: ReactNode;\n /** Text to insert at the caret. Can be a string OR a function that\n * receives the live query and returns the string — useful for\n * commands that consume the typed query (e.g. `/mention bob` →\n * `@bob`). */\n insert: string | ((query: string) => string);\n /** Extra keywords to match against the typed query in addition to\n * the rendered `label` (when label is a string) and `description`. */\n keywords?: string[];\n}\n\nexport interface UseTextareaCommandsOptions {\n textareaRef: RefObject<HTMLTextAreaElement | null>;\n /** Controlled value — pass the same string you pass to the textarea. */\n value: string;\n /** Setter — receives the new full value after insertion. */\n onChange: (next: string) => void;\n commands: TextareaCommand[];\n /** Trigger character. Default `\"/\"`. */\n trigger?: string;\n /** Open the palette as soon as the trigger is typed (even with no\n * query). Default `true`. Set `false` if you want consumers to type\n * at least one character to open. */\n openOnEmptyTrigger?: boolean;\n /** Maximum visible items in the filtered result list. Default 8. */\n maxItems?: number;\n}\n\nexport interface UseTextareaCommandsReturn {\n /** Whether the palette is currently open. */\n isOpen: boolean;\n /** Query typed after the trigger (without the trigger character). */\n query: string;\n /** Highlighted item index (0-based). */\n activeIndex: number;\n /** Filtered + capped list of matching commands. */\n items: TextareaCommand[];\n\n /** Keydown handler — wire to the textarea's `onKeyDown`. Returns\n * `true` if the key was consumed (so the consumer can stop). */\n onKeyDown: (e: ReactKeyboardEvent<HTMLTextAreaElement>) => boolean;\n /** Force-close the palette (e.g. on textarea blur). */\n dismiss: () => void;\n /** Commit the supplied command — inserts its text at the trigger\n * position and consumes the trigger + query. */\n commit: (cmd: TextareaCommand) => void;\n\n /** Pixel position of the caret at the moment the palette opened.\n * Use to anchor the popover in your own UI. */\n caretRect: DOMRect | null;\n}\n\n/* ---------------------------------------------------------------------------\n * Helpers\n * ------------------------------------------------------------------------- */\n\n/** Find the nearest trigger character behind the caret (within the\n * current line) and return the index + query string. Returns `null`\n * when no open trigger is in scope (e.g. there's whitespace between\n * the trigger and the caret, or the caret is mid-word that doesn't\n * start with the trigger). */\nfunction findOpenTrigger(\n value: string,\n caret: number,\n trigger: string,\n): { triggerIndex: number; query: string } | null {\n // Walk backwards from the caret looking for the trigger char OR a\n // whitespace boundary. Whitespace closes the trigger window.\n let i = caret - 1;\n while (i >= 0) {\n const ch = value[i];\n if (ch === \"\\n\" || ch === \" \" || ch === \"\\t\") return null;\n if (value.startsWith(trigger, i)) {\n // Trigger must be at the start of input OR preceded by whitespace\n // / newline. Stops \"https://\" from opening a command palette.\n const before = i === 0 ? \"\" : value[i - 1];\n if (\n i === 0 ||\n before === \" \" ||\n before === \"\\n\" ||\n before === \"\\t\"\n ) {\n return {\n triggerIndex: i,\n query: value.slice(i + trigger.length, caret),\n };\n }\n return null;\n }\n i--;\n }\n return null;\n}\n\n/** Approximate caret-pixel-rect for a textarea using a mirror div.\n * Browsers don't expose the caret position natively for textareas. */\nfunction getCaretRect(\n textarea: HTMLTextAreaElement,\n caret: number,\n): DOMRect | null {\n if (typeof document === \"undefined\") return null;\n const mirror = document.createElement(\"div\");\n const styles = window.getComputedStyle(textarea);\n // Copy the visual properties that affect line-wrapping + glyph metrics.\n for (const prop of [\n \"boxSizing\",\n \"width\",\n \"fontFamily\",\n \"fontSize\",\n \"fontWeight\",\n \"fontStyle\",\n \"letterSpacing\",\n \"lineHeight\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"borderTopWidth\",\n \"borderRightWidth\",\n \"borderBottomWidth\",\n \"borderLeftWidth\",\n \"textTransform\",\n \"wordSpacing\",\n \"tabSize\",\n \"whiteSpace\",\n ] as const) {\n (mirror.style as unknown as Record<string, string>)[prop] = styles[prop];\n }\n mirror.style.position = \"absolute\";\n mirror.style.visibility = \"hidden\";\n mirror.style.overflow = \"hidden\";\n mirror.style.top = \"0\";\n mirror.style.left = \"0\";\n mirror.style.whiteSpace = \"pre-wrap\";\n mirror.style.wordWrap = \"break-word\";\n mirror.textContent = textarea.value.slice(0, caret);\n const marker = document.createElement(\"span\");\n marker.textContent = \"​\"; // zero-width space → measurable\n mirror.appendChild(marker);\n document.body.appendChild(mirror);\n\n const taRect = textarea.getBoundingClientRect();\n const markerRect = marker.getBoundingClientRect();\n const mirrorRect = mirror.getBoundingClientRect();\n const x = taRect.left + (markerRect.left - mirrorRect.left) -\n textarea.scrollLeft;\n const y = taRect.top + (markerRect.top - mirrorRect.top) -\n textarea.scrollTop;\n const out = new DOMRect(x, y, 0, markerRect.height || 16);\n document.body.removeChild(mirror);\n return out;\n}\n\n/* ---------------------------------------------------------------------------\n * Hook\n * ------------------------------------------------------------------------- */\n\nexport function useTextareaCommands({\n textareaRef,\n value,\n onChange,\n commands,\n trigger = \"/\",\n openOnEmptyTrigger = true,\n maxItems = 8,\n}: UseTextareaCommandsOptions): UseTextareaCommandsReturn {\n const [isOpen, setIsOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n const [triggerIndex, setTriggerIndex] = useState<number | null>(null);\n const [caretRect, setCaretRect] = useState<DOMRect | null>(null);\n // Tracks the (value, caret) snapshot at the moment the user dismissed\n // the palette. The trigger-detect effect skips re-opening when the\n // current state still matches — without this guard, Escape would\n // dismiss but the very next effect run would re-open the palette\n // because the trigger char is still in scope.\n const dismissedAtRef = useRef<{ value: string; caret: number } | null>(\n null,\n );\n\n /* ── Filter the command list against the current query ── */\n const items = useMemo(() => {\n const q = query.trim().toLowerCase();\n if (!q) return commands.slice(0, maxItems);\n return commands\n .filter((c) => {\n const hay = [\n typeof c.label === \"string\" ? c.label : \"\",\n typeof c.description === \"string\" ? c.description : \"\",\n c.id,\n ...(c.keywords ?? []),\n ]\n .join(\" \")\n .toLowerCase();\n return hay.includes(q);\n })\n .slice(0, maxItems);\n }, [commands, query, maxItems]);\n\n /* ── Re-evaluate the trigger window on every value or caret change ── */\n useEffect(() => {\n const ta = textareaRef.current;\n if (!ta) return;\n const caret = ta.selectionStart ?? 0;\n // If the user dismissed at this exact (value, caret), don't reopen.\n const dismissedAt = dismissedAtRef.current;\n if (\n dismissedAt &&\n dismissedAt.value === value &&\n dismissedAt.caret === caret\n ) {\n return;\n }\n const found = findOpenTrigger(value, caret, trigger);\n if (!found) {\n if (isOpen) setIsOpen(false);\n setTriggerIndex(null);\n return;\n }\n // Clear the dismissed snapshot once the user moves out of it —\n // future trigger events are real, not stale.\n if (dismissedAt) dismissedAtRef.current = null;\n // Open if the trigger is in scope AND either we already have a\n // query OR `openOnEmptyTrigger` allows opening on the bare trigger.\n if (found.query.length > 0 || openOnEmptyTrigger) {\n setQuery(found.query);\n setTriggerIndex(found.triggerIndex);\n setIsOpen(true);\n // Reset highlight when the query changes — keeps it pinned to\n // the top match.\n setActiveIndex(0);\n setCaretRect(getCaretRect(ta, caret));\n }\n }, [value, trigger, openOnEmptyTrigger, isOpen, textareaRef]);\n\n /* ── Commit a chosen command ── */\n const commit = useCallback(\n (cmd: TextareaCommand) => {\n const ta = textareaRef.current;\n if (!ta || triggerIndex == null) return;\n const insertText =\n typeof cmd.insert === \"function\" ? cmd.insert(query) : cmd.insert;\n const caret = ta.selectionStart ?? value.length;\n const before = value.slice(0, triggerIndex);\n const after = value.slice(caret);\n const next = `${before}${insertText}${after}`;\n // Snapshot the post-commit caret position so the trigger-detect\n // effect doesn't immediately reopen against the original\n // (unchanged) value when the consumer's onChange is async or\n // a no-op (e.g. in tests).\n dismissedAtRef.current = {\n value,\n caret,\n };\n onChange(next);\n setIsOpen(false);\n setTriggerIndex(null);\n // Restore caret to the end of the inserted text on the next frame.\n requestAnimationFrame(() => {\n const pos = before.length + insertText.length;\n ta.focus();\n ta.setSelectionRange(pos, pos);\n });\n },\n [textareaRef, triggerIndex, query, value, onChange],\n );\n\n const dismiss = useCallback(() => {\n const ta = textareaRef.current;\n dismissedAtRef.current = {\n value,\n caret: ta?.selectionStart ?? value.length,\n };\n setIsOpen(false);\n setTriggerIndex(null);\n }, [textareaRef, value]);\n\n /* ── Keyboard nav while the palette is open ── */\n const onKeyDown = useCallback(\n (e: ReactKeyboardEvent<HTMLTextAreaElement>): boolean => {\n if (!isOpen) return false;\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActiveIndex((i) => Math.min(items.length - 1, i + 1));\n return true;\n }\n if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActiveIndex((i) => Math.max(0, i - 1));\n return true;\n }\n if (e.key === \"Enter\" || e.key === \"Tab\") {\n const pick = items[activeIndex];\n if (pick) {\n e.preventDefault();\n commit(pick);\n return true;\n }\n }\n if (e.key === \"Escape\") {\n e.preventDefault();\n dismiss();\n return true;\n }\n return false;\n },\n [isOpen, items, activeIndex, commit, dismiss],\n );\n\n return {\n isOpen,\n query,\n activeIndex,\n items,\n onKeyDown,\n dismiss,\n commit,\n caretRect,\n };\n}\n","\"use client\";\nimport type { RefObject } from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\n\n/* ---------------------------------------------------------------------------\n * useTextareaSelection — selection state + clipboard / wrap helpers.\n *\n * const sel = useTextareaSelection({ textareaRef, value, onChange });\n *\n * if (sel.active) {\n * // user has highlighted text — render a floating toolbar\n * sel.copy(); // copies selection to clipboard\n * sel.cut(); // copies + deletes\n * sel.wrap(\"**\",\"**\"); // selection becomes **selection**\n * sel.replace(\"...\"); // replace the selection with a literal string\n * }\n *\n * The hook tracks the selection across `selectionchange` events (more\n * reliable than `select` for shift-arrow nav). Returns a pixel rect for\n * the SELECTION so callers can anchor a floating toolbar above it.\n * ------------------------------------------------------------------------- */\n\nexport interface UseTextareaSelectionOptions {\n textareaRef: RefObject<HTMLTextAreaElement | null>;\n /** Current textarea value. */\n value: string;\n /** Setter — called when `cut`/`wrap`/`replace` mutate the text. */\n onChange: (next: string) => void;\n}\n\nexport interface UseTextareaSelectionReturn {\n /** True when there's a non-empty selection in the focused textarea. */\n active: boolean;\n /** Selected text. Empty string when `active` is false. */\n text: string;\n /** Character offsets. */\n start: number;\n end: number;\n /** Approximate pixel rect of the selection — anchor a floating\n * toolbar above this (`top - toolbar.height - 4`). Null when no\n * active selection. */\n rect: DOMRect | null;\n\n /** Copy the current selection to the clipboard. Resolves with `true`\n * on success. */\n copy: () => Promise<boolean>;\n /** Copy + delete (= cut). Resolves `true` on success. */\n cut: () => Promise<boolean>;\n /** Wrap the selection with `open` / `close` strings. Selection\n * expands to include the wrappers. */\n wrap: (open: string, close?: string) => void;\n /** Replace the selection with a literal string. Caret lands at the\n * end of the inserted text. */\n replace: (text: string) => void;\n}\n\n/* ---------------------------------------------------------------------------\n * Helpers — selection-rect via a measured mirror div (same recipe as\n * useTextareaCommands' caret-rect helper, expanded to cover a range).\n * ------------------------------------------------------------------------- */\n\nfunction getSelectionRect(\n textarea: HTMLTextAreaElement,\n start: number,\n end: number,\n): DOMRect | null {\n if (typeof document === \"undefined\") return null;\n if (start === end) return null;\n const mirror = document.createElement(\"div\");\n const styles = window.getComputedStyle(textarea);\n for (const prop of [\n \"boxSizing\",\n \"width\",\n \"fontFamily\",\n \"fontSize\",\n \"fontWeight\",\n \"fontStyle\",\n \"letterSpacing\",\n \"lineHeight\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n \"borderTopWidth\",\n \"borderRightWidth\",\n \"borderBottomWidth\",\n \"borderLeftWidth\",\n \"textTransform\",\n \"wordSpacing\",\n \"tabSize\",\n \"whiteSpace\",\n ] as const) {\n (mirror.style as unknown as Record<string, string>)[prop] = styles[prop];\n }\n mirror.style.position = \"absolute\";\n mirror.style.visibility = \"hidden\";\n mirror.style.overflow = \"hidden\";\n mirror.style.top = \"0\";\n mirror.style.left = \"0\";\n mirror.style.whiteSpace = \"pre-wrap\";\n mirror.style.wordWrap = \"break-word\";\n\n const pre = document.createTextNode(textarea.value.slice(0, start));\n const range = document.createElement(\"span\");\n range.textContent = textarea.value.slice(start, end) || \"​\";\n const post = document.createTextNode(textarea.value.slice(end));\n\n mirror.appendChild(pre);\n mirror.appendChild(range);\n mirror.appendChild(post);\n document.body.appendChild(mirror);\n\n const taRect = textarea.getBoundingClientRect();\n const rangeRect = range.getBoundingClientRect();\n const mirrorRect = mirror.getBoundingClientRect();\n const out = new DOMRect(\n taRect.left + (rangeRect.left - mirrorRect.left) - textarea.scrollLeft,\n taRect.top + (rangeRect.top - mirrorRect.top) - textarea.scrollTop,\n rangeRect.width,\n rangeRect.height,\n );\n document.body.removeChild(mirror);\n return out;\n}\n\n/* ---------------------------------------------------------------------------\n * Hook\n * ------------------------------------------------------------------------- */\n\nexport function useTextareaSelection({\n textareaRef,\n value,\n onChange,\n}: UseTextareaSelectionOptions): UseTextareaSelectionReturn {\n const [start, setStart] = useState(0);\n const [end, setEnd] = useState(0);\n const [rect, setRect] = useState<DOMRect | null>(null);\n\n /* ── Subscribe to selectionchange (fires on caret moves + drags) ── */\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n const handler = () => {\n const ta = textareaRef.current;\n if (!ta || document.activeElement !== ta) {\n setStart(0);\n setEnd(0);\n setRect(null);\n return;\n }\n const s = ta.selectionStart ?? 0;\n const e = ta.selectionEnd ?? 0;\n setStart(s);\n setEnd(e);\n setRect(s !== e ? getSelectionRect(ta, s, e) : null);\n };\n document.addEventListener(\"selectionchange\", handler);\n return () => document.removeEventListener(\"selectionchange\", handler);\n }, [textareaRef]);\n\n const active = start !== end;\n const text = active ? value.slice(start, end) : \"\";\n\n const writeToClipboard = useCallback(\n async (str: string): Promise<boolean> => {\n try {\n if (\n typeof navigator !== \"undefined\" &&\n navigator.clipboard?.writeText\n ) {\n await navigator.clipboard.writeText(str);\n return true;\n }\n } catch {\n /* fall through to execCommand fallback */\n }\n // Legacy fallback for permission-denied environments. Uses an\n // off-screen textarea so we don't disturb the user's selection.\n try {\n const tmp = document.createElement(\"textarea\");\n tmp.value = str;\n tmp.style.position = \"fixed\";\n tmp.style.left = \"-9999px\";\n document.body.appendChild(tmp);\n tmp.select();\n const ok = document.execCommand(\"copy\");\n document.body.removeChild(tmp);\n return ok;\n } catch {\n return false;\n }\n },\n [],\n );\n\n const copy = useCallback(async () => {\n if (!active) return false;\n return writeToClipboard(text);\n }, [active, text, writeToClipboard]);\n\n const replace = useCallback(\n (str: string) => {\n const ta = textareaRef.current;\n if (!ta) return;\n const next = value.slice(0, start) + str + value.slice(end);\n onChange(next);\n requestAnimationFrame(() => {\n ta.focus();\n const caret = start + str.length;\n ta.setSelectionRange(caret, caret);\n });\n },\n [textareaRef, value, start, end, onChange],\n );\n\n const cut = useCallback(async () => {\n if (!active) return false;\n const ok = await writeToClipboard(text);\n if (ok) replace(\"\");\n return ok;\n }, [active, text, writeToClipboard, replace]);\n\n const wrap = useCallback(\n (open: string, close?: string) => {\n const ta = textareaRef.current;\n if (!ta) return;\n const closing = close ?? open;\n const before = value.slice(0, start);\n const sel = value.slice(start, end);\n const after = value.slice(end);\n const next = `${before}${open}${sel}${closing}${after}`;\n onChange(next);\n requestAnimationFrame(() => {\n ta.focus();\n // Re-select the wrapped content (including the wrappers) so\n // the user sees the result and can keep working.\n const newStart = start;\n const newEnd = end + open.length + closing.length;\n ta.setSelectionRange(newStart, newEnd);\n });\n },\n [textareaRef, value, start, end, onChange],\n );\n\n return {\n active,\n text,\n start,\n end,\n rect,\n copy,\n cut,\n wrap,\n replace,\n };\n}\n","\"use client\";\nimport {\n CodeIcon,\n HeadingIcon,\n ListBulletedIcon,\n ListNumberedIcon,\n QuotesIcon,\n RedoIcon,\n TextBoldIcon,\n TextItalicIcon,\n TextLinkIcon,\n TextStrikethroughIcon,\n UndoIcon,\n} from \"@octaviaflow/icons\";\nimport type { RefObject } from \"react\";\nimport { type ReactNode, useCallback, useMemo, useRef } from \"react\";\n\n/* ---------------------------------------------------------------------------\n * useTextareaTools — toolbar tools + always-on editor helpers.\n *\n * The \"third tier\" of the textarea editor section, sitting alongside:\n * - `useTextareaCommands` (inline `/command` palette)\n * - `useTextareaSelection` (selection-only toolbar)\n *\n * Tools are always-visible buttons rendered in a toolbar above/below the\n * textarea (think Markdown editor chrome: B / I / Code / Link / Quote).\n * Each tool receives a `helpers` bundle that exposes the underlying\n * editing primitives (selection, caret, line-aware mutations, undo).\n *\n * Consumers can:\n * - Compose any combination of built-in tools from the\n * `textareaTools` factory\n * - Mix in fully custom tools (`{ id, label, icon, onAction }`)\n * - Drive the hook directly to build their own toolbar UI\n * ------------------------------------------------------------------------- */\n\nexport interface TextareaToolHelpers {\n /** Current full text. */\n value: string;\n /** Current selection / caret state. */\n selection: {\n text: string;\n start: number;\n end: number;\n active: boolean;\n };\n /** Replace the entire textarea content. */\n setValue: (next: string) => void;\n /** Replace the selection with `text` (inserts at caret when no\n * selection is active). Caret lands after the inserted text. */\n replace: (text: string) => void;\n /** Insert `text` at the caret without disturbing the selection's\n * surrounding content. Identical to `replace` when nothing is\n * selected. */\n insert: (text: string) => void;\n /** Wrap the selection with `open` / `close` strings. When no\n * selection is active, drops the markers around an empty span at\n * the caret. Caret ends up between them so the user can type. */\n wrap: (open: string, close?: string) => void;\n /** Prepend `prefix` to the start of every line that overlaps the\n * selection (or just the caret's line when no selection). Useful for\n * list / quote / heading tools. */\n prependLines: (prefix: string) => void;\n /** Programmatic undo / redo via the native execCommand bridge.\n * Falls back silently when the browser doesn't expose it. */\n undo: () => void;\n redo: () => void;\n /** Direct access to the underlying DOM node for cases the abstraction\n * doesn't cover. */\n getTextarea: () => HTMLTextAreaElement | null;\n}\n\nexport interface TextareaTool {\n id: string;\n label: ReactNode;\n icon?: ReactNode;\n /** Title attribute for the toolbar button. Defaults to the `label`\n * when it's a string. */\n title?: string;\n /** Visual treatment — `\"divider\"` renders a vertical separator\n * instead of a button. Otherwise `\"button\"`. */\n kind?: \"button\" | \"divider\";\n /** Fires when the toolbar button is clicked. Receives a helpers\n * bundle that proxies the editing primitives. Can be async. */\n onAction?: (helpers: TextareaToolHelpers) => void | Promise<void>;\n /** Hide the button when this predicate returns false. Re-evaluated\n * on every value / selection change. Useful for \"only show Link\n * when something is selected\" patterns. */\n isVisible?: (helpers: TextareaToolHelpers) => boolean;\n}\n\nexport interface UseTextareaToolsOptions {\n textareaRef: RefObject<HTMLTextAreaElement | null>;\n value: string;\n onChange: (next: string) => void;\n tools: TextareaTool[];\n}\n\nexport interface UseTextareaToolsReturn {\n /** Filtered + ready-to-render tools (visibility predicates applied). */\n tools: TextareaTool[];\n /** Invoke a tool by id. */\n runTool: (id: string) => Promise<void>;\n /** Snapshot helpers — same object passed into `onAction` so consumers\n * can call them outside the toolbar (e.g. from a keyboard shortcut). */\n helpers: TextareaToolHelpers;\n}\n\n/* ---------------------------------------------------------------------------\n * Hook\n * ------------------------------------------------------------------------- */\n\nexport function useTextareaTools({\n textareaRef,\n value,\n onChange,\n tools,\n}: UseTextareaToolsOptions): UseTextareaToolsReturn {\n // Keep latest value in a ref so tool callbacks always see the\n // up-to-date string, even when chained synchronously.\n const valueRef = useRef(value);\n valueRef.current = value;\n\n const helpers = useMemo<TextareaToolHelpers>(() => {\n const getTa = () => textareaRef.current;\n\n const getSelection = () => {\n const ta = getTa();\n const s = ta?.selectionStart ?? 0;\n const e = ta?.selectionEnd ?? 0;\n return {\n text: valueRef.current.slice(s, e),\n start: s,\n end: e,\n active: s !== e,\n };\n };\n\n const setValue = (next: string) => onChange(next);\n\n const replace = (text: string) => {\n const ta = getTa();\n if (!ta) return;\n const { start, end } = getSelection();\n const next =\n valueRef.current.slice(0, start) + text + valueRef.current.slice(end);\n onChange(next);\n requestAnimationFrame(() => {\n ta.focus();\n const caret = start + text.length;\n ta.setSelectionRange(caret, caret);\n });\n };\n\n const insert = (text: string) => replace(text);\n\n const wrap = (open: string, close?: string) => {\n const ta = getTa();\n if (!ta) return;\n const closing = close ?? open;\n const { start, end } = getSelection();\n const sel = valueRef.current.slice(start, end);\n const next =\n valueRef.current.slice(0, start) +\n open +\n sel +\n closing +\n valueRef.current.slice(end);\n onChange(next);\n requestAnimationFrame(() => {\n ta.focus();\n if (start === end) {\n // Empty selection — drop the caret between the wrappers so\n // the user can type the body content right away.\n const caret = start + open.length;\n ta.setSelectionRange(caret, caret);\n } else {\n ta.setSelectionRange(start, end + open.length + closing.length);\n }\n });\n };\n\n const prependLines = (prefix: string) => {\n const ta = getTa();\n if (!ta) return;\n const { start, end } = getSelection();\n // Expand selection to whole lines so prefixes land at line starts.\n const v = valueRef.current;\n const lineStart = v.lastIndexOf(\"\\n\", start - 1) + 1;\n const lineEnd = (() => {\n const idx = v.indexOf(\"\\n\", end);\n return idx === -1 ? v.length : idx;\n })();\n const block = v.slice(lineStart, lineEnd);\n const updated = block\n .split(\"\\n\")\n .map((line) => `${prefix}${line}`)\n .join(\"\\n\");\n const next = v.slice(0, lineStart) + updated + v.slice(lineEnd);\n onChange(next);\n requestAnimationFrame(() => {\n ta.focus();\n ta.setSelectionRange(\n lineStart,\n lineStart + updated.length,\n );\n });\n };\n\n const undo = () => {\n try {\n getTa()?.focus();\n document.execCommand(\"undo\");\n } catch {\n /* not all browsers expose undo via execCommand */\n }\n };\n const redo = () => {\n try {\n getTa()?.focus();\n document.execCommand(\"redo\");\n } catch {\n /* same */\n }\n };\n\n return {\n get value() {\n return valueRef.current;\n },\n get selection() {\n return getSelection();\n },\n setValue,\n replace,\n insert,\n wrap,\n prependLines,\n undo,\n redo,\n getTextarea: getTa,\n };\n }, [textareaRef, onChange]);\n\n // Visibility filter — re-evaluated each render so predicates that\n // depend on the current selection update naturally.\n const visibleTools = useMemo(\n () => tools.filter((t) => (t.isVisible ? t.isVisible(helpers) : true)),\n [tools, helpers],\n );\n\n const runTool = useCallback(\n async (id: string) => {\n const tool = tools.find((t) => t.id === id);\n if (!tool || tool.kind === \"divider\") return;\n await tool.onAction?.(helpers);\n },\n [tools, helpers],\n );\n\n return { tools: visibleTools, runTool, helpers };\n}\n\n/* ---------------------------------------------------------------------------\n * `textareaTools` — factory for the built-in Markdown/editor tools.\n *\n * Each factory returns a `TextareaTool`. Consumers compose them freely:\n *\n * tools={[\n * textareaTools.bold(),\n * textareaTools.italic(),\n * textareaTools.divider(),\n * textareaTools.bulletList(),\n * textareaTools.numberedList(),\n * textareaTools.divider(),\n * textareaTools.link(),\n * myCustomTool,\n * ]}\n * ------------------------------------------------------------------------- */\n\nconst wrapTool = (\n id: string,\n open: string,\n close: string,\n label: ReactNode,\n icon: ReactNode,\n title?: string,\n): TextareaTool => ({\n id,\n label,\n icon,\n title,\n onAction: (h) => h.wrap(open, close),\n});\n\nconst prependLineTool = (\n id: string,\n prefix: string,\n label: ReactNode,\n icon: ReactNode,\n title?: string,\n): TextareaTool => ({\n id,\n label,\n icon,\n title,\n onAction: (h) => h.prependLines(prefix),\n});\n\nexport const textareaTools = {\n bold: (): TextareaTool =>\n wrapTool(\"bold\", \"**\", \"**\", \"Bold\", <TextBoldIcon />, \"Bold (⌘B)\"),\n\n italic: (): TextareaTool =>\n wrapTool(\"italic\", \"*\", \"*\", \"Italic\", <TextItalicIcon />, \"Italic (⌘I)\"),\n\n strikethrough: (): TextareaTool =>\n wrapTool(\n \"strike\",\n \"~~\",\n \"~~\",\n \"Strikethrough\",\n <TextStrikethroughIcon />,\n \"Strikethrough\",\n ),\n\n code: (): TextareaTool =>\n wrapTool(\"code\", \"`\", \"`\", \"Code\", <CodeIcon />, \"Inline code\"),\n\n codeBlock: (): TextareaTool => ({\n id: \"code-block\",\n label: \"Code block\",\n icon: <CodeIcon />,\n title: \"Code block\",\n onAction: (h) => h.wrap(\"```\\n\", \"\\n```\"),\n }),\n\n link: (): TextareaTool => ({\n id: \"link\",\n label: \"Link\",\n icon: <TextLinkIcon />,\n title: \"Insert link\",\n onAction: (h) => {\n const sel = h.selection;\n const text = sel.active ? sel.text : \"link text\";\n h.replace(`[${text}](https://)`);\n },\n }),\n\n /** Heading. Defaults to H2. Pass a `level` (1–6) to override. */\n heading: (level: 1 | 2 | 3 | 4 | 5 | 6 = 2): TextareaTool =>\n prependLineTool(\n `heading-${level}`,\n `${\"#\".repeat(level)} `,\n `H${level}`,\n <HeadingIcon />,\n `Heading ${level}`,\n ),\n\n bulletList: (): TextareaTool =>\n prependLineTool(\n \"ul\",\n \"- \",\n \"Bullet list\",\n <ListBulletedIcon />,\n \"Bullet list\",\n ),\n\n numberedList: (): TextareaTool =>\n prependLineTool(\n \"ol\",\n \"1. \",\n \"Numbered list\",\n <ListNumberedIcon />,\n \"Numbered list\",\n ),\n\n quote: (): TextareaTool =>\n prependLineTool(\n \"quote\",\n \"> \",\n \"Quote\",\n <QuotesIcon />,\n \"Quote\",\n ),\n\n undo: (): TextareaTool => ({\n id: \"undo\",\n label: \"Undo\",\n icon: <UndoIcon />,\n title: \"Undo (⌘Z)\",\n onAction: (h) => h.undo(),\n }),\n\n redo: (): TextareaTool => ({\n id: \"redo\",\n label: \"Redo\",\n icon: <RedoIcon />,\n title: \"Redo (⌘⇧Z)\",\n onAction: (h) => h.redo(),\n }),\n\n divider: (id = \"divider\"): TextareaTool => ({\n id: `${id}-${Math.random().toString(36).slice(2, 8)}`,\n label: \"\",\n kind: \"divider\",\n }),\n};\n","\"use client\";\nimport {\n type ComponentPropsWithoutRef,\n type CSSProperties,\n forwardRef,\n type ReactNode,\n useEffect,\n useId,\n useRef,\n useState,\n} from \"react\";\nimport { useTextField } from \"react-aria\";\nimport { createPortal } from \"react-dom\";\nimport { CopyIcon, CutIcon } from \"@octaviaflow/icons\";\nimport {\n type TextareaCommand,\n useTextareaCommands,\n} from \"../../hooks/useTextareaCommands\";\nimport { useTextareaSelection } from \"../../hooks/useTextareaSelection\";\nimport {\n type TextareaTool,\n useTextareaTools,\n} from \"../../hooks/useTextareaTools\";\nimport { resolveAccessibleName } from \"../../utils/a11y\";\nimport { cn } from \"../../utils/cn\";\n\n/* ---------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\nexport type TextareaSize = \"sm\" | \"md\" | \"lg\";\n\n/** User-resize handle direction. Mirrors the native CSS `resize`\n * property. Pass `false` (legacy) and we map it to `\"none\"`. */\nexport type TextareaResize =\n | \"vertical\"\n | \"horizontal\"\n | \"both\"\n | \"none\"\n | boolean;\n\ntype TextareaPropsBase = Omit<\n ComponentPropsWithoutRef<\"textarea\">,\n \"size\" | \"prefix\"\n>;\n\nexport interface TextareaProps extends TextareaPropsBase {\n /** Visible label — accepts rich content. */\n label?: ReactNode;\n /** Boolean error flag — pairs with `errorMessage`. (Back-compat with v1.) */\n error?: boolean;\n /** Error message. When set with `error={true}` renders below the input\n * with `role=\"alert\"` and tints the border. */\n errorMessage?: ReactNode;\n /** Helper text rendered below the field when no error is set. */\n helperText?: ReactNode;\n /** User-drag resize handle direction. Default `\"vertical\"`.\n *\n * - `\"vertical\"` — only the bottom edge is draggable (most common).\n * - `\"horizontal\"` — only the right edge.\n * - `\"both\"` — corner handle, both axes.\n * - `\"none\"` — no user resize (auto-grow still works if enabled).\n * - Legacy `boolean` — `true` ≡ `\"vertical\"`, `false` ≡ `\"none\"`.\n */\n resize?: TextareaResize;\n /** Auto-grow the textarea as the user types, capped at `maxRows`.\n * Default `false`. When enabled the user-drag `resize` handle is\n * typically set to `\"none\"` so the two systems don't fight. */\n autoResize?: boolean;\n /** Minimum visible rows (only when `autoResize` is on). Default `rows`. */\n minRows?: number;\n /** Maximum visible rows before the textarea scrolls (only when\n * `autoResize` is on). Default `Infinity`. */\n maxRows?: number;\n /** Hard pixel ceiling on the textarea's height — applied as inline\n * `max-height`. Pair with `autoResize` to cap the auto-grow OR use\n * alone to limit how tall the user can drag the resize handle. */\n maxHeight?: number | string;\n /** Hard pixel ceiling on the textarea's width — applied as inline\n * `max-width`. Useful when `resize=\"horizontal\"` or `\"both\"`. */\n maxWidth?: number | string;\n /** Minimum pixel floor for the textarea's height. */\n minHeight?: number | string;\n /** Minimum pixel floor for the textarea's width. */\n minWidth?: number | string;\n maxLength?: number;\n size?: TextareaSize;\n rows?: number;\n\n /* ─── Inline command palette + selection toolbar ─────────────────\n *\n * These two opt-in sections live below / above the textarea while\n * the user is editing, giving the field a \"rich editor\" feel without\n * pulling in a contenteditable + range library:\n *\n * - `commands` → typing the trigger (default `/`) opens an\n * inline popover with the supplied commands. Arrow keys + Enter\n * commit. Each command's `insert` is appended at the caret with\n * the trigger + query removed automatically.\n *\n * - `selectionToolbar` → selecting text reveals a floating\n * toolbar with Copy / Cut / wrap buttons; consumers can extend\n * with custom actions.\n *\n * Both are powered by the `useTextareaCommands` and\n * `useTextareaSelection` hooks, which are also exported standalone\n * for consumers who want to roll their own UI.\n */\n commands?: TextareaCommand[];\n /** Trigger character for the command palette. Default `\"/\"`. */\n commandTrigger?: string;\n /** Show a floating Copy / Cut toolbar over a non-empty selection.\n * Default `false`. */\n selectionToolbar?: boolean;\n /** Custom actions appended to the selection toolbar's built-in\n * Copy / Cut. Each action receives the live selected text and the\n * selection helpers from `useTextareaSelection`. */\n selectionActions?: TextareaSelectionAction[];\n /** Always-visible toolbar of tools that act on the textarea content.\n * Compose from the `textareaTools` factory (bold, italic, code,\n * heading, link, undo, …) and / or pass custom `TextareaTool`\n * objects. The toolbar uses `useTextareaTools` under the hood —\n * consumers can also call the hook directly to roll their own UI. */\n tools?: TextareaTool[];\n /** Where the tools toolbar sits relative to the field. Default\n * `\"top\"`. */\n toolbarPosition?: \"top\" | \"bottom\";\n}\n\n/* ---------------------------------------------------------------------------\n * Selection toolbar action\n * ------------------------------------------------------------------------- */\n\nexport interface TextareaSelectionAction {\n id: string;\n label: ReactNode;\n icon?: ReactNode;\n /** Called when the user clicks the action. Receives the live\n * selection text and the helpers from `useTextareaSelection`. */\n onAction: (\n selection: string,\n helpers: {\n replace: (s: string) => void;\n wrap: (open: string, close?: string) => void;\n copy: () => Promise<boolean>;\n cut: () => Promise<boolean>;\n },\n ) => void;\n}\n\n/* ---------------------------------------------------------------------------\n * Component\n * ------------------------------------------------------------------------- */\n\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(\n function Textarea(\n {\n label,\n error = false,\n errorMessage,\n helperText,\n resize = \"vertical\",\n autoResize = false,\n minRows,\n maxRows,\n maxHeight,\n maxWidth,\n minHeight,\n minWidth,\n maxLength,\n size = \"md\",\n rows = 3,\n disabled = false,\n className,\n style: consumerStyle,\n defaultValue,\n value,\n onChange,\n id: providedId,\n commands,\n commandTrigger = \"/\",\n selectionToolbar = false,\n selectionActions,\n tools,\n toolbarPosition = \"top\",\n ...props\n },\n forwardedRef,\n ) {\n const innerRef = useRef<HTMLTextAreaElement>(null);\n // Compose forwarded + internal ref.\n const setRef = (node: HTMLTextAreaElement | null) => {\n (innerRef as { current: HTMLTextAreaElement | null }).current = node;\n if (typeof forwardedRef === \"function\") forwardedRef(node);\n else if (forwardedRef)\n (forwardedRef as { current: HTMLTextAreaElement | null }).current = node;\n };\n\n const reactId = useId();\n const baseId = providedId ?? `ods-textarea-${reactId}`;\n const hintId =\n (error && errorMessage) || helperText ? `${baseId}-hint` : undefined;\n const [charCount, setCharCount] = useState(\n () => String(value ?? defaultValue ?? \"\").length,\n );\n\n const ariaNameProps = resolveAccessibleName({\n label: typeof label === \"string\" ? label : undefined,\n ariaLabel: props[\"aria-label\"],\n ariaLabelledby: (props as Record<string, unknown>)[\n \"aria-labelledby\"\n ] as string | undefined,\n componentName: \"Textarea\",\n });\n\n const { labelProps, inputProps } = useTextField(\n {\n label: typeof label === \"string\" ? label : undefined,\n ...ariaNameProps,\n isDisabled: disabled,\n errorMessage:\n typeof errorMessage === \"string\" ? errorMessage : undefined,\n validationState: error ? \"invalid\" : undefined,\n inputElementType: \"textarea\",\n value: value as string | undefined,\n defaultValue: defaultValue as string | undefined,\n },\n innerRef,\n );\n\n const describedBy =\n [\n (props as Record<string, unknown>)[\"aria-describedby\"] as\n | string\n | undefined,\n hintId,\n ]\n .filter(Boolean)\n .join(\" \") || undefined;\n\n const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setCharCount(e.target.value.length);\n onChange?.(e);\n };\n\n /* ── Inline command palette ───────────────────────────────────── */\n // The hooks need a `(value, onChange(string))` pair. Controlled\n // textareas already have a `value` prop; uncontrolled ones don't.\n // We mirror the current DOM value via `liveValue` so the hooks see\n // the same string regardless of which mode the consumer chose.\n const [liveValue, setLiveValue] = useState<string>(\n String(value ?? defaultValue ?? \"\"),\n );\n useEffect(() => {\n // Keep liveValue in sync with the controlled prop when present.\n if (value != null) setLiveValue(String(value));\n }, [value]);\n const handleChangeWithMirror = (\n e: React.ChangeEvent<HTMLTextAreaElement>,\n ) => {\n setLiveValue(e.target.value);\n handleChange(e);\n };\n const setLiveAndCommit = (next: string) => {\n setLiveValue(next);\n // Synthesize an event-like change so the consumer's `onChange`\n // receives the updated value via the same path.\n if (innerRef.current) innerRef.current.value = next;\n onChange?.({\n target: innerRef.current as HTMLTextAreaElement,\n currentTarget: innerRef.current as HTMLTextAreaElement,\n } as unknown as React.ChangeEvent<HTMLTextAreaElement>);\n setCharCount(next.length);\n };\n\n const cmdPalette = useTextareaCommands({\n textareaRef: innerRef,\n value: liveValue,\n onChange: setLiveAndCommit,\n commands: commands ?? [],\n trigger: commandTrigger,\n });\n const cmdEnabled = (commands?.length ?? 0) > 0;\n\n const sel = useTextareaSelection({\n textareaRef: innerRef,\n value: liveValue,\n onChange: setLiveAndCommit,\n });\n\n // Always-visible toolbar — driven by the `useTextareaTools` hook.\n // Stays empty when no `tools` array is provided so the toolbar\n // section never renders.\n const toolbar = useTextareaTools({\n textareaRef: innerRef,\n value: liveValue,\n onChange: setLiveAndCommit,\n tools: tools ?? [],\n });\n const toolbarEnabled = (tools?.length ?? 0) > 0;\n\n const handleKeyDownWithCommands = (\n e: React.KeyboardEvent<HTMLTextAreaElement>,\n ) => {\n if (cmdEnabled) {\n const consumed = cmdPalette.onKeyDown(e);\n if (consumed) return;\n }\n (props as { onKeyDown?: React.KeyboardEventHandler<HTMLTextAreaElement> })\n .onKeyDown?.(e);\n };\n\n // ── Auto-grow textarea (height) ───────────────────────────────────\n //\n // Mirrors the line-height-aware sizing we use in PromptInput. We\n // detect three line-height forms (`\"normal\"`, unitless like `\"1.5\"`,\n // or px like `\"24px\"`) so a unitless multiplier doesn't end up\n // being treated as 1.5 PIXELS — a real bug we hit in v1.\n //\n // Effective max comes from `maxHeight` (explicit px ceiling) OR the\n // computed line-height × `maxRows` cap, whichever is smaller. When\n // neither is set, the textarea grows freely (no cap).\n useEffect(() => {\n if (!autoResize) return;\n const el = innerRef.current;\n if (!el) return;\n const computed = window.getComputedStyle(el);\n const fontSize = parseFloat(computed.fontSize) || 16;\n const lhRaw = computed.lineHeight;\n const lh =\n lhRaw === \"normal\"\n ? fontSize * 1.2\n : lhRaw.endsWith(\"px\")\n ? parseFloat(lhRaw)\n : parseFloat(lhRaw) * fontSize;\n const padding =\n parseFloat(computed.paddingTop) + parseFloat(computed.paddingBottom);\n\n const rowCap =\n maxRows != null && Number.isFinite(maxRows)\n ? lh * maxRows + padding\n : Number.POSITIVE_INFINITY;\n const pixelCap =\n typeof maxHeight === \"number\"\n ? maxHeight\n : Number.POSITIVE_INFINITY;\n const effectiveMax = Math.min(rowCap, pixelCap);\n\n const rowFloor = lh * (minRows ?? rows) + padding;\n\n // Reset to natural height then clamp.\n el.style.height = \"auto\";\n const target = Math.max(\n rowFloor,\n Math.min(effectiveMax, el.scrollHeight),\n );\n el.style.height = `${target}px`;\n el.style.overflowY = el.scrollHeight > effectiveMax ? \"auto\" : \"hidden\";\n }, [autoResize, value, defaultValue, minRows, maxRows, maxHeight, rows]);\n\n const resolvedResize: \"vertical\" | \"horizontal\" | \"both\" | \"none\" =\n typeof resize === \"boolean\"\n ? resize\n ? \"vertical\"\n : \"none\"\n : resize;\n\n const toCss = (v: number | string | undefined): string | undefined =>\n v == null ? undefined : typeof v === \"number\" ? `${v}px` : v;\n\n // Apply the constraint CSS inline so it survives consumer overrides\n // and works regardless of class-bundling order. `resize` becomes a\n // CSS variable consumed by the field rule so the class can read it.\n const fieldStyle: CSSProperties = {\n maxHeight: toCss(maxHeight),\n maxWidth: toCss(maxWidth),\n minHeight: toCss(minHeight),\n minWidth: toCss(minWidth),\n resize: resolvedResize,\n };\n\n return (\n <div\n className={cn(\n \"ods-textarea\",\n `ods-textarea--${size}`,\n `ods-textarea--resize-${resolvedResize}`,\n autoResize && \"ods-textarea--auto-resize\",\n error && \"ods-textarea--error\",\n disabled && \"ods-textarea--disabled\",\n className,\n )}\n style={consumerStyle}\n >\n {label && (\n <label\n {...labelProps}\n htmlFor={baseId}\n className=\"ods-textarea__label\"\n >\n {label}\n </label>\n )}\n {toolbarEnabled && toolbarPosition === \"top\" && (\n <TextareaToolbar\n tools={toolbar.tools}\n onRun={toolbar.runTool}\n />\n )}\n <div className=\"ods-textarea__wrapper\">\n <textarea\n {...(props as ComponentPropsWithoutRef<\"textarea\">)}\n {...inputProps}\n ref={setRef}\n id={baseId}\n rows={autoResize ? (minRows ?? rows) : rows}\n disabled={disabled}\n maxLength={maxLength}\n defaultValue={defaultValue}\n value={value}\n onChange={handleChangeWithMirror}\n onKeyDown={handleKeyDownWithCommands}\n className=\"ods-textarea__field\"\n style={fieldStyle}\n aria-invalid={error || undefined}\n aria-describedby={describedBy}\n // When the command palette is open, expose it as the\n // companion combobox so AT users hear the active option.\n aria-autocomplete={cmdEnabled ? \"list\" : undefined}\n aria-expanded={cmdEnabled ? cmdPalette.isOpen : undefined}\n aria-controls={\n cmdEnabled && cmdPalette.isOpen\n ? `${baseId}-cmd-list`\n : undefined\n }\n aria-activedescendant={\n cmdEnabled && cmdPalette.isOpen && cmdPalette.items[\n cmdPalette.activeIndex\n ]\n ? `${baseId}-cmd-${cmdPalette.items[cmdPalette.activeIndex].id}`\n : undefined\n }\n />\n\n {/* ── Inline command palette ─────────────────────────── */}\n {cmdEnabled && cmdPalette.isOpen && cmdPalette.items.length > 0 &&\n typeof document !== \"undefined\" &&\n createPortal(\n <ul\n id={`${baseId}-cmd-list`}\n role=\"listbox\"\n aria-label=\"Inline commands\"\n className=\"ods-textarea__cmd-popover\"\n style={{\n position: \"fixed\",\n top: (cmdPalette.caretRect?.bottom ?? 0) + 6,\n left: cmdPalette.caretRect?.left ?? 0,\n }}\n >\n {cmdPalette.items.map((c, i) => (\n <li\n key={c.id}\n id={`${baseId}-cmd-${c.id}`}\n role=\"option\"\n aria-selected={i === cmdPalette.activeIndex}\n className={cn(\n \"ods-textarea__cmd-item\",\n i === cmdPalette.activeIndex &&\n \"ods-textarea__cmd-item--active\",\n )}\n onMouseDown={(e) => {\n // mousedown + preventDefault so the textarea\n // doesn't lose focus before commit fires.\n e.preventDefault();\n cmdPalette.commit(c);\n }}\n onMouseEnter={() => {\n // No public hover-state setter — close + reopen\n // pattern would be heavy. Skipping hover-to-\n // highlight for now; ArrowUp/Down nav covers it.\n }}\n >\n {c.icon && (\n <span className=\"ods-textarea__cmd-icon\">{c.icon}</span>\n )}\n <span className=\"ods-textarea__cmd-text\">\n <span className=\"ods-textarea__cmd-label\">\n {c.label}\n </span>\n {c.description && (\n <span className=\"ods-textarea__cmd-desc\">\n {c.description}\n </span>\n )}\n </span>\n </li>\n ))}\n </ul>,\n document.body,\n )}\n\n {/* ── Selection toolbar ──────────────────────────────── */}\n {selectionToolbar && sel.active && sel.rect &&\n typeof document !== \"undefined\" &&\n createPortal(\n <div\n role=\"toolbar\"\n aria-label=\"Selection actions\"\n className=\"ods-textarea__sel-toolbar\"\n style={{\n position: \"fixed\",\n top: sel.rect.top - 36,\n left: sel.rect.left,\n }}\n // mousedown + preventDefault keeps the textarea\n // selection alive while the user clicks a button.\n onMouseDown={(e) => e.preventDefault()}\n >\n <button\n type=\"button\"\n className=\"ods-textarea__sel-btn\"\n onClick={() => sel.copy()}\n aria-label=\"Copy selection\"\n title=\"Copy\"\n >\n <CopyIcon size=\"xs\" />\n </button>\n <button\n type=\"button\"\n className=\"ods-textarea__sel-btn\"\n onClick={() => sel.cut()}\n aria-label=\"Cut selection\"\n title=\"Cut\"\n >\n <CutIcon size=\"xs\" />\n </button>\n {selectionActions?.map((a) => (\n <button\n key={a.id}\n type=\"button\"\n className=\"ods-textarea__sel-btn\"\n onClick={() =>\n a.onAction(sel.text, {\n replace: sel.replace,\n wrap: sel.wrap,\n copy: sel.copy,\n cut: sel.cut,\n })\n }\n title={typeof a.label === \"string\" ? a.label : undefined}\n >\n {a.icon}\n {a.label && (\n <span className=\"ods-textarea__sel-btn-label\">\n {a.label}\n </span>\n )}\n </button>\n ))}\n </div>,\n document.body,\n )}\n {maxLength != null && (\n <span\n className=\"ods-textarea__count\"\n aria-live={charCount > maxLength ? \"polite\" : \"off\"}\n >\n {charCount}/{maxLength}\n </span>\n )}\n </div>\n {toolbarEnabled && toolbarPosition === \"bottom\" && (\n <TextareaToolbar\n tools={toolbar.tools}\n onRun={toolbar.runTool}\n />\n )}\n {error && errorMessage ? (\n <div\n id={hintId}\n className=\"ods-textarea__error-message\"\n role=\"alert\"\n >\n {errorMessage}\n </div>\n ) : helperText ? (\n <div id={hintId} className=\"ods-textarea__hint\">\n {helperText}\n </div>\n ) : null}\n </div>\n );\n },\n);\n\nTextarea.displayName = \"Textarea\";\n\n/* ---------------------------------------------------------------------------\n * Internal — toolbar renderer\n *\n * Stays internal because consumers who want a custom UI should call\n * `useTextareaTools` directly. The toolbar's only job here is to map\n * the resolved tools array to clickable buttons / dividers using the\n * same chrome as the rest of the textarea section.\n * ------------------------------------------------------------------------- */\nfunction TextareaToolbar({\n tools,\n onRun,\n}: {\n tools: TextareaTool[];\n onRun: (id: string) => void | Promise<void>;\n}) {\n return (\n <div\n role=\"toolbar\"\n aria-label=\"Formatting\"\n className=\"ods-textarea__toolbar\"\n // mousedown + preventDefault keeps the textarea's selection /\n // caret alive while a button is clicked.\n onMouseDown={(e) => {\n if (\n (e.target as HTMLElement).closest(\".ods-textarea__toolbar-btn\")\n ) {\n e.preventDefault();\n }\n }}\n >\n {tools.map((t) => {\n if (t.kind === \"divider\") {\n return (\n <span\n key={t.id}\n className=\"ods-textarea__toolbar-divider\"\n aria-hidden=\"true\"\n />\n );\n }\n return (\n <button\n key={t.id}\n type=\"button\"\n className=\"ods-textarea__toolbar-btn\"\n title={t.title ?? (typeof t.label === \"string\" ? t.label : undefined)}\n aria-label={typeof t.label === \"string\" ? t.label : t.id}\n onClick={() => onRun(t.id)}\n >\n {t.icon ? (\n <span className=\"ods-textarea__toolbar-icon\">{t.icon}</span>\n ) : (\n <span className=\"ods-textarea__toolbar-text\">{t.label}</span>\n )}\n </button>\n );\n })}\n </div>\n );\n}\n","\"use client\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type ReactNode,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/* ---------------------------------------------------------------------------\n * CountUp — animated numeric counter.\n *\n * For ETL / orchestration dashboards: rows processed, runs completed,\n * MRR, throughput totals. Pairs naturally with `Sparkline` and `Stat`.\n *\n * The animation is implementation-light — a `requestAnimationFrame` loop\n * with a configurable easing function. Skips entirely when the user has\n * `prefers-reduced-motion` enabled or `disableAnimation` is true.\n *\n * Re-runs the tween whenever `value` changes, starting from the previous\n * displayed value (so consecutive updates flow smoothly without a reset\n * to 0).\n * ------------------------------------------------------------------------- */\n\nexport type Easing = (t: number) => number;\n\nexport interface CountUpProps\n extends Omit<\n ComponentPropsWithoutRef<\"span\">,\n // HTMLSpanElement carries a native `prefix` attribute (string) — omit\n // it so our `ReactNode` prefix slot can coexist.\n \"children\" | \"onChange\" | \"prefix\"\n > {\n /** Target value. */\n value: number;\n /** Starting value on FIRST mount. Default 0. */\n from?: number;\n /** Tween duration in ms. Default 800. */\n duration?: number;\n /** Easing function. Default `easeOutCubic`. */\n easing?: Easing;\n /** Decimal places when no `formatValue` is supplied. Default 0. */\n decimals?: number;\n /** Custom formatter — wins over `decimals`. */\n formatValue?: (value: number) => ReactNode;\n /** Inline content before the number. */\n prefix?: ReactNode;\n /** Inline content after the number (e.g. \"%\"). */\n suffix?: ReactNode;\n /** Delay the tween start in ms. */\n delay?: number;\n /**\n * Skip the animation and render `value` immediately. Reads as a\n * \"static mode\" — useful for SSR snapshots or print views.\n */\n disableAnimation?: boolean;\n /** Fires once when the tween settles on the target value. */\n onComplete?: () => void;\n}\n\n/* ---------------------------------------------------------------------------\n * Easings\n * ------------------------------------------------------------------------- */\n\nexport const easeLinear: Easing = (t) => t;\nexport const easeOutCubic: Easing = (t) => 1 - Math.pow(1 - t, 3);\nexport const easeOutQuart: Easing = (t) => 1 - Math.pow(1 - t, 4);\nexport const easeOutExpo: Easing = (t) =>\n t === 1 ? 1 : 1 - Math.pow(2, -10 * t);\n\n/* ---------------------------------------------------------------------------\n * Component\n * ------------------------------------------------------------------------- */\n\nexport const CountUp = forwardRef<HTMLSpanElement, CountUpProps>(\n function CountUp(\n {\n value,\n from = 0,\n duration = 800,\n easing = easeOutCubic,\n decimals = 0,\n formatValue,\n prefix,\n suffix,\n delay = 0,\n disableAnimation = false,\n onComplete,\n className,\n ...rest\n },\n ref,\n ) {\n // The current rendered number. Initialise to `from` on first mount;\n // subsequent renders tween from the previous displayed value.\n const [n, setN] = useState<number>(disableAnimation ? value : from);\n const lastRendered = useRef<number>(disableAnimation ? value : from);\n\n useEffect(() => {\n // Respect prefers-reduced-motion — snap to target without animation.\n const reduced =\n typeof window !== \"undefined\" &&\n window.matchMedia?.(\"(prefers-reduced-motion: reduce)\")\n .matches;\n\n if (disableAnimation || reduced) {\n setN(value);\n lastRendered.current = value;\n onComplete?.();\n return;\n }\n\n const startValue = lastRendered.current;\n const delta = value - startValue;\n if (delta === 0) return;\n\n let raf: number | null = null;\n let timeoutId: number | null = null;\n let startTime: number | null = null;\n let cancelled = false;\n\n const tick = (ts: number) => {\n if (cancelled) return;\n if (startTime === null) startTime = ts;\n const t = Math.min(1, (ts - startTime) / Math.max(1, duration));\n const eased = easing(t);\n const current = startValue + delta * eased;\n setN(current);\n lastRendered.current = current;\n if (t < 1) {\n raf = requestAnimationFrame(tick);\n } else {\n lastRendered.current = value;\n setN(value);\n onComplete?.();\n }\n };\n\n const start = () => {\n raf = requestAnimationFrame(tick);\n };\n\n if (delay > 0) {\n timeoutId = window.setTimeout(start, delay);\n } else {\n start();\n }\n\n return () => {\n cancelled = true;\n if (raf !== null) cancelAnimationFrame(raf);\n if (timeoutId !== null) window.clearTimeout(timeoutId);\n };\n // We intentionally exclude `easing` from deps — it should be a\n // stable function reference. If the consumer changes easing\n // mid-flight, we just pick it up on the next value change.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [value, duration, delay, disableAnimation]);\n\n const display = formatValue ? formatValue(n) : n.toFixed(decimals);\n\n return (\n <span\n {...rest}\n ref={ref}\n className={cn(\"ods-count-up\", className)}\n // aria-live so screen readers announce updates without a stale\n // value lingering. Polite (default for \"status\") avoids\n // interrupting other announcements.\n aria-live=\"polite\"\n aria-atomic=\"true\"\n >\n {prefix}\n {display}\n {suffix}\n </span>\n );\n },\n);\n\nCountUp.displayName = \"CountUp\";\n","\"use client\";\nimport {\n QuotesIcon,\n StarFilledIcon,\n StarIcon,\n} from \"@octaviaflow/icons\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type ReactNode,\n useId,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Avatar, type AvatarProps } from \"../Avatar\";\nimport { Card, type CardRadius } from \"../Card\";\n\n/* ---------------------------------------------------------------------------\n * TestimonialCard — pull-quote card with author + optional rating.\n *\n * Composes on the polished `Card` primitive (forwardRef, native props,\n * focus rings, radius). Uses the polished `Avatar` primitive for the\n * author photo and `@octaviaflow/icons` for the quote glyph + star\n * rating.\n * ------------------------------------------------------------------------- */\n\nexport type TestimonialCardSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface TestimonialCardAuthor {\n /** Display name. */\n name: ReactNode;\n /** Avatar — forwarded to the polished Avatar primitive. */\n avatar?: Pick<AvatarProps, \"src\" | \"initials\" | \"alt\">;\n /** Job title / role / handle. */\n role?: ReactNode;\n}\n\nexport interface TestimonialCardProps\n extends Omit<\n ComponentPropsWithoutRef<\"figure\">,\n // Native `role` is an AriaRole string; our legacy `role` prop is a\n // ReactNode (author's job title). Omit so they don't collide.\n \"role\" | \"onDrag\" | \"onDragStart\" | \"onDragEnd\" | \"onAnimationStart\"\n > {\n /** The testimonial body. */\n quote: ReactNode;\n /**\n * Author — accepts either a plain ReactNode (legacy: name only) or a\n * structured `{ name, role?, avatar? }` object (preferred).\n */\n author: ReactNode | TestimonialCardAuthor;\n /** Legacy: author role rendered below the name. Use `author.role` instead. */\n role?: ReactNode;\n /** Legacy: raw avatar slot (e.g. <img />). Use `author.avatar` instead. */\n avatar?: ReactNode;\n /** Legacy: initial character to render in the avatar circle. */\n initial?: ReactNode;\n /** 0–5 star rating. */\n rating?: number;\n /** Optional company logo node — rendered top-right (e.g. customer logo). */\n logo?: ReactNode;\n /** Size variant — drives quote-text size + padding. */\n size?: TestimonialCardSize;\n /** Card corner radius (passes through). */\n radius?: CardRadius;\n}\n\nfunction isAuthorObject(\n v: TestimonialCardProps[\"author\"],\n): v is TestimonialCardAuthor {\n return (\n typeof v === \"object\" &&\n v !== null &&\n !(\"type\" in (v as object)) && // exclude React elements\n \"name\" in (v as unknown as Record<string, unknown>)\n );\n}\n\nexport const TestimonialCard = forwardRef<\n HTMLElement,\n TestimonialCardProps\n>(function TestimonialCard(\n {\n quote,\n author,\n role: legacyRole,\n avatar: legacyAvatar,\n initial: legacyInitial,\n rating,\n logo,\n size = \"md\",\n radius = \"md\",\n id: providedId,\n className,\n ...rest\n },\n ref,\n) {\n const reactId = useId();\n const baseId = providedId ?? `ods-testimonial-${reactId}`;\n const quoteId = `${baseId}-quote`;\n const authorId = `${baseId}-author`;\n\n // Resolve the author shape — structured wins, legacy props fill in.\n const resolved: TestimonialCardAuthor = isAuthorObject(author)\n ? author\n : {\n name: author,\n role: legacyRole,\n avatar: legacyAvatar\n ? undefined // legacy raw-node path handled below\n : {\n initials:\n typeof legacyInitial === \"string\"\n ? legacyInitial\n : typeof author === \"string\"\n ? author.charAt(0).toUpperCase()\n : undefined,\n },\n };\n\n const renderAvatar = () => {\n // Legacy raw `avatar` node (e.g. <img />) — preserve back-compat.\n if (!isAuthorObject(author) && legacyAvatar) {\n return (\n <span\n className=\"ods-testimonial__avatar ods-testimonial__avatar--legacy\"\n aria-hidden=\"true\"\n >\n {legacyAvatar}\n </span>\n );\n }\n return (\n <Avatar\n size={size === \"sm\" ? \"xs\" : size === \"lg\" ? \"md\" : \"sm\"}\n src={resolved.avatar?.src}\n initials={resolved.avatar?.initials}\n alt={\n resolved.avatar?.alt ??\n (typeof resolved.name === \"string\" ? resolved.name : undefined)\n }\n className=\"ods-testimonial__avatar\"\n />\n );\n };\n\n return (\n <Card\n // Card forwards refs to a div; figure is a different element so we\n // render the figure semantics in our children and let Card own\n // the focusable surface as a generic block. The forwardRef on\n // TestimonialCard's outer type is `HTMLElement` so consumers\n // can still attach a ref without TS friction.\n {...(rest as unknown as ComponentPropsWithoutRef<\"div\">)}\n ref={ref as unknown as React.Ref<HTMLDivElement>}\n id={baseId}\n radius={radius}\n padding=\"none\"\n variant=\"subtle\"\n className={cn(\n \"ods-testimonial\",\n `ods-testimonial--${size}`,\n className,\n )}\n aria-labelledby={authorId}\n aria-describedby={quoteId}\n >\n <div className=\"ods-testimonial__head\">\n <span className=\"ods-testimonial__quote\" aria-hidden=\"true\">\n <QuotesIcon size=\"md\" />\n </span>\n {logo && (\n <span className=\"ods-testimonial__logo\" aria-hidden=\"true\">\n {logo}\n </span>\n )}\n </div>\n\n <blockquote id={quoteId} className=\"ods-testimonial__text\">\n {quote}\n </blockquote>\n\n {typeof rating === \"number\" && (\n <div\n className=\"ods-testimonial__rating\"\n role=\"img\"\n aria-label={`${rating} out of 5 stars`}\n >\n {Array.from({ length: 5 }).map((_, i) =>\n i < Math.round(rating) ? (\n <StarFilledIcon\n key={i}\n size=\"xs\"\n className=\"ods-testimonial__star ods-testimonial__star--on\"\n />\n ) : (\n <StarIcon\n key={i}\n size=\"xs\"\n className=\"ods-testimonial__star\"\n />\n ),\n )}\n </div>\n )}\n\n <figcaption className=\"ods-testimonial__author\" id={authorId}>\n {renderAvatar()}\n <span className=\"ods-testimonial__author-info\">\n <span className=\"ods-testimonial__author-name\">\n {resolved.name}\n </span>\n {resolved.role && (\n <span className=\"ods-testimonial__author-role\">\n {resolved.role}\n </span>\n )}\n </span>\n </figcaption>\n </Card>\n );\n});\n\nTestimonialCard.displayName = \"TestimonialCard\";\n"],"mappings":"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","names":["Card","CardHeader","CardBody","CardFooter","CardTitle","CardDescription","forwardRef","jsx","forwardRef","Avatar","AvatarStack","forwardRef","jsx","jsxs","forwardRef","BlogCard","useCallback","useMemo","useState","useCallback","useEffect","useState","useCallback","useMemo","useRef","jsx","forwardRef","useEffect","useId","useRef","useState","jsx","jsxs","forwardRef","Textarea","useRef","useId","useState","useEffect","forwardRef","useEffect","useRef","useState","jsxs","forwardRef","CountUp","useState","useRef","useEffect","QuotesIcon","forwardRef","useId","jsx","jsxs","forwardRef","TestimonialCard","useId","QuotesIcon"]}
@@ -0,0 +1,118 @@
1
+ import { type ComponentPropsWithoutRef, type FormEvent, type ReactNode } from "react";
2
+ import { type PasswordInputProps } from "../PasswordInput";
3
+ import { type SocialProvider } from "../SocialButton";
4
+ export interface AuthScreenProps extends ComponentPropsWithoutRef<"div"> {
5
+ /**
6
+ * Decorative pane content. Defaults to `<AuthArtPanel />`; pass `null`
7
+ * to render a single centered form column with no art pane.
8
+ */
9
+ art?: ReactNode;
10
+ /** Which side the art pane sits on. Default `"right"`. */
11
+ artSide?: "left" | "right";
12
+ /**
13
+ * `"card"` (default) floats the split as a framed card on a subtle
14
+ * canvas — the reference look. `"full"` stretches the split edge-to-edge
15
+ * for a full-bleed page.
16
+ */
17
+ frame?: "card" | "full";
18
+ /** The form pane — typically `AuthLoginForm` or `AuthSignupForm`. */
19
+ children: ReactNode;
20
+ }
21
+ export declare function AuthScreen({ art, artSide, frame, children, className, ...rest }: AuthScreenProps): import("react/jsx-runtime").JSX.Element;
22
+ export type AuthArtPanelProps = ComponentPropsWithoutRef<"div">;
23
+ export declare function AuthArtPanel({ className, ...rest }: AuthArtPanelProps): import("react/jsx-runtime").JSX.Element;
24
+ export interface AuthLoginValues {
25
+ email: string;
26
+ password: string;
27
+ remember: boolean;
28
+ }
29
+ type FormPropsBase = Omit<ComponentPropsWithoutRef<"form">, "onSubmit" | "title">;
30
+ export interface AuthLoginFormProps extends FormPropsBase {
31
+ logo?: ReactNode;
32
+ /** Default `"Welcome back!"`. */
33
+ title?: ReactNode;
34
+ /** Default `"Sign in to continue to your OctaviaFlow workspace."`. */
35
+ description?: ReactNode;
36
+ /** `"h1"` for a standalone page (default), `"h2"` when embedded. */
37
+ headingLevel?: "h1" | "h2";
38
+ /** Inline error banner above the fields. Pass falsy to hide. */
39
+ error?: ReactNode;
40
+ /** Inline success banner above the fields. */
41
+ success?: ReactNode;
42
+ /** Disables the fields and puts the submit button in its loading state. */
43
+ loading?: boolean;
44
+ emailLabel?: ReactNode;
45
+ emailPlaceholder?: string;
46
+ defaultEmail?: string;
47
+ passwordLabel?: ReactNode;
48
+ passwordPlaceholder?: string;
49
+ submitLabel?: ReactNode;
50
+ /** Render the "Remember me" checkbox. Default `true`. */
51
+ showRemember?: boolean;
52
+ rememberLabel?: ReactNode;
53
+ defaultRemember?: boolean;
54
+ /** Forgot-password affordance — link when `href`, button when only `onClick`. */
55
+ forgotHref?: string;
56
+ onForgotClick?: () => void;
57
+ forgotLabel?: ReactNode;
58
+ /** Social sign-in row under the divider. Default `["google"]`. */
59
+ socialProviders?: SocialProvider[];
60
+ onSocialClick?: (provider: SocialProvider) => void;
61
+ socialDividerLabel?: ReactNode;
62
+ /** Register affordance in the footer. */
63
+ registerHref?: string;
64
+ onRegisterClick?: () => void;
65
+ registerPrompt?: ReactNode;
66
+ registerLabel?: ReactNode;
67
+ /** Fully custom footer — replaces the built-in register line. */
68
+ footer?: ReactNode;
69
+ /**
70
+ * Called with the collected values on submit. The native event is always
71
+ * `preventDefault()`ed — wire your own request in this callback.
72
+ */
73
+ onSubmit?: (values: AuthLoginValues, event: FormEvent<HTMLFormElement>) => void;
74
+ }
75
+ export declare function AuthLoginForm({ logo, title, description, headingLevel, error, success, loading, emailLabel, emailPlaceholder, defaultEmail, passwordLabel, passwordPlaceholder, submitLabel, showRemember, rememberLabel, defaultRemember, forgotHref, onForgotClick, forgotLabel, socialProviders, onSocialClick, socialDividerLabel, registerHref, onRegisterClick, registerPrompt, registerLabel, footer, onSubmit, className, ...rest }: AuthLoginFormProps): import("react/jsx-runtime").JSX.Element;
76
+ export interface AuthSignupValues {
77
+ name: string;
78
+ email: string;
79
+ password: string;
80
+ acceptTerms: boolean;
81
+ }
82
+ export interface AuthSignupFormProps extends FormPropsBase {
83
+ logo?: ReactNode;
84
+ /** Default `"Create your account"`. */
85
+ title?: ReactNode;
86
+ /** Default `"Start automating with OctaviaFlow in minutes."`. */
87
+ description?: ReactNode;
88
+ headingLevel?: "h1" | "h2";
89
+ error?: ReactNode;
90
+ success?: ReactNode;
91
+ loading?: boolean;
92
+ nameLabel?: ReactNode;
93
+ namePlaceholder?: string;
94
+ emailLabel?: ReactNode;
95
+ emailPlaceholder?: string;
96
+ passwordLabel?: ReactNode;
97
+ passwordPlaceholder?: string;
98
+ /** Forwarded to `PasswordInput` to render the strength meter. */
99
+ passwordStrengthRules?: PasswordInputProps["strengthRules"];
100
+ submitLabel?: ReactNode;
101
+ /** Render the terms checkbox. Default `true` (checkbox is `required`). */
102
+ showTerms?: boolean;
103
+ /** Terms copy — pass a node with your own links. */
104
+ termsLabel?: ReactNode;
105
+ socialProviders?: SocialProvider[];
106
+ onSocialClick?: (provider: SocialProvider) => void;
107
+ socialDividerLabel?: ReactNode;
108
+ /** Sign-in affordance in the footer. */
109
+ signInHref?: string;
110
+ onSignInClick?: () => void;
111
+ signInPrompt?: ReactNode;
112
+ signInLabel?: ReactNode;
113
+ footer?: ReactNode;
114
+ onSubmit?: (values: AuthSignupValues, event: FormEvent<HTMLFormElement>) => void;
115
+ }
116
+ export declare function AuthSignupForm({ logo, title, description, headingLevel, error, success, loading, nameLabel, namePlaceholder, emailLabel, emailPlaceholder, passwordLabel, passwordPlaceholder, passwordStrengthRules, submitLabel, showTerms, termsLabel, socialProviders, onSocialClick, socialDividerLabel, signInHref, onSignInClick, signInPrompt, signInLabel, footer, onSubmit, className, ...rest }: AuthSignupFormProps): import("react/jsx-runtime").JSX.Element;
117
+ export {};
118
+ //# sourceMappingURL=AuthScreen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthScreen.d.ts","sourceRoot":"","sources":["../../../src/components/AuthScreen/AuthScreen.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { AuthArtPanel, type AuthArtPanelProps, AuthLoginForm, type AuthLoginFormProps, type AuthLoginValues, AuthScreen, type AuthScreenProps, AuthSignupForm, type AuthSignupFormProps, type AuthSignupValues, } from "./AuthScreen";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/AuthScreen/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,KAAK,iBAAiB,EACtB,aAAa,EACb,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,UAAU,EACV,KAAK,eAAe,EACpB,cAAc,EACd,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAC"}
@@ -60,6 +60,14 @@ export interface DataMapperProps extends Omit<ComponentPropsWithoutRef<"div">, "
60
60
  onClose?: () => void;
61
61
  /** Sidebar starts open. */
62
62
  defaultSidebarOpen?: boolean;
63
+ /**
64
+ * Target-field groups (object/array rows) start expanded so their mapped
65
+ * sub-fields are visible without a click. Defaults to `true`. Set `false`
66
+ * for the legacy all-collapsed behavior. New groups appearing after mount
67
+ * (e.g. an async target schema) are auto-expanded too, without overriding a
68
+ * group the user has manually collapsed.
69
+ */
70
+ defaultGroupsExpanded?: boolean;
63
71
  className?: string;
64
72
  }
65
73
  export declare const DataMapper: import("react").ForwardRefExoticComponent<DataMapperProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -1 +1 @@
1
- {"version":3,"file":"DataMapper.d.ts","sourceRoot":"","sources":["../../../src/components/DataMapper/DataMapper.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,wBAAwB,EAE7B,KAAK,SAAS,EAOf,MAAM,OAAO,CAAC;AAOf,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,GAAG,EAAE,MAAM,CAAC;IACZ,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,2FAA2F;IAC3F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;IAC7B,4EAA4E;IAC5E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;AAE3E,MAAM,WAAW,eACf,SAAQ,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IACnE,oBAAoB;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,mEAAmE;IACnE,YAAY,EAAE,eAAe,EAAE,CAAC;IAChC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;IACjC,yEAAyE;IACzE,SAAS,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACjC,sCAAsC;IACtC,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,2DAA2D;IAC3D,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,QAAQ,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,IAAI,CAAC;IAC5C,qDAAqD;IACrD,cAAc,CAAC,EAAE,iBAAiB,CAAC;IACnC,8BAA8B;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iCAAiC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,2BAA2B;IAC3B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAmaD,eAAO,MAAM,UAAU,4GAi4BtB,CAAC"}
1
+ {"version":3,"file":"DataMapper.d.ts","sourceRoot":"","sources":["../../../src/components/DataMapper/DataMapper.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,wBAAwB,EAE7B,KAAK,SAAS,EAOf,MAAM,OAAO,CAAC;AAOf,MAAM,WAAW,eAAe;IAC9B,mFAAmF;IACnF,GAAG,EAAE,MAAM,CAAC;IACZ,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,2FAA2F;IAC3F,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;IAC7B,4EAA4E;IAC5E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;AAE3E,MAAM,WAAW,eACf,SAAQ,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IACnE,oBAAoB;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,mEAAmE;IACnE,YAAY,EAAE,eAAe,EAAE,CAAC;IAChC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;IACjC,yEAAyE;IACzE,SAAS,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACjC,sCAAsC;IACtC,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,2DAA2D;IAC3D,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,QAAQ,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,IAAI,CAAC;IAC5C,qDAAqD;IACrD,cAAc,CAAC,EAAE,iBAAiB,CAAC;IACnC,8BAA8B;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iCAAiC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,2BAA2B;IAC3B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAqbD,eAAO,MAAM,UAAU,4GAigCtB,CAAC"}
@@ -0,0 +1,45 @@
1
+ import type { ComponentPropsWithoutRef, ReactNode } from "react";
2
+ export type FlowDoctorSeverity = "error" | "warning";
3
+ export interface FlowDoctorIssue {
4
+ /** Stable identity (rule + anchor). */
5
+ id: string;
6
+ severity: FlowDoctorSeverity;
7
+ /** Human-readable problem statement. */
8
+ message: string;
9
+ /** Rule slug that produced the issue (e.g. `"trigger-required"`). */
10
+ rule?: string;
11
+ /** Optional remediation hint ("Connect a trigger before activating"). */
12
+ hint?: string;
13
+ /** Anchors for click-to-focus. */
14
+ nodeId?: string;
15
+ edgeId?: string;
16
+ /** Secondary label — usually the offending node's title. */
17
+ source?: string;
18
+ }
19
+ export interface FlowDoctorCheck {
20
+ id: string;
21
+ label: string;
22
+ description?: string;
23
+ }
24
+ export type FlowDoctorTone = "clean" | "warning" | "error";
25
+ export interface FlowDoctorProps extends Omit<ComponentPropsWithoutRef<"section">, "title"> {
26
+ issues: FlowDoctorIssue[];
27
+ /** Rules that ran and passed — shown in a collapsed "Passed" disclosure. */
28
+ checks?: FlowDoctorCheck[];
29
+ /** Panel heading. Default `"Flow Doctor"`. */
30
+ title?: ReactNode;
31
+ /** Click a row → host selects/pans to the offending node or edge. */
32
+ onIssueClick?: (issue: FlowDoctorIssue) => void;
33
+ /** Compact spacing for overlay embedding (e.g. the toolbar hover card). */
34
+ dense?: boolean;
35
+ /** Cap listed issues; a "+N more" footer covers the remainder. */
36
+ maxVisible?: number;
37
+ /** Right-aligned header slot (e.g. a "Re-run checks" action). */
38
+ headerExtra?: ReactNode;
39
+ }
40
+ /** Derive the overall verdict tone from an issue list. */
41
+ export declare function flowDoctorTone(issues: FlowDoctorIssue[]): FlowDoctorTone;
42
+ /** One-line verdict, shared with the toolbar badge's aria-label. */
43
+ export declare function flowDoctorSummary(issues: FlowDoctorIssue[]): string;
44
+ export declare function FlowDoctor({ issues, checks, title, onIssueClick, dense, maxVisible, headerExtra, className, ...rest }: FlowDoctorProps): import("react/jsx-runtime").JSX.Element;
45
+ //# sourceMappingURL=FlowDoctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FlowDoctor.d.ts","sourceRoot":"","sources":["../../../src/components/FlowDoctor/FlowDoctor.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAgBjE,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,wBAAwB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IACzF,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,4EAA4E;IAC5E,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B,8CAA8C;IAC9C,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,qEAAqE;IACrE,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAChD,2EAA2E;IAC3E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB;AAED,0DAA0D;AAC1D,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,cAAc,CAIxE;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,CAUnE;AA0GD,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,MAAM,EACN,KAAqB,EACrB,YAAY,EACZ,KAAa,EACb,UAAU,EACV,WAAW,EACX,SAAS,EACT,GAAG,IAAI,EACR,EAAE,eAAe,2CA2EjB"}
@@ -0,0 +1,2 @@
1
+ export { FlowDoctor, type FlowDoctorCheck, type FlowDoctorIssue, type FlowDoctorProps, type FlowDoctorSeverity, type FlowDoctorTone, flowDoctorSummary, flowDoctorTone, } from "./FlowDoctor";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FlowDoctor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,iBAAiB,EACjB,cAAc,GACf,MAAM,cAAc,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { type ReactNode } from "react";
2
+ import { type FlowDoctorCheck, type FlowDoctorIssue } from "../FlowDoctor";
2
3
  import { type HoverCardPlacement } from "../HoverCard";
3
4
  export interface FlowToolbarProps {
4
5
  children?: ReactNode;
@@ -149,19 +150,12 @@ export interface FlowToolbarResetProps {
149
150
  }
150
151
  export declare function FlowToolbarReset({ onReset, disabled, shortcut, className, }: FlowToolbarResetProps): import("react/jsx-runtime").JSX.Element;
151
152
  export declare function FlowToolbarZoom({ zoom: zoomProp, onZoomIn, onZoomOut, onFit, onReset, className, }: FlowToolbarZoomProps): import("react/jsx-runtime").JSX.Element;
152
- export interface FlowToolbarIssueItem {
153
- /** Stable identity (rule + anchor). */
154
- id: string;
155
- severity: "error" | "warning";
156
- message: string;
157
- /** Anchors for click-to-focus. */
158
- nodeId?: string;
159
- edgeId?: string;
160
- /** Optional secondary line (e.g. the node's label). */
161
- source?: string;
162
- }
153
+ /** @deprecated Use `FlowDoctorIssue` — same shape, richer optional fields. */
154
+ export type FlowToolbarIssueItem = FlowDoctorIssue;
163
155
  export interface FlowToolbarIssuesProps {
164
156
  issues: FlowToolbarIssueItem[];
157
+ /** Rules that passed — shown in the panel's collapsed "Passed" section. */
158
+ checks?: FlowDoctorCheck[];
165
159
  /** Click a row → host selects/pans to the offending node. */
166
160
  onIssueClick?: (issue: FlowToolbarIssueItem) => void;
167
161
  /** Overlay side relative to the button. Default `right` (left toolbar). */
@@ -174,5 +168,5 @@ export interface FlowToolbarIssuesProps {
174
168
  closeDelay?: number;
175
169
  className?: string;
176
170
  }
177
- export declare function FlowToolbarIssues({ issues, onIssueClick, placement, maxVisible, label, openDelay, closeDelay, className, }: FlowToolbarIssuesProps): import("react/jsx-runtime").JSX.Element;
171
+ export declare function FlowToolbarIssues({ issues, checks, onIssueClick, placement, maxVisible, label, openDelay, closeDelay, className, }: FlowToolbarIssuesProps): import("react/jsx-runtime").JSX.Element;
178
172
  //# sourceMappingURL=FlowToolbar.d.ts.map