@bizapps/design-system-testing 1.12.1 → 1.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/editor.cjs +1 -1
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.js +1 -1
- package/dist/editor.js.map +1 -1
- package/dist/main.cjs +32 -12
- package/dist/main.cjs.map +1 -1
- package/dist/main.js +32 -12
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
package/dist/editor.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/utils.ts","../src/components/ui/Label/label.tsx","../src/components/ui/Button/button.tsx","../src/components/compounds/RichTextEditor/rich-text-toolbar.tsx","../src/components/compounds/RichTextEditor/rich-text-editor.tsx","../src/components/ui/DropdownMenu/dropdown-menu.tsx","../src/components/compounds/RichTextEditor/table-menu.tsx","../src/tokens/animation.ts","../src/components/ui/Dialog/dialog.tsx","../src/components/ui/Dropzone/dropzone.tsx","../src/components/ui/Input/input.tsx","../src/components/compounds/RichTextEditor/insert-image-dialog.tsx","../src/components/compounds/RichTextEditor/resizable-image.tsx","../src/components/compounds/RichTextEditor/link-bubble-menu.tsx","../src/components/compounds/RichTextEditor/list-menu.tsx","../src/components/compounds/RichTextEditor/use-rich-text-editor.tsx","../src/components/compounds/RichTextEditor/color-menu.tsx","../src/components/compounds/RichTextEditor/insert-link-dialog.tsx"],"names":["twMerge","clsx","jsx","LabelPrimitive","cva","Slot","jsxs","LoaderCircle","useId","EditorContent","DropdownMenuPrimitive","useState","createContext","DialogPrimitive","useContext","AnimatePresence","motion","XIcon","useDropzone","UploadIcon","Trash2","useRef","useCallback","useEffect","NodeViewWrapper","Image","ReactNodeViewRenderer","useEditorState","ExternalLink","Pencil","Unlink","useMemo","BubbleMenu","ChevronDown","Check","useEditor","StarterKit","Highlight","TableKit","Bold","Italic","Heading2","Highlighter","Underline","Strikethrough","Quote","List","ListOrdered","LinkIcon","ImagePlus","TableIcon","Ban"],"mappings":"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","file":"editor.cjs","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { type ComponentProps } from 'react';\nimport { Label as LabelPrimitive } from 'radix-ui';\n\nimport { cn } from '@/lib/utils';\n\nfunction Label({ className, ...props }: ComponentProps<typeof LabelPrimitive.Root>) {\n return (\n <LabelPrimitive.Root\n data-slot='label'\n className={cn(\n 'text-foreground text-sm leading-6 font-medium transition-colors select-none',\n 'group-has-disabled/field:cursor-not-allowed group-has-disabled/field:opacity-50',\n 'peer-disabled:cursor-not-allowed peer-disabled:opacity-50',\n 'aria-invalid:text-destructive dark:aria-invalid:text-destructive/90',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport { Label };\n","import { type ComponentProps, type MouseEvent } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { Slot } from 'radix-ui';\nimport {LoaderCircle} from 'lucide-react'\n\nimport { cn } from '@/lib/utils';\n\nconst buttonVariants = cva(\n 'group/button inline-flex shrink-0 items-center justify-center gap-2 rounded-lg border border-transparent bg-clip-padding text-sm font-semibold whitespace-nowrap transition-all duration-150 outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 data-[loading]:cursor-not-allowed data-[loading]:opacity-80 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0',\n {\n variants: {\n variant: {\n primary:\n 'cursor-pointer bg-primary text-primary-foreground hover:bg-primary/80 focus-visible:ring-primary/30',\n secondary:\n 'cursor-pointer bg-secondary text-secondary-foreground hover:bg-[var(--color-orange-700)] focus-visible:ring-secondary/30',\n cancel: 'cursor-pointer bg-destructive text-secondary-foreground hover:bg-[var(--color-red-600)] focus-visible:ring-destructive/30',\n outline:\n 'border border-foreground/50 bg-transparent text-muted-foreground hover:bg-foreground/50 hover:text-white',\n ghost: 'cursor-pointer bg-transparent text-muted-foreground hover:bg-foreground/10 hover:text-primary focus-visible:ring-ring/30 border-none',\n cancelGhost:\n 'cursor-pointer bg-destructive/10 text-red-600 hover:bg-destructive/15 hover:text-red-600 focus-visible:ring-ring/30',\n },\n size: {\n sm: 'h-8 px-3 text-xs',\n md: 'h-9 px-4 text-sm',\n lg: 'h-10 px-6 text-sm',\n 'icon-sm': 'size-8 rounded-full p-0',\n },\n },\n defaultVariants: {\n variant: 'primary',\n size: 'md',\n },\n },\n);\n\n/**\n * Interactive button with 6 variants and 4 sizes. Use `asChild` to render as any element via Radix Slot.\n * When `isLoading` is true, a spinner is shown and clicks are blocked while keeping the not-allowed cursor.\n */\nfunction Button({\n className,\n variant = 'primary',\n size = 'md',\n asChild = false,\n isLoading = false,\n children,\n onClick,\n ...props\n}: ComponentProps<'button'> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n isLoading?: boolean;\n }) {\n const Comp = asChild ? Slot.Root : 'button';\n\n function handleClick(e: MouseEvent<HTMLButtonElement>) {\n if (isLoading) {\n e.preventDefault();\n return;\n }\n onClick?.(e);\n }\n\n return (\n <Comp\n data-slot='button'\n data-variant={variant}\n data-size={size}\n data-loading={isLoading || undefined}\n aria-busy={isLoading || undefined}\n className={cn(buttonVariants({ variant, size, className }))}\n onClick={handleClick}\n {...props}>\n {isLoading && <LoaderCircle size={16} className='animate-spin' aria-hidden='true' />}\n {children}\n </Comp>\n );\n}\n\nexport { Button, buttonVariants };\n","import type { Editor } from '@tiptap/react';\nimport type { ReactNode } from 'react';\n\nimport { Button } from '@/components/ui/Button/button';\n\n/**\n * A toolbar entry is data, never a mark.\n *\n * An editor's marks are ProseMirror extensions — code with serialization and\n * parsing rules — so they belong to whoever owns the document contract, not to\n * this package. A consumer declares what its buttons do here and keeps its own\n * custom marks; the toolbar only asks the editor whether something is active\n * and runs the callback it was handed.\n */\ntype ToolbarItem =\n | { kind: 'separator' }\n | {\n kind: 'button';\n id: string;\n /**\n * A node, not an icon name: keeps this package off any icon library\n * and lets a button pass bare text (a font's own name, say) instead.\n */\n icon: ReactNode;\n /** Already translated. Names the button for both `title` and `aria-label`. */\n label: string;\n /**\n * What to ask the editor for the pressed state. Omit for actions that\n * only open a dialog and are never \"on\" — announcing those as a\n * permanently-off toggle misleads a screen reader.\n */\n active?: { name: string; attrs?: Record<string, unknown> };\n run: (editor: Editor) => void;\n }\n /** Escape hatch for entries that own state or render their own popover. */\n | { kind: 'custom'; id: string; render: (editor: Editor | null) => ReactNode };\n\ninterface RichTextToolbarProps {\n /** Null while the editor mounts; every button disables itself until then. */\n editor: Editor | null;\n items: ToolbarItem[];\n}\n\n/** Renders a declarative toolbar for a Tiptap editor. */\nfunction RichTextToolbar({ editor, items }: RichTextToolbarProps) {\n return (\n <div\n role='toolbar'\n data-slot='rich-text-toolbar'\n className='flex items-center gap-1 rounded-t-md border border-b-0 p-1'>\n {items.map((item, index) => {\n if (item.kind === 'separator') {\n // Index is a stable key here: `items` is a static\n // declaration, not a reorderable list.\n return (\n <div\n key={`separator-${index}`}\n data-slot='rich-text-toolbar-separator'\n aria-hidden='true'\n className='bg-border mx-1 h-5 w-px'\n />\n );\n }\n\n if (item.kind === 'custom') {\n return <span key={item.id}>{item.render(editor)}</span>;\n }\n\n const active = item.active\n ? (editor?.isActive(item.active.name, item.active.attrs) ?? false)\n : false;\n\n return (\n <Button\n key={item.id}\n type='button'\n size='sm'\n variant={active ? 'secondary' : 'ghost'}\n disabled={!editor}\n title={item.label}\n aria-label={item.label}\n aria-pressed={item.active ? active : undefined}\n data-slot='rich-text-toolbar-button'\n onClick={() => editor && item.run(editor)}>\n {item.icon}\n </Button>\n );\n })}\n </div>\n );\n}\n\nexport { RichTextToolbar };\nexport type { RichTextToolbarProps, ToolbarItem };\n","'use client';\n\nimport { useId } from 'react';\nimport { EditorContent, type Editor } from '@tiptap/react';\nimport type { ReactNode } from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { Label } from '@/components/ui/Label/label';\nimport { RichTextToolbar, type ToolbarItem } from './rich-text-toolbar';\n\n/**\n * Base content styles for the editable area, exported so a consumer can pass\n * them to `useEditor({ editorProps: { attributes: { class } } })` — ProseMirror\n * needs that class at construction time, before this component renders.\n *\n * Compose rather than replace: `cn(EDITOR_CONTENT_STYLE, 'my-overrides')`.\n */\nconst EDITOR_CONTENT_STYLE = cn(\n 'min-h-[220px] px-3 py-2 text-sm outline-none',\n '[&_h2]:text-lg [&_h2]:font-semibold',\n '[&_ol]:my-4 [&_ol]:list-decimal [&_ol]:pl-5 [&_ul]:my-4 [&_ul]:list-disc [&_ul]:pl-5',\n '[&_blockquote]:border-secondary [&_blockquote]:my-4 [&_blockquote]:ml-4 [&_blockquote]:border-l-4 [&_blockquote]:pl-2',\n '[&_a]:text-primary [&_a]:underline',\n // last-of-type, not last-child: prosemirror-tables appends its\n // .column-resize-handle widget inside the hovered cell, which makes the\n // cell's <p> stop matching :last-child and springs mb-4 back on — the row\n // grows 16px on hover. The handle is absolutely positioned but still counts\n // as a child for structural selectors.\n '[&_p]:mb-4 [&_p]:min-h-[1.25em] [&_p:last-of-type]:mb-0',\n // Paragraphs inside a quote sit closer together than body copy. Every Enter\n // inside a blockquote opens a new <p>, and at the body's mb-4 the lines of a\n // single quote read as separate paragraphs. Declared after the rule above so\n // it wins on equal specificity.\n '[&_blockquote_p]:mb-1 [&_blockquote_p:last-of-type]:mb-0',\n '[&_img]:my-2 [&_img]:max-w-full [&_img]:rounded-md',\n '[&_table]:my-3 [&_table]:w-full [&_table]:table-fixed [&_table]:border-collapse',\n '[&_td]:relative [&_td]:border [&_td]:px-2 [&_td]:py-1 [&_td]:align-top',\n '[&_th]:bg-muted [&_th]:relative [&_th]:border [&_th]:px-2 [&_th]:py-1 [&_th]:text-left [&_th]:font-semibold',\n '[&_.selectedCell]:bg-primary/10',\n // prosemirror-tables renders one handle PER ROW, so the column reads as a\n // single bar down the table. At full primary it looked like the table had\n // broken rather than like something to grab — hence the muted tint and the\n // wider, border-straddling hit area (matches upstream's 4px).\n '[&_.column-resize-handle]:bg-primary/40 [&_.column-resize-handle]:pointer-events-none [&_.column-resize-handle]:absolute [&_.column-resize-handle]:top-0 [&_.column-resize-handle]:-right-0.5 [&_.column-resize-handle]:bottom-0 [&_.column-resize-handle]:z-20 [&_.column-resize-handle]:w-1',\n '[&.resize-cursor]:cursor-col-resize',\n // Selected-node outline, scoped away from images.\n //\n // ProseMirror marks whichever node is selected, and this ring is the only\n // cue for most of them — but an image already announces its selection with a\n // visible resize handle, so the extra box only framed the picture.\n //\n // Excluded via `.node-image`, the class Tiptap puts on the wrapper it\n // generates for a node view (`div.react-renderer.node-<name>`). That wrapper,\n // not the NodeViewWrapper inside it, is what receives\n // ProseMirror-selectednode — so a data-slot on our own element sits one level\n // too deep to match.\n '[&_.ProseMirror-selectednode:not(.node-image)]:outline-primary [&_.ProseMirror-selectednode:not(.node-image)]:outline-2 [&_.ProseMirror-selectednode:not(.node-image)]:outline-offset-2 [&_.ProseMirror-selectednode:not(.node-image)]:outline',\n);\n\ninterface RichTextEditorProps {\n /** Null while the editor mounts. Build it with Tiptap's `useEditor`. */\n editor: Editor | null;\n items: ToolbarItem[];\n /**\n * Already translated. Omit to render no visible label.\n *\n * Note that a visible label does NOT name the editable area on its own:\n * ProseMirror renders that as role='textbox', and EditorContent's props land\n * on a wrapper div rather than on the editable node. Give the editor its own\n * name where you construct it:\n *\n * ```ts\n * useEditor({\n * editorProps: { attributes: { class: EDITOR_CONTENT_STYLE, 'aria-label': t('body') } },\n * })\n * ```\n */\n label?: string;\n /** Already translated message. Drives the destructive border and the hint. */\n error?: string;\n /**\n * Slot under the editor for product-specific actions, so the editor itself\n * stays free of any one product's features.\n */\n footer?: ReactNode;\n className?: string;\n}\n\n/** Chrome for a Tiptap editor: a declarative toolbar, the editable area, and an error slot. */\nfunction RichTextEditor({ editor, items, label, error, footer, className }: RichTextEditorProps) {\n const errorId = useId();\n\n return (\n <div data-slot='rich-text-editor' className={cn('flex flex-col gap-1', className)}>\n {label && <Label>{label}</Label>}\n <RichTextToolbar editor={editor} items={items} />\n <EditorContent\n editor={editor}\n aria-invalid={!!error}\n aria-errormessage={error ? errorId : undefined}\n onClick={() => editor?.commands.focus()}\n className={cn(\n 'rounded-t-none rounded-b-md border shadow-xs',\n 'focus-within:border-ring focus-within:ring-ring/30 focus-within:ring-3',\n error && 'border-destructive',\n )}\n />\n {/* role='alert' rather than a plain span: aria-errormessage only\n counts if the referenced node is exposed to assistive tech, and\n an alert also announces the message when it appears. */}\n {error && (\n <span id={errorId} role='alert' className='text-destructive text-xs'>\n {error}\n </span>\n )}\n {footer}\n </div>\n );\n}\n\nexport { RichTextEditor, EDITOR_CONTENT_STYLE };\nexport type { RichTextEditorProps };\n","import { type ComponentProps } from 'react';\nimport { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui';\n\nimport { cn } from '@/lib/utils';\nimport { CheckIcon, ChevronRightIcon } from 'lucide-react';\n\nfunction DropdownMenu({ ...props }: ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n return <DropdownMenuPrimitive.Root {...props} />;\n}\n\nfunction DropdownMenuPortal({\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Portal>) {\n return <DropdownMenuPrimitive.Portal {...props} />;\n}\n\nfunction DropdownMenuTrigger({\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n return <DropdownMenuPrimitive.Trigger data-slot='dropdown-menu-trigger' {...props} />;\n}\n\nfunction DropdownMenuContent({\n className,\n align = 'start',\n sideOffset = 4,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n data-slot='dropdown-menu-content'\n sideOffset={sideOffset}\n align={align}\n className={cn(\n 'bg-popover text-popover-foreground ring-foreground/5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:ring-foreground/10 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-48 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-3xl p-1.5 shadow-lg ring-1 duration-100 data-[state=closed]:overflow-hidden',\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n}\n\nfunction DropdownMenuGroup({ ...props }: ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n return <DropdownMenuPrimitive.Group data-slot='dropdown-menu-group' {...props} />;\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = 'default',\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: 'default' | 'destructive';\n}) {\n return (\n <DropdownMenuPrimitive.Item\n data-slot='dropdown-menu-item'\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"group/dropdown-menu-item focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:*:[svg]:text-destructive relative flex cursor-default items-center gap-2.5 rounded-2xl px-3 py-2 text-sm font-medium outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-9.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n inset,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & {\n inset?: boolean;\n}) {\n return (\n <DropdownMenuPrimitive.CheckboxItem\n data-slot='dropdown-menu-checkbox-item'\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground relative flex cursor-default items-center gap-2.5 rounded-2xl py-2 pr-8 pl-3 text-sm font-medium outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-9.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n checked={checked}\n {...props}>\n <span\n className='pointer-events-none absolute right-2 flex items-center justify-center'\n data-slot='dropdown-menu-checkbox-item-indicator'>\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon aria-hidden='true' />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n );\n}\n\nfunction DropdownMenuRadioGroup({\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {\n return <DropdownMenuPrimitive.RadioGroup data-slot='dropdown-menu-radio-group' {...props} />;\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n inset,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & {\n inset?: boolean;\n}) {\n return (\n <DropdownMenuPrimitive.RadioItem\n data-slot='dropdown-menu-radio-item'\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground relative flex cursor-default items-center gap-2.5 rounded-2xl py-2 pr-8 pl-3 text-sm font-medium outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-9.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}>\n <span\n className='pointer-events-none absolute right-2 flex items-center justify-center'\n data-slot='dropdown-menu-radio-item-indicator'>\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon aria-hidden='true' />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n );\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean;\n}) {\n return (\n <DropdownMenuPrimitive.Label\n data-slot='dropdown-menu-label'\n data-inset={inset}\n className={cn('text-muted-foreground px-3 py-2.5 text-xs data-inset:pl-9.5', className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot='dropdown-menu-separator'\n className={cn('bg-border/50 -mx-1.5 my-1.5 h-px', className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuShortcut({ className, ...props }: ComponentProps<'span'>) {\n return (\n <span\n data-slot='dropdown-menu-shortcut'\n className={cn(\n 'text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground ml-auto text-xs tracking-widest',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSub({ ...props }: ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot='dropdown-menu-sub' {...props} />;\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n}) {\n return (\n <DropdownMenuPrimitive.SubTrigger\n data-slot='dropdown-menu-sub-trigger'\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center gap-2 rounded-2xl px-3 py-2 text-sm font-medium outline-hidden select-none data-inset:pl-9.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}>\n {children}\n <ChevronRightIcon className='ml-auto' aria-hidden='true' />\n </DropdownMenuPrimitive.SubTrigger>\n );\n}\n\nfunction DropdownMenuSubContent({\n className,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n return (\n <DropdownMenuPrimitive.SubContent\n data-slot='dropdown-menu-sub-content'\n className={cn(\n 'bg-popover text-popover-foreground ring-foreground/5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:ring-foreground/10 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 z-50 min-w-36 origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-3xl p-1.5 shadow-lg ring-1 duration-100',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport {\n DropdownMenu,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubTrigger,\n DropdownMenuSubContent,\n};\n","'use client';\n\nimport { useState } from 'react';\nimport type { Editor } from '@tiptap/react';\n// Type-only: Tiptap declares its table commands (insertTable, addRowAfter, …)\n// by module augmentation, so they exist on ChainedCommands only where the table\n// extension is in scope. `import type` pulls in those declarations without\n// adding the package to the bundle — the consumer supplies the runtime copy\n// through its own `extensions` array.\nimport type {} from '@tiptap/extension-table';\nimport type { ReactNode } from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/Button/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@/components/ui/DropdownMenu/dropdown-menu';\n\nconst DEFAULT_ROWS = 8;\nconst DEFAULT_COLUMNS = 10;\n\ninterface TableMenuLabels {\n trigger: string;\n insert: string;\n /**\n * A function, not a string: this is the only label with variables, and\n * formatting it here would mean reimplementing message interpolation. The\n * consumer keeps that in whatever i18n layer it already has.\n */\n dimensions: (rows: number, columns: number) => string;\n rowBefore: string;\n rowAfter: string;\n deleteRow: string;\n columnBefore: string;\n columnAfter: string;\n deleteColumn: string;\n toggleHeader: string;\n deleteTable: string;\n}\n\ninterface TableMenuProps {\n editor: Editor | null;\n labels: TableMenuLabels;\n icon: ReactNode;\n /**\n * The picker grid's extent. These bound the visual picker only — a\n * consumer whose document contract caps table size should also enforce\n * that ceiling where it validates the document.\n */\n maxRows?: number;\n maxColumns?: number;\n}\n\n/** Word-style table controls: a grid picker to insert, then row/column actions. */\nfunction TableMenu({\n editor,\n labels,\n icon,\n maxRows = DEFAULT_ROWS,\n maxColumns = DEFAULT_COLUMNS,\n}: TableMenuProps) {\n const [hovered, setHovered] = useState({ rows: 0, columns: 0 });\n\n // `can().deleteTable()` is the cheapest \"is the cursor in a table\" probe\n // Tiptap offers, and it gates every row/column action below.\n const insideTable = editor?.can().deleteTable() ?? false;\n\n function insert(rows: number, columns: number) {\n editor?.chain().focus().insertTable({ rows, cols: columns, withHeaderRow: true }).run();\n }\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type='button'\n size='sm'\n variant={editor?.isActive('table') ? 'secondary' : 'ghost'}\n disabled={!editor}\n title={labels.trigger}\n aria-label={labels.trigger}\n data-slot='table-menu-trigger'>\n {icon}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align='start' className='w-56'>\n {/* role='none' on the wrapper: a role='menu' subtree may only\n contain menuitem/group/separator, and this size picker is a\n grid of plain buttons plus a live counter. Presenting the\n wrapper as non-semantic takes it out of the menu's required\n -children contract while leaving its buttons reachable —\n which is what axe's aria-required-children rule wants. */}\n <div role='none' className='px-2 py-1.5'>\n <p className='text-muted-foreground mb-1.5 text-xs'>{labels.insert}</p>\n <div\n className='grid gap-0.5'\n style={{ gridTemplateColumns: `repeat(${maxColumns}, 1fr)` }}\n onMouseLeave={() => setHovered({ rows: 0, columns: 0 })}>\n {Array.from({ length: maxRows * maxColumns }, (_, index) => {\n const rows = Math.floor(index / maxColumns) + 1;\n const columns = (index % maxColumns) + 1;\n const active = rows <= hovered.rows && columns <= hovered.columns;\n\n return (\n <button\n key={index}\n type='button'\n aria-label={labels.dimensions(rows, columns)}\n className={cn(\n 'h-3.5 w-3.5 cursor-pointer rounded-[2px] border',\n active ? 'bg-primary border-primary' : 'bg-background',\n )}\n // onFocus mirrors onMouseEnter so the grid\n // is usable by keyboard, not just hover.\n onMouseEnter={() => setHovered({ rows, columns })}\n onFocus={() => setHovered({ rows, columns })}\n onClick={() => insert(rows, columns)}\n />\n );\n })}\n </div>\n <p\n aria-live='polite'\n data-slot='table-menu-dimensions'\n className='text-muted-foreground mt-1.5 text-xs tabular-nums'>\n {labels.dimensions(hovered.rows, hovered.columns)}\n </p>\n </div>\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem\n className='cursor-pointer'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().addRowBefore().run()}>\n {labels.rowBefore}\n </DropdownMenuItem>\n <DropdownMenuItem\n className='cursor-pointer'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().addRowAfter().run()}>\n {labels.rowAfter}\n </DropdownMenuItem>\n <DropdownMenuItem\n className='cursor-pointer'\n variant='destructive'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().deleteRow().run()}>\n {labels.deleteRow}\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem\n className='cursor-pointer'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().addColumnBefore().run()}>\n {labels.columnBefore}\n </DropdownMenuItem>\n <DropdownMenuItem\n className='cursor-pointer'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().addColumnAfter().run()}>\n {labels.columnAfter}\n </DropdownMenuItem>\n <DropdownMenuItem\n className='cursor-pointer'\n variant='destructive'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().deleteColumn().run()}>\n {labels.deleteColumn}\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem\n className='cursor-pointer'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().toggleHeaderRow().run()}>\n {labels.toggleHeader}\n </DropdownMenuItem>\n <DropdownMenuItem\n className='cursor-pointer'\n variant='destructive'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().deleteTable().run()}>\n {labels.deleteTable}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport { TableMenu };\nexport type { TableMenuProps, TableMenuLabels };\n","// ─────────────────────────────────────────────\n// tcce-design-system · animation tokens\n// Motion (ex Framer Motion) — sutil y profesional\n// ─────────────────────────────────────────────\n\n// ── Durations ────────────────────────────────\n// Usa la escala más corta posible para cada caso.\n// instant → feedback táctil (hover, active, focus ring)\n// fast → elementos pequeños que entran/salen (badge, tooltip, switch)\n// normal → componentes de tamaño medio (dropdown, toast, input state)\n// slow → overlays y transiciones de página (modal backdrop, sidebar)\nexport const duration = {\n instant: 0.1,\n fast: 0.15,\n normal: 0.25,\n slow: 0.4,\n} as const;\n\n// ── Easings ──────────────────────────────────\n// Curvas estándar de Material Design adaptadas para uso profesional.\n// smooth → entrada y salida equilibrada (la más usada)\n// enter → aceleración suave al entrar (elementos que aparecen)\n// exit → desaceleración al salir (elementos que desaparecen)\n// linear → progreso, loaders, skeleton shimmer\nexport const ease = {\n smooth: [0.4, 0, 0.2, 1] as const,\n enter: [0.0, 0, 0.2, 1] as const,\n exit: [0.4, 0, 1.0, 1] as const,\n linear: [0.0, 0, 1.0, 1] as const,\n drawer: [0.22, 1, 0.36, 1] as const,\n} as const;\n\n// ── Spring configs ────────────────────────────\n// Solo para componentes que necesitan sensación física ligera.\n// gentle → modales, drawers, paneles deslizantes\n// snappy → switches, toggles, checkboxes\n// NO usar spring en: toasts, tooltips, dropdowns (demasiado movimiento)\nexport const spring = {\n gentle: { type: 'spring', stiffness: 260, damping: 28 } as const,\n snappy: { type: 'spring', stiffness: 400, damping: 30 } as const,\n} as const;\n\n// ── Transitions predefinidas ──────────────────\n// Combinaciones listas para usar en cada tipo de componente.\n// Importa la que corresponda en lugar de armar la config cada vez.\n\nexport const transition = {\n // Botones — feedback instantáneo en hover/tap\n button: {\n duration: duration.instant,\n ease: ease.smooth,\n },\n\n // Switch / toggle / checkbox\n toggle: {\n ...spring.snappy,\n },\n\n // Inputs — cambio de borde en focus, estados de error\n input: {\n duration: duration.fast,\n ease: ease.smooth,\n },\n\n // Dropdown / select / popover\n dropdown: {\n duration: duration.fast,\n ease: ease.enter,\n },\n\n // Toast / notification — entra rápido, sale más rápido aún\n toast: {\n duration: duration.fast,\n ease: ease.smooth,\n },\n\n // Modal / dialog — más lento para dar peso al overlay\n modal: {\n ...spring.gentle,\n },\n\n // Sidebar / navigation drawer\n sidebar: {\n duration: duration.slow,\n ease: ease.smooth,\n },\n\n // Cards — hover sutil, sin spring\n card: {\n duration: duration.fast,\n ease: ease.smooth,\n },\n\n // Drawer / slide panel — smooth enter, fast exit\n drawer: {\n duration: 0.3,\n ease: ease.drawer,\n },\n drawerExit: {\n duration: 0.2,\n ease: ease.exit,\n },\n} as const;\n\n// ── Variants Motion reutilizables ─────────────\n// Úsalos directamente en <motion.div variants={fadeIn}>\n\nexport const fadeIn = {\n hidden: { opacity: 0 },\n visible: { opacity: 1, transition: transition.dropdown },\n exit: { opacity: 0, transition: { duration: duration.fast, ease: ease.exit } },\n} as const;\n\nexport const slideUp = {\n hidden: { opacity: 0, y: 8 },\n visible: { opacity: 1, y: 0, transition: transition.dropdown },\n exit: { opacity: 0, y: 4, transition: { duration: duration.fast, ease: ease.exit } },\n} as const;\n\nexport const slideRight = {\n hidden: { opacity: 0, x: -12 },\n visible: { opacity: 1, x: 0, transition: transition.sidebar },\n exit: { opacity: 0, x: -12, transition: { duration: duration.normal, ease: ease.exit } },\n} as const;\n\nexport const scaleIn = {\n hidden: { opacity: 0, scale: 0.97 },\n visible: { opacity: 1, scale: 1, transition: transition.modal },\n exit: { opacity: 0, scale: 0.97, transition: { duration: duration.fast, ease: ease.exit } },\n} as const;\n\n// ── Stagger (para listas y grids) ─────────────\n// Úsalo en el contenedor padre con variants + staggerChildren\nexport const stagger = {\n container: {\n hidden: {},\n visible: { transition: { staggerChildren: 0.06, delayChildren: 0.05 } },\n },\n item: {\n hidden: { opacity: 0, y: 6 },\n visible: { opacity: 1, y: 0, transition: transition.card },\n },\n} as const;\n\n// ── Export agrupado ───────────────────────────\nexport const animation = {\n duration,\n ease,\n spring,\n transition,\n variants: { fadeIn, slideUp, slideRight, scaleIn, stagger },\n} as const;\n\nexport type AnimationTokens = typeof animation;\n","import { createContext, useContext, useState, type ComponentProps } from 'react';\nimport { Dialog as DialogPrimitive } from 'radix-ui';\nimport { motion, AnimatePresence } from 'motion/react';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/Button/button';\nimport { XIcon } from 'lucide-react';\nimport { transition, ease, duration } from '@/tokens/animation';\n\n// ─── Contexto interno ─────────────────────────────────────────────────────────\n\nconst DialogContext = createContext(false);\n\n// ─── Root ────────────────────────────────────────────────────────────────────\n\nfunction Dialog({ children, ...props }: ComponentProps<typeof DialogPrimitive.Root>) {\n const [internalOpen, setInternalOpen] = useState(props.defaultOpen ?? false);\n\n const isOpen = props.open !== undefined ? props.open : internalOpen;\n\n return (\n <DialogContext.Provider value={isOpen}>\n <DialogPrimitive.Root\n data-slot='dialog'\n open={isOpen}\n onOpenChange={(v) => {\n setInternalOpen(v);\n props.onOpenChange?.(v);\n }}\n {...props}>\n {children}\n </DialogPrimitive.Root>\n </DialogContext.Provider>\n );\n}\n\n// ─── Trigger ─────────────────────────────────────────────────────────────────\n\nfunction DialogTrigger({ ...props }: ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot='dialog-trigger' {...props} />;\n}\n\n// ─── Portal — AnimatePresence vive aquí ──────────────────────────────────────\n\nfunction DialogPortal({ children, ...props }: ComponentProps<typeof DialogPrimitive.Portal>) {\n const isOpen = useContext(DialogContext);\n\n return (\n <DialogPrimitive.Portal data-slot='dialog-portal' forceMount {...props}>\n <AnimatePresence mode='sync'>{isOpen && children}</AnimatePresence>\n </DialogPrimitive.Portal>\n );\n}\n\n// ─── Close ───────────────────────────────────────────────────────────────────\n\nfunction DialogClose({ ...props }: ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot='dialog-close' {...props} />;\n}\n\n// ─── Overlay — fade independiente ────────────────────────────────────────────\n\nfunction DialogOverlay({ className, ...props }: ComponentProps<typeof DialogPrimitive.Overlay>) {\n return (\n <DialogPrimitive.Overlay data-slot='dialog-overlay' asChild forceMount {...props}>\n <motion.div\n className={cn(\n 'fixed inset-0 isolate z-50 bg-black/30 supports-backdrop-filter:backdrop-blur-sm',\n className,\n )}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: duration.normal, ease: ease.smooth }}\n />\n </DialogPrimitive.Overlay>\n );\n}\n\n// ─── Content — scale + fade + slideUp con spring ─────────────────────────────\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = false,\n ...props\n}: ComponentProps<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean;\n}) {\n return (\n <DialogPortal>\n <DialogOverlay key='dialog-overlay' />\n <DialogPrimitive.Content\n key='dialog-content'\n data-slot='dialog-content'\n asChild\n forceMount\n className={cn(\n 'bg-popover text-popover-foreground ring-foreground/5 dark:ring-foreground/10 fixed top-1/2 left-1/2 z-50 flex max-h-[85vh] w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 flex-col rounded-lg text-sm shadow-xl ring-1 outline-none sm:max-w-sm',\n className,\n )}\n {...props}>\n <motion.div\n className='flex max-h-[85vh] flex-col'\n initial={{ opacity: 0, scale: 0.96, y: 8 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.96, y: 4 }}\n transition={transition.modal}>\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close data-slot='dialog-close' asChild>\n <Button\n variant='ghost'\n className='absolute top-4 right-4'\n size='icon-sm'>\n <XIcon />\n <span className='sr-only'>Close</span>\n </Button>\n </DialogPrimitive.Close>\n )}\n </motion.div>\n </DialogPrimitive.Content>\n </DialogPortal>\n );\n}\n\n// ─── Header ──────────────────────────────────────────────────────────────────\n\nfunction DialogHeader({ className, ...props }: ComponentProps<'div'>) {\n return (\n <div\n data-slot='dialog-header'\n className={cn('flex shrink-0 flex-col gap-3 px-6 pt-6', className)}\n {...props}\n />\n );\n}\n\nfunction DialogBody({ className, ...props }: ComponentProps<'div'>) {\n return (\n <div\n data-slot='dialog-body'\n className={cn('flex-1 overflow-y-auto px-6 pb-6', className)}\n {...props}\n />\n );\n}\n\n// ─── Footer ──────────────────────────────────────────────────────────────────\n\nfunction DialogFooter({\n className,\n showCloseButton = false,\n children,\n ...props\n}: ComponentProps<'div'> & {\n showCloseButton?: boolean;\n}) {\n return (\n <div\n data-slot='dialog-footer'\n className={cn(\n 'border-border bg-muted/40 flex shrink-0 flex-wrap items-center justify-end gap-2 rounded-b-lg border-t px-6 pt-4 pb-4',\n className,\n )}\n {...props}>\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close asChild>\n <Button variant='secondary'>Close</Button>\n </DialogPrimitive.Close>\n )}\n </div>\n );\n}\n\n// ─── Title ───────────────────────────────────────────────────────────────────\n\nfunction DialogTitle({ className, ...props }: ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot='dialog-title'\n className={cn('font-heading text-lg leading-none font-bold', className)}\n {...props}\n />\n );\n}\n\n// ─── Description ─────────────────────────────────────────────────────────────\n\nfunction DialogDescription({\n className,\n ...props\n}: ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot='dialog-description'\n className={cn(\n 'text-muted-foreground *:[a]:hover:text-foreground text-sm *:[a]:underline *:[a]:underline-offset-3',\n className,\n )}\n {...props}\n />\n );\n}\n\n// ─── Exports ─────────────────────────────────────────────────────────────────\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogBody,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n","import { UploadIcon } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { createContext, useContext } from 'react';\nimport type { DropEvent, DropzoneOptions, FileRejection } from 'react-dropzone';\nimport { useDropzone } from 'react-dropzone';\nimport { cva } from 'class-variance-authority';\nimport { Button } from '@/components/ui/Button/button';\nimport { cn } from '@/lib/utils';\n\ninterface DropzoneContextType {\n src?: File[];\n accept?: DropzoneOptions['accept'];\n maxSize?: DropzoneOptions['maxSize'];\n minSize?: DropzoneOptions['minSize'];\n maxFiles?: DropzoneOptions['maxFiles'];\n}\n\nconst renderBytes = (bytes: number) => {\n const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];\n let size = bytes;\n let unitIndex = 0;\n\n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n\n return `${size.toFixed(2)}${units[unitIndex]}`;\n};\n\nconst DropzoneContext = createContext<DropzoneContextType | undefined>(undefined);\n\nconst dropzoneVariants = cva('', {\n variants: {\n border: {\n default: 'border border-solid border-foreground/15',\n dashed: 'border-dashed border-foreground/50',\n },\n },\n defaultVariants: {\n border: 'default',\n },\n});\n\nexport type DropzoneProps = Omit<DropzoneOptions, 'onDrop'> & {\n src?: File[];\n className?: string;\n border?: 'default' | 'dashed';\n onDrop?: (acceptedFiles: File[], fileRejections: FileRejection[], event: DropEvent) => void;\n children?: ReactNode;\n};\n\nexport const Dropzone = ({\n accept,\n maxFiles = 1,\n maxSize,\n minSize,\n onDrop,\n onError,\n disabled,\n src,\n className,\n children,\n border,\n ...props\n}: DropzoneProps) => {\n const { getRootProps, getInputProps, isDragActive } = useDropzone({\n accept,\n maxFiles,\n maxSize,\n minSize,\n onError,\n disabled,\n onDrop: (acceptedFiles, fileRejections, event) => {\n if (fileRejections.length > 0) {\n const message = fileRejections.at(0)?.errors.at(0)?.message;\n onError?.(new Error(message));\n }\n if (acceptedFiles.length > 0) {\n onDrop?.(acceptedFiles, fileRejections, event);\n }\n },\n ...props,\n });\n\n return (\n <DropzoneContext.Provider\n key={JSON.stringify(src)}\n value={{ src, accept, maxSize, minSize, maxFiles }}>\n <Button\n data-slot='dropzone'\n data-border={border ?? 'default'}\n className={cn(\n 'cursor-auto relative h-auto w-full flex-col overflow-hidden p-8',\n dropzoneVariants({ border }),\n isDragActive && 'bg-foreground/10 outline-none',\n className,\n )}\n disabled={disabled}\n type='button'\n variant='ghost'\n {...getRootProps()}>\n <input {...getInputProps()} disabled={disabled} />\n {children}\n </Button>\n </DropzoneContext.Provider>\n );\n};\n\nconst useDropzoneContext = () => {\n const context = useContext(DropzoneContext);\n\n if (!context) {\n throw new Error('useDropzoneContext must be used within a Dropzone');\n }\n\n return context;\n};\n\nexport interface DropzoneContentProps {\n children?: ReactNode;\n className?: string;\n}\n\nconst maxLabelItems = 3;\n\nexport const DropzoneContent = ({ children, className }: DropzoneContentProps) => {\n const { src } = useDropzoneContext();\n\n if (!src) {\n return null;\n }\n\n if (children) {\n return children;\n }\n\n return (\n <div className={cn('flex flex-col items-center justify-center', className)}>\n <div className='bg-muted text-muted-foreground flex size-8 items-center justify-center rounded-md'>\n <UploadIcon size={16} />\n </div>\n <p className='text-foreground my-2 w-full truncate text-sm font-medium'>\n {src.length > maxLabelItems\n ? `${new Intl.ListFormat('en').format(\n src.slice(0, maxLabelItems).map((file) => file.name),\n )} and ${src.length - maxLabelItems} more`\n : new Intl.ListFormat('en').format(src.map((file) => file.name))}\n </p>\n <p className='text-muted-foreground w-full text-xs font-normal text-wrap'>\n Drag and drop or click to replace\n </p>\n </div>\n );\n};\n\nexport interface DropzoneEmptyStateProps {\n children?: ReactNode;\n className?: string;\n}\n\nexport const DropzoneEmptyState = ({ children, className }: DropzoneEmptyStateProps) => {\n const { src, accept, maxSize, minSize, maxFiles } = useDropzoneContext();\n\n if (src) {\n return null;\n }\n\n if (children) {\n return children;\n }\n\n let caption = '';\n\n if (accept) {\n caption += 'Accepts ';\n caption += new Intl.ListFormat('en').format(Object.keys(accept));\n }\n\n if (minSize && maxSize) {\n caption += ` between ${renderBytes(minSize)} and ${renderBytes(maxSize)}`;\n } else if (minSize) {\n caption += ` at least ${renderBytes(minSize)}`;\n } else if (maxSize) {\n caption += ` less than ${renderBytes(maxSize)}`;\n }\n\n return (\n <div className={cn('flex flex-col items-center justify-center', className)}>\n <div className='bg-muted text-muted-foreground flex size-8 items-center justify-center rounded-md'>\n <UploadIcon size={16} />\n </div>\n <p className='text-foreground my-2 w-full text-center text-sm font-medium text-wrap'>\n Upload {maxFiles === 1 ? 'a file' : 'files'}\n </p>\n <p className='text-muted-foreground text-center text-xs font-normal text-wrap'>\n Drag and drop or click to upload\n </p>\n\n {caption && (\n <p className='text-muted-foreground text-xs font-normal text-wrap'>{caption}.</p>\n )}\n </div>\n );\n};\n","import { type ComponentProps } from 'react';\nimport { cn } from '@/lib/utils';\n\nfunction Input({ className, type, ...props }: ComponentProps<'input'>) {\n return (\n <input\n type={type}\n data-slot='input'\n className={cn(\n 'border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[border-color,box-shadow] outline-hidden md:text-sm',\n 'placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground',\n 'file:text-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium',\n 'focus-visible:border-ring focus-visible:ring-ring/30 focus-visible:ring-3',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-invalid:ring-3',\n 'dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport { Input };\n","import { useId } from 'react';\nimport { Trash2 } from 'lucide-react';\n\nimport { Button } from '@/components/ui/Button/button';\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/Dialog/dialog';\nimport { Dropzone, DropzoneContent, DropzoneEmptyState } from '@/components/ui/Dropzone/dropzone';\nimport { Input } from '@/components/ui/Input/input';\nimport { Label } from '@/components/ui/Label/label';\n\nconst DEFAULT_MAX_SIZE = 5 * 1024 * 1024;\nconst DEFAULT_ACCEPT = { 'image/*': ['.png', '.jpg', '.jpeg', '.webp'] };\n\ninterface InsertImageDialogLabels {\n title: string;\n urlLabel: string;\n urlPlaceholder: string;\n altLabel: string;\n hint: string;\n cancel: string;\n apply: string;\n remove: string;\n}\n\ninterface InsertImageDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n labels: InsertImageDialogLabels;\n url: string;\n onUrlChange: (url: string) => void;\n alt: string;\n onAltChange: (alt: string) => void;\n file: File | null;\n onFileChange: (file: File | null) => void;\n /** True while the consumer is transferring the picked file. Locks the form. */\n uploading: boolean;\n onApply: () => void;\n onCancel?: () => void;\n /**\n * True when editing an image already in the document — reveals the\n * destructive remove action beside the apply button.\n */\n removable?: boolean;\n onRemove?: () => void;\n /** Upload limits belong to whoever receives the file, not to this dialog. */\n maxSizeBytes?: number;\n accept?: Record<string, string[]>;\n}\n\n/**\n * A controlled form for inserting an image. It deliberately does NOT upload:\n * the consumer owns the transfer (its own API, its own storage) and drives\n * `uploading` / `onApply` from there, so this dialog stays reusable across\n * products with different backends.\n */\nfunction InsertImageDialog({\n open,\n onOpenChange,\n labels,\n url,\n onUrlChange,\n alt,\n onAltChange,\n file,\n onFileChange,\n uploading,\n onApply,\n onCancel,\n removable = false,\n onRemove,\n maxSizeBytes = DEFAULT_MAX_SIZE,\n accept = DEFAULT_ACCEPT,\n}: InsertImageDialogProps) {\n // Generated ids, not fixed strings: two dialogs on one page would otherwise\n // share an id and each label would point at the wrong input.\n const urlId = useId();\n const altId = useId();\n\n // Alt text is required by design, not by politeness — an image with no\n // alternative text is unusable to a screen reader, so the dialog refuses to\n // put one in the document at all. There is deliberately no prop to opt out.\n const canApply = Boolean(file || url.trim()) && Boolean(alt.trim()) && !uploading;\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className='px-4 py-2' data-slot='insert-image-dialog'>\n <DialogHeader>\n <DialogTitle>{labels.title}</DialogTitle>\n </DialogHeader>\n <div className='mt-4 flex flex-col gap-3'>\n <Dropzone\n accept={accept}\n maxFiles={1}\n maxSize={maxSizeBytes}\n disabled={uploading}\n src={file ? [file] : []}\n onDrop={(files) => onFileChange(files[0] ?? null)}>\n <DropzoneEmptyState />\n <DropzoneContent />\n </Dropzone>\n {file && <p className='text-muted-foreground text-xs'>{file.name}</p>}\n <div className='flex flex-col gap-1'>\n <Label htmlFor={urlId}>{labels.urlLabel}</Label>\n <Input\n id={urlId}\n placeholder={labels.urlPlaceholder}\n value={url}\n onChange={(event) => onUrlChange(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && canApply) {\n event.preventDefault();\n onApply();\n }\n }}\n />\n </div>\n <div className='flex flex-col gap-1'>\n <Label htmlFor={altId}>{labels.altLabel}</Label>\n <Input\n id={altId}\n value={alt}\n onChange={(event) => onAltChange(event.target.value)}\n />\n </div>\n <p className='text-muted-foreground text-xs'>{labels.hint}</p>\n </div>\n <DialogFooter>\n {removable && onRemove && (\n <Button\n type='button'\n variant='ghost'\n className='text-destructive'\n onClick={onRemove}>\n <Trash2 className='h-4 w-4' />\n {labels.remove}\n </Button>\n )}\n <Button\n type='button'\n variant='outline'\n onClick={() => {\n if (onCancel) onCancel();\n else onOpenChange(false);\n }}>\n {labels.cancel}\n </Button>\n <Button type='button' onClick={onApply} disabled={!canApply}>\n {labels.apply}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport { InsertImageDialog };\nexport type { InsertImageDialogProps, InsertImageDialogLabels };\n","'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { Image, type ImageOptions } from '@tiptap/extension-image';\nimport { NodeViewWrapper, ReactNodeViewRenderer, type NodeViewProps } from '@tiptap/react';\n\nimport { cn } from '@/lib/utils';\n\nconst DEFAULT_MIN_WIDTH = 120;\n/** Fallbacks for the brief window before the file reports its real dimensions. */\nconst DEFAULT_START_WIDTH = 400;\nconst DEFAULT_RATIO = 4 / 3;\n/** How much one arrow press resizes by: coarse enough to be useful, fine enough to aim. */\nconst KEYBOARD_STEP = 20;\n\ninterface ResizableImageOptions {\n /** Already translated: names the resize handle for assistive tech. */\n resizeLabel: string;\n minWidth?: number;\n}\n\ninterface ImageAttrs {\n src: string;\n alt: string;\n width: number;\n height: number;\n}\n\n/**\n * A resize-overlay NodeView. The stock Image extension renders its own view (a\n * draggable img); this one owns the DOM so the handle can sit on top of the\n * picture.\n *\n * `width`/`height` are applied as an inline style rather than HTML attributes,\n * so a consumer that declares them `rendered: false` keeps the size in the\n * document JSON only — which is where a serializer should read it from. On the\n * unmeasured path (0/0) the img falls back to its natural size instead of\n * collapsing to `width=\"0\"`.\n */\nfunction ResizableImageView({ node, updateAttributes, selected, extension }: NodeViewProps) {\n const { src, alt, width, height } = node.attrs as ImageAttrs;\n\n // A ref that always holds the node's current size. The destructured values\n // above are captured by the resize callbacks, and ProseMirror can apply\n // several transactions before React re-renders this view — so two arrow\n // presses in a row would both start from the same stale width. Repeated\n // presses have to compound.\n const sizeRef = useRef({ width, height });\n sizeRef.current = { width, height };\n\n const { resizeLabel, minWidth = DEFAULT_MIN_WIDTH } =\n extension.options as ResizableImageOptions;\n\n const dragRef = useRef<{\n startX: number;\n width: number;\n ratio: number;\n maxWidth: number;\n } | null>(null);\n const [dragging, setDragging] = useState(false);\n\n // Shared by the pointer drag and the arrow keys so both clamp identically.\n const resizeTo = useCallback(\n (nextWidth: number, ratio: number, maxWidth: number) => {\n const clamped = Math.max(minWidth, Math.min(Math.round(nextWidth), maxWidth));\n updateAttributes({ width: clamped, height: Math.round(clamped / ratio) });\n },\n [minWidth, updateAttributes],\n );\n\n // Reads the live DOM because width/height stay 0 until the first resize.\n const measure = useCallback((handle: HTMLElement) => {\n const image = handle.parentElement?.querySelector('img') ?? null;\n const current = sizeRef.current;\n\n // The ceiling is the EDITABLE AREA, never the wrapper: the wrapper is\n // inline-block, so its own width is the image's width — measuring it\n // made every shrink permanent, because the reduced size instantly\n // became the new maximum and growing back was impossible.\n const editable = handle.closest('.ProseMirror');\n const available = editable?.clientWidth ?? 0;\n\n const naturalWidth = image?.naturalWidth ?? 0;\n const naturalHeight = image?.naturalHeight ?? 0;\n\n // The ratio comes from whichever pair is known, but the starting\n // WIDTH must be what is on screen — capped to the column. Starting\n // from an unbounded natural width meant a 4000px photo computed\n // 3980 for the first shrink, clamped straight to the ceiling, and\n // then sat there: every later press recomputed the same way, so the\n // image could never be made smaller.\n const ratio =\n current.width > 0 && current.height > 0\n ? current.width / current.height\n : naturalWidth > 0 && naturalHeight > 0\n ? naturalWidth / naturalHeight\n : DEFAULT_RATIO;\n\n const unbounded = current.width > 0 ? current.width : naturalWidth || DEFAULT_START_WIDTH;\n const startWidth = available > 0 ? Math.min(unbounded, available) : unbounded;\n\n return {\n width: startWidth,\n ratio,\n // jsdom reports clientWidth as 0, so a zero measure means \"no\n // constraint\" — the real clamp only applies in a browser.\n maxWidth: available > 0 ? available : Infinity,\n };\n }, []);\n\n // An image arrives with width/height at 0, which renders it at its natural\n // size — a 4000px photo blows past the editor and looks broken. Fit it to the\n // column once, on mount, keeping its ratio.\n //\n // Deliberately an effect and NOT an onLoad handler: the write below is a\n // ProseMirror transaction, and a consumer running with\n // `shouldRerenderOnTransaction: true` re-renders this view on every\n // transaction. In a browser that remounts the <img>, which fires `load`\n // again, which writes again — React bailed out with \"Maximum update depth\n // exceeded\". jsdom does not re-fire load on re-render, so no test caught it;\n // an effect guarded by a ref cannot re-enter regardless.\n const imageRef = useRef<HTMLImageElement>(null);\n const fittedSrcRef = useRef<string | null>(null);\n\n useEffect(() => {\n const img = imageRef.current;\n if (!img) return;\n // Author already chose a size, or this src was fitted before.\n if (sizeRef.current.width > 0 || fittedSrcRef.current === src) return;\n\n const fit = () => {\n const available = img.closest('.ProseMirror')?.clientWidth ?? 0;\n // Nothing to measure yet. Returning without claiming the src leaves\n // the door open for the load event below — an image inserted right\n // after an upload has no dimensions on the first pass, and a silent\n // bail here left it stuck at its natural size until the author\n // happened to drag the handle.\n if (!img.naturalWidth || !img.naturalHeight || available <= 0) return false;\n\n fittedSrcRef.current = src;\n // Never upscale: a small image keeps its own size rather than being\n // stretched across the column and going soft.\n const nextWidth = Math.min(img.naturalWidth, available);\n updateAttributes({\n width: nextWidth,\n height: Math.round(nextWidth / (img.naturalWidth / img.naturalHeight)),\n });\n\n return true;\n };\n\n // `complete` covers a cached file and a data URI, both ready before the\n // effect runs, which would never fire a load event here. It is also true\n // for a broken image, so a successful fit is what ends the attempt.\n if (img.complete && fit()) return;\n\n // Not `{ once: true }`: a decode can report zero dimensions on the first\n // event, and giving up after one try is what made a freshly uploaded\n // image render at full size.\n const onLoad = () => {\n if (fit()) img.removeEventListener('load', onLoad);\n };\n img.addEventListener('load', onLoad);\n return () => img.removeEventListener('load', onLoad);\n }, [src, updateAttributes]);\n\n const onPointerDown = useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n event.preventDefault();\n event.stopPropagation();\n const start = measure(event.currentTarget);\n dragRef.current = { startX: event.clientX, ...start };\n setDragging(true);\n\n const onMove = (moveEvent: PointerEvent) => {\n const drag = dragRef.current;\n if (!drag) return;\n resizeTo(drag.width + (moveEvent.clientX - drag.startX), drag.ratio, drag.maxWidth);\n };\n const onUp = () => {\n dragRef.current = null;\n setDragging(false);\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onUp);\n };\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onUp);\n },\n [measure, resizeTo],\n );\n\n // A pointer-only handle leaves the image unresizable without a mouse, which\n // role='button' promises but does not deliver. Arrow keys drive the same\n // clamped resize.\n const onKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n const step =\n event.key === 'ArrowRight'\n ? KEYBOARD_STEP\n : event.key === 'ArrowLeft'\n ? -KEYBOARD_STEP\n : 0;\n if (step === 0) return;\n\n event.preventDefault();\n const start = measure(event.currentTarget);\n resizeTo(start.width + step, start.ratio, start.maxWidth);\n },\n [measure, resizeTo],\n );\n\n const sizeStyle =\n width > 0\n ? { width, height: height > 0 ? height : undefined, maxWidth: '100%' }\n : undefined;\n\n return (\n <NodeViewWrapper\n data-slot='resizable-image'\n className='group relative inline-block max-w-full'>\n <img\n ref={imageRef}\n src={src}\n alt={alt}\n className='max-w-full rounded-md'\n style={sizeStyle}\n draggable={false}\n />\n <div\n role='button'\n tabIndex={0}\n aria-label={resizeLabel}\n title={resizeLabel}\n data-slot='resizable-image-handle'\n onPointerDown={onPointerDown}\n onKeyDown={onKeyDown}\n className={cn(\n 'border-primary absolute -right-1 -bottom-1 h-4 w-4 cursor-se-resize touch-none rounded-full border-2 bg-white transition-opacity',\n 'focus-visible:ring-ring/50 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:outline-none',\n dragging || selected ? 'opacity-100' : 'opacity-0 group-hover:opacity-100',\n )}\n />\n </NodeViewWrapper>\n );\n}\n\n/**\n * Builds an Image extension whose node view carries a resize handle.\n *\n * A factory rather than a component because ProseMirror — not React —\n * instantiates the node view, so there is no place to hand it props. Options\n * ride on the extension instead, and the view reads them off `extension.options`.\n */\nfunction createResizableImage(options: ResizableImageOptions) {\n // The type argument REPLACES the options type rather than widening it, so it\n // has to spell out the intersection: without it `addOptions` may only return\n // ImageOptions (rejecting resizeLabel), and with a bare\n // ResizableImageOptions the stock options a consumer still configures\n // (inline, allowBase64) disappear.\n return Image.extend<ImageOptions & ResizableImageOptions>({\n addOptions() {\n // `this.parent!()`, not `this.parent?.()`: the optional call widens\n // every inherited field to `| undefined`, which no longer satisfies\n // ImageOptions' required `inline`. Image always defines addOptions.\n return { ...this.parent!(), ...options };\n },\n // The size attributes belong to the extension, not to the consumer: the\n // stock Image extension keeps width/height too, but they default to null\n // and render as HTML attributes, which pins the image to a fixed size.\n //\n // A numeric default with `rendered: false` is what makes resizing work\n // at all — Tiptap v3 gates DOM emission on `rendered`, so the size stays\n // out of the markup and lives only in the document JSON, where a\n // serializer can read it. Without these declarations the schema drops\n // every updateAttributes({ width }) call and the handle does nothing.\n addAttributes() {\n return {\n ...this.parent?.(),\n width: { default: 0, rendered: false },\n height: { default: 0, rendered: false },\n };\n },\n addNodeView() {\n return ReactNodeViewRenderer(ResizableImageView);\n },\n });\n}\n\nexport { createResizableImage };\nexport type { ResizableImageOptions };\n","'use client';\n\nimport { useCallback, useMemo } from 'react';\nimport { useEditorState } from '@tiptap/react';\nimport { BubbleMenu } from '@tiptap/react/menus';\n// Type-only: Tiptap declares setLink/unsetLink by module augmentation, so they\n// exist on ChainedCommands only where the link extension is in scope. This pulls\n// in the declarations without adding the package to the bundle — StarterKit\n// supplies the runtime copy through the consumer's own extensions array.\nimport type {} from '@tiptap/extension-link';\nimport { ExternalLink, Pencil, Unlink } from 'lucide-react';\n\nimport { Button } from '@/components/ui/Button/button';\n\nimport type { Editor } from '@tiptap/react';\n\ninterface LinkBubbleMenuLabels {\n open: string;\n edit: string;\n remove: string;\n}\n\ninterface LinkBubbleMenuProps {\n editor: Editor | null;\n labels: LinkBubbleMenuLabels;\n /** Opens the consumer's link dialog, pre-filled with the current href. */\n onEdit: () => void;\n /**\n * Follows the link. Left to the consumer for the cases this package cannot\n * judge — routing instead of navigating, or confirming first.\n *\n * Defaults to opening a new tab, which is also what Ctrl/Cmd-click does, so\n * the author never loses unsaved work just by checking a URL.\n */\n onOpen?: (href: string) => void;\n}\n\ninterface LinkActionsProps {\n editor: Editor;\n labels: LinkBubbleMenuLabels;\n onEdit: () => void;\n onOpen?: (href: string) => void;\n}\n\n/**\n * A floating bar that appears when the cursor sits inside a link, offering to\n * open, edit or unlink it.\n *\n * It exists because an editor cannot let a plain click navigate: clicking is how\n * you place the cursor to fix a typo, so `openOnClick` stays false and this\n * gives the author a deliberate way out to the URL. Ctrl/Cmd-click is wired\n * separately, on the editor itself, for people who expect the shortcut.\n */\n/**\n * The bar itself, without any positioning.\n *\n * Split out from the floating wrapper so its behaviour is reachable in a test:\n * BubbleMenu positions through Floating UI, which needs layout APIs jsdom does\n * not implement, and mounting it in jsdom fails before any button exists.\n */\nfunction LinkActions({ editor, labels, onEdit, onOpen }: LinkActionsProps) {\n // useEditorState, never a bare editor.getAttributes() in the render body:\n // reading editor state during render re-subscribes on every render, each\n // subscription emits, and the editor's notification loop never settles —\n // React aborts with \"Maximum update depth exceeded\" once a consumer sets\n // shouldRerenderOnTransaction. This subscribes once and re-renders only when\n // the href actually changes.\n // `canOpen`, not just a truthy href: this reads the STORED attribute, so it\n // never sees the blanking Tiptap applies to a disallowed href when it\n // renders. Asking the editor whether it would accept the URL reuses the\n // Link extension's own `protocols` / `isAllowedUri` configuration, and stops\n // a document built outside the insert-link dialog from turning this button\n // into a `javascript:` sink. Disabled rather than silently inert, so the\n // author can tell the difference.\n const { href, canOpen } = useEditorState({\n editor,\n selector: ({ editor: current }) => {\n const value = (current.getAttributes('link').href as string | undefined) ?? '';\n return { href: value, canOpen: !!value && current.can().setLink({ href: value }) };\n },\n });\n\n return (\n <div\n data-slot='link-bubble-menu'\n className='bg-popover text-popover-foreground flex items-center gap-1 rounded-md border p-1 shadow-md'>\n <span className='text-muted-foreground max-w-[16rem] truncate px-2 text-xs'>\n {href}\n </span>\n <Button\n type='button'\n size='sm'\n variant='ghost'\n title={labels.open}\n aria-label={labels.open}\n disabled={!canOpen}\n onClick={() => {\n if (!canOpen) return;\n if (onOpen) {\n onOpen(href);\n return;\n }\n // A new tab by default, matching Ctrl/Cmd-click: checking\n // where a link points should never cost the author unsaved\n // work. noopener/noreferrer keeps the opened page from\n // reaching back through window.opener.\n window.open(href, '_blank', 'noopener,noreferrer');\n }}>\n <ExternalLink className='h-4 w-4' />\n </Button>\n <Button\n type='button'\n size='sm'\n variant='ghost'\n title={labels.edit}\n aria-label={labels.edit}\n onClick={onEdit}>\n <Pencil className='h-4 w-4' />\n </Button>\n <Button\n type='button'\n size='sm'\n variant='ghost'\n className='text-destructive'\n title={labels.remove}\n aria-label={labels.remove}\n // extendMarkRange first: the caret is somewhere inside the link,\n // and unsetLink alone would only clear the character range under\n // it, leaving the rest of the anchor behind.\n onClick={() => editor.chain().focus().extendMarkRange('link').unsetLink().run()}>\n <Unlink className='h-4 w-4' />\n </Button>\n </div>\n );\n}\n\n/**\n * A floating bar that appears when the caret sits inside a link, offering to\n * open, edit or unlink it.\n *\n * It exists because an editor cannot let a plain click navigate: clicking is how\n * you place the caret to fix a typo, so `openOnClick` stays false and this gives\n * the author a deliberate way out to the URL. Ctrl/Cmd-click is wired separately,\n * on the editor itself, for people who expect the shortcut.\n */\nfunction LinkBubbleMenu({ editor, labels, onEdit, onOpen }: LinkBubbleMenuProps) {\n // Both props below MUST be referentially stable. BubbleMenu re-runs its\n // plugin setup whenever they change, and each setup emits a transaction —\n // so a fresh inline function or object literal per render feeds the editor's\n // notification loop until React aborts with \"Maximum update depth exceeded\".\n // The hooks run before the null check so their order never varies.\n const shouldShow = useCallback(\n // Only while the caret is actually in a link — otherwise this bar would\n // compete with any other bubble menu the consumer adds.\n ({ editor: current }: { editor: Editor }) => current.isActive('link'),\n [],\n );\n const options = useMemo(() => ({ placement: 'bottom' as const, offset: 8 }), []);\n\n if (!editor) return null;\n\n return (\n <BubbleMenu editor={editor} shouldShow={shouldShow} options={options}>\n <LinkActions editor={editor} labels={labels} onEdit={onEdit} onOpen={onOpen} />\n </BubbleMenu>\n );\n}\n\nexport { LinkBubbleMenu, LinkActions };\nexport type { LinkBubbleMenuProps, LinkActionsProps, LinkBubbleMenuLabels };\n","'use client';\n\nimport { Check, ChevronDown } from 'lucide-react';\n\nimport type { Editor } from '@tiptap/react';\nimport type { ReactNode } from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/Button/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@/components/ui/DropdownMenu/dropdown-menu';\n\n/** One list style the consumer offers. */\ninterface ListOption {\n /** The Tiptap node this entry toggles, e.g. `bulletList`. */\n node: string;\n /** Already translated name. */\n label: string;\n icon: ReactNode;\n run: (editor: Editor) => void;\n}\n\ninterface ListMenuProps {\n editor: Editor | null;\n /** Already translated. Names the trigger for assistive tech. */\n triggerLabel: string;\n /** Shown on the trigger when no list style is active. */\n icon: ReactNode;\n options: ListOption[];\n}\n\n/**\n * Groups the list styles behind one trigger.\n *\n * A row of separate buttons costs three toolbar slots for choices that are\n * mutually exclusive; one trigger showing the active style reads faster and\n * leaves room for the rest of the toolbar. The trigger swaps to the active\n * style's icon so the current state is visible without opening the menu.\n */\nfunction ListMenu({ editor, triggerLabel, icon, options }: ListMenuProps) {\n const active = options.find((option) => editor?.isActive(option.node));\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type='button'\n size='sm'\n variant={active ? 'secondary' : 'ghost'}\n disabled={!editor}\n title={active ? active.label : triggerLabel}\n aria-label={active ? active.label : triggerLabel}\n data-slot='list-menu-trigger'>\n {active ? active.icon : icon}\n {/* Marks the trigger as a disclosure: without it the button\n looks like the other toolbar toggles and nothing suggests\n there are more styles behind it. */}\n <ChevronDown className='h-3 w-3 opacity-60' />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align='start'>\n {options.map((option) => {\n const isActive = editor?.isActive(option.node) ?? false;\n\n return (\n <DropdownMenuItem\n key={option.node}\n disabled={!editor}\n className='cursor-pointer'\n onSelect={() => editor && option.run(editor)}>\n {option.icon}\n <span className='flex-1'>{option.label}</span>\n {/* A tick rather than a highlighted row: these\n toggle, so the menu has to say which is on. Kept\n mounted at zero opacity so rows do not shift\n width as the active style changes. */}\n <Check\n aria-hidden='true'\n className={cn('h-4 w-4', isActive ? 'opacity-100' : 'opacity-0')}\n />\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport { ListMenu };\nexport type { ListMenuProps, ListOption };\n","'use client';\n\nimport { useCallback, useMemo, useState } from 'react';\nimport Highlight from '@tiptap/extension-highlight';\nimport { TableKit } from '@tiptap/extension-table';\nimport { useEditor, type Editor, type JSONContent } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\nimport {\n Bold,\n Heading2,\n Highlighter,\n ImagePlus,\n Italic,\n Link as LinkIcon,\n List,\n ListOrdered,\n Quote,\n Strikethrough,\n Table as TableIcon,\n Underline,\n} from 'lucide-react';\n\nimport { createResizableImage } from './resizable-image';\nimport { LinkBubbleMenu, type LinkBubbleMenuLabels } from './link-bubble-menu';\nimport { EDITOR_CONTENT_STYLE } from './rich-text-editor';\nimport { ListMenu } from './list-menu';\nimport { TableMenu, type TableMenuLabels } from './table-menu';\n\nimport type { ReactNode } from 'react';\nimport type { EditorOptions } from '@tiptap/react';\nimport type { ToolbarItem } from './rich-text-toolbar';\n\n/**\n * Whatever `useEditor` accepts in its `extensions` array.\n *\n * Derived from Tiptap's own option rather than imported as AnyExtension: the\n * name resolves to a structurally different declaration depending on which copy\n * of @tiptap/core is in scope, and the two do not assign to each other.\n */\ntype EditorExtension = EditorOptions['extensions'][number];\n\n/** Every string the built-in toolbar and menus need. All already translated. */\ninterface RichTextEditorLabels {\n /** Names the editable area for assistive tech. Required — it has no visible label. */\n editor: string;\n bold: string;\n italic: string;\n heading: string;\n underline: string;\n strikethrough: string;\n quote: string;\n insertLink: string;\n insertImage: string;\n resizeImage: string;\n lists: { trigger: string; bullet: string; ordered: string };\n /** The floating bar shown while the caret sits inside a link. */\n link: LinkBubbleMenuLabels;\n table: TableMenuLabels;\n highlight: string;\n}\n\ninterface UseRichTextEditorOptions {\n labels: RichTextEditorLabels;\n /** Fires on every document change, with the current ProseMirror JSON. */\n onUpdate?: (doc: JSONContent) => void;\n /** Initial document. */\n content?: JSONContent | string;\n /** Opens the consumer's link dialog. Wire the toolbar's link button to it. */\n onInsertLink?: () => void;\n /** Opens the consumer's image dialog. */\n onInsertImage?: () => void;\n /**\n * Marks and nodes this product's document contract requires — a brand font,\n * a colour palette, anything a server-side whitelist validates. They are\n * appended to the built-in set rather than replacing it.\n */\n extraExtensions?: EditorExtension[];\n /**\n * Extra toolbar entries, and where they go. `after` names a built-in id\n * (`heading`, `highlight`, `strike`, `image`…); omit it to append at the end.\n */\n extraToolbar?: { after?: string; items: ToolbarItem[] }[];\n /**\n * Replaces a built-in entry, keyed by its id.\n *\n * For when a product needs a richer version of something the preset already\n * provides — swapping the single highlight button for a palette of shades,\n * say. Replacing rather than adding keeps the toolbar from carrying both.\n */\n replaceToolbar?: Record<string, ToolbarItem>;\n /** Merged on top of the built-in content styles. */\n contentClassName?: string;\n /** Allows data: URIs in images. Off by default: uploads belong in storage. */\n allowBase64Images?: boolean;\n /**\n * Merged into the editor's `editorProps`. For behaviour only a product can\n * define — clamping pasted tables to a contract's row limit, say.\n *\n * `attributes` and `handleClick` are set by the hook and are not overridable:\n * they carry the accessible name and the link shortcut, which are the\n * defaults consumers were getting wrong by hand.\n */\n editorProps?: Omit<NonNullable<EditorOptions['editorProps']>, 'attributes' | 'handleClick'>;\n}\n\ninterface UseRichTextEditorResult {\n editor: Editor | null;\n /**\n * The floating link bar, ready to render beside `<RichTextEditor />`.\n *\n * Returned as an element rather than left to the consumer because it is easy\n * to forget, and an editor without it gives the author no way to reach or\n * remove a link they have already inserted.\n */\n linkMenu: ReactNode;\n /** Ready for `<RichTextEditor items={...} />`. */\n toolbar: ToolbarItem[];\n /** True when the caret has no selection, so a new link needs its own text. */\n linkNeedsText: boolean;\n /** Reads the caret's current href — pre-fill the dialog with it. */\n currentLinkHref: () => string;\n /** Applies a link, inserting `text` when there is no selection to wrap. */\n applyLink: (href: string, text?: string) => void;\n}\n\n/**\n * Builds a configured Tiptap editor and its toolbar.\n *\n * Everything a rich text editor needs to behave correctly is set up here —\n * Ctrl/Cmd-click on links, the accessible name for the editable area, the\n * repaint-on-transaction the toolbar's pressed state depends on, the content\n * styles — so a consumer cannot end up with a subtly different editor by\n * forgetting one of them.\n *\n * What stays with the consumer is what only it can know: the marks its document\n * contract allows, and the copy. Both arrive as options.\n */\nfunction useRichTextEditor({\n labels,\n onUpdate,\n content,\n onInsertLink,\n onInsertImage,\n extraExtensions = [],\n extraToolbar = [],\n replaceToolbar,\n contentClassName,\n allowBase64Images = false,\n editorProps,\n}: UseRichTextEditorOptions): UseRichTextEditorResult {\n // Tracked here rather than by the consumer because it is derived from editor\n // state at the moment the dialog opens, which the consumer would otherwise\n // have to reach into the editor for.\n const [linkNeedsText, setLinkNeedsText] = useState(false);\n\n const editor = useEditor({\n extensions: [\n // openOnClick false: a plain click has to place the caret so the\n // author can edit link text. Left at its default, Tiptap navigates\n // the current tab and throws the author out of the editor.\n StarterKit.configure({ link: { openOnClick: false } }),\n Highlight,\n TableKit.configure({ table: { resizable: true } }),\n createResizableImage({ resizeLabel: labels.resizeImage }).configure({\n inline: false,\n allowBase64: allowBase64Images,\n }),\n ...extraExtensions,\n ],\n content,\n immediatelyRender: false,\n // Required for the toolbar's pressed state and the image node view to\n // repaint as the selection and attributes change.\n shouldRerenderOnTransaction: true,\n editorProps: {\n ...editorProps,\n attributes: {\n // ProseMirror's editable div needs its own accessible name: a\n // visible <Label> beside it is decoration, and a screen reader\n // would announce an unnamed box.\n role: 'textbox',\n 'aria-label': labels.editor,\n class: contentClassName\n ? `${EDITOR_CONTENT_STYLE} ${contentClassName}`\n : EDITOR_CONTENT_STYLE,\n },\n // Ctrl/Cmd-click opens the link in a new tab and leaves the author\n // where they were: the shortcut is a deliberate gesture, and keeping\n // the editor open means no unsaved work is at risk. A plain click\n // falls through to ProseMirror and just moves the caret.\n handleClick(_view, _pos, event) {\n if (!event.ctrlKey && !event.metaKey) return false;\n\n const href = (event.target as HTMLElement)?.closest('a')?.getAttribute('href');\n if (!href) return false;\n\n event.preventDefault();\n // noopener/noreferrer: the opened page must not get a handle on\n // the editor's window through window.opener.\n window.open(href, '_blank', 'noopener,noreferrer');\n return true;\n },\n },\n onUpdate: onUpdate ? ({ editor: current }) => onUpdate(current.getJSON()) : undefined,\n });\n\n const currentLinkHref = useCallback(\n () => (editor?.getAttributes('link').href as string | undefined) ?? '',\n [editor],\n );\n\n const openLink = useCallback(() => {\n if (editor) {\n const { from, to } = editor.state.selection;\n setLinkNeedsText(from === to && !editor.isActive('link'));\n }\n onInsertLink?.();\n }, [editor, onInsertLink]);\n\n const applyLink = useCallback(\n (href: string, text?: string) => {\n if (!editor) return;\n const url = href.trim();\n\n // Both branches below have to answer the same question: is this a\n // URL the document is allowed to point at? `setLink` refuses an\n // unsafe protocol (javascript:, data:, …) on its own, but the\n // no-selection branch builds the mark by hand and never reaches\n // that check — so an unsafe href used to land in the document JSON.\n // It stayed invisible in the editor, because Tiptap blanks a\n // disallowed href when it renders, and was handed to the consumer\n // intact through `onUpdate`.\n //\n // Asking the editor up front is what keeps the two paths honest,\n // and it reuses whatever `protocols` / `isAllowedUri` the consumer\n // configured on the Link extension rather than a second allowlist\n // of our own. An empty url is left to fall through: that is how a\n // link is removed.\n if (url && !editor.can().setLink({ href: url })) return;\n\n if (linkNeedsText) {\n // Nothing was selected, so there is no range to mark: insert the\n // text carrying the link in one transaction.\n if (url && text?.trim()) {\n editor\n .chain()\n .focus()\n .insertContent({\n type: 'text',\n text: text.trim(),\n marks: [{ type: 'link', attrs: { href: url } }],\n })\n .run();\n }\n return;\n }\n\n // extendMarkRange first: the caret may sit inside a link without a\n // selection, and without it only the character under it would change.\n if (url) editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run();\n else editor.chain().focus().extendMarkRange('link').unsetLink().run();\n },\n [editor, linkNeedsText],\n );\n\n const toolbar = useMemo(() => {\n const builtIn: ToolbarItem[] = [\n {\n kind: 'button',\n id: 'bold',\n icon: <Bold className='h-4 w-4' />,\n label: labels.bold,\n active: { name: 'bold' },\n run: (e) => e.chain().focus().toggleBold().run(),\n },\n {\n kind: 'button',\n id: 'italic',\n icon: <Italic className='h-4 w-4' />,\n label: labels.italic,\n active: { name: 'italic' },\n run: (e) => e.chain().focus().toggleItalic().run(),\n },\n {\n kind: 'button',\n id: 'heading',\n icon: <Heading2 className='h-4 w-4' />,\n label: labels.heading,\n active: { name: 'heading', attrs: { level: 2 } },\n run: (e) => e.chain().focus().toggleHeading({ level: 2 }).run(),\n },\n { kind: 'separator' },\n {\n kind: 'button',\n id: 'highlight',\n icon: <Highlighter className='h-4 w-4' />,\n label: labels.highlight,\n active: { name: 'highlight' },\n run: (e) => e.chain().focus().toggleHighlight().run(),\n },\n {\n kind: 'button',\n id: 'underline',\n icon: <Underline className='h-4 w-4' />,\n label: labels.underline,\n active: { name: 'underline' },\n run: (e) => e.chain().focus().toggleMark('underline').run(),\n },\n {\n kind: 'button',\n id: 'strike',\n icon: <Strikethrough className='h-4 w-4' />,\n label: labels.strikethrough,\n active: { name: 'strike' },\n run: (e) => e.chain().focus().toggleMark('strike').run(),\n },\n { kind: 'separator' },\n {\n kind: 'button',\n id: 'quote',\n icon: <Quote className='h-4 w-4' />,\n label: labels.quote,\n active: { name: 'blockquote' },\n run: (e) => e.chain().focus().toggleBlockquote().run(),\n },\n {\n kind: 'custom',\n id: 'lists',\n render: (current) => (\n <ListMenu\n editor={current}\n triggerLabel={labels.lists.trigger}\n icon={<List className='h-4 w-4' />}\n options={[\n {\n node: 'bulletList',\n label: labels.lists.bullet,\n icon: <List className='h-4 w-4' />,\n run: (e) => e.chain().focus().toggleBulletList().run(),\n },\n {\n node: 'orderedList',\n label: labels.lists.ordered,\n icon: <ListOrdered className='h-4 w-4' />,\n run: (e) => e.chain().focus().toggleOrderedList().run(),\n },\n ]}\n />\n ),\n },\n { kind: 'separator' },\n {\n kind: 'button',\n id: 'link',\n icon: <LinkIcon className='h-4 w-4' />,\n label: labels.insertLink,\n active: { name: 'link' },\n run: () => openLink(),\n },\n {\n kind: 'button',\n id: 'image',\n icon: <ImagePlus className='h-4 w-4' />,\n label: labels.insertImage,\n // No `active`: this opens a dialog, it is never a pressed state.\n run: () => onInsertImage?.(),\n },\n {\n kind: 'custom',\n id: 'table',\n render: (current) => (\n <TableMenu\n editor={current}\n icon={<TableIcon className='h-4 w-4' />}\n labels={labels.table}\n />\n ),\n },\n ];\n\n // Swap replaced entries first, so `after` anchors still resolve against\n // the same ids afterwards.\n let items = replaceToolbar\n ? builtIn.map((item) =>\n item.kind !== 'separator' && replaceToolbar[item.id]\n ? replaceToolbar[item.id]\n : item,\n )\n : builtIn;\n const appended: ToolbarItem[] = [];\n\n for (const group of extraToolbar) {\n if (!group.after) {\n appended.push(...group.items);\n continue;\n }\n const at = items.findIndex(\n (item) => item.kind !== 'separator' && item.id === group.after,\n );\n if (at === -1) {\n appended.push(...group.items);\n continue;\n }\n items = [...items.slice(0, at + 1), ...group.items, ...items.slice(at + 1)];\n }\n\n return [...items, ...appended];\n }, [labels, extraToolbar, replaceToolbar, onInsertImage, openLink]);\n\n const linkMenu = <LinkBubbleMenu editor={editor} labels={labels.link} onEdit={openLink} />;\n\n return { editor, toolbar, linkMenu, linkNeedsText, currentLinkHref, applyLink };\n}\n\nexport { useRichTextEditor };\nexport type { UseRichTextEditorOptions, UseRichTextEditorResult, RichTextEditorLabels };\n","'use client';\n\nimport type { Editor } from '@tiptap/react';\nimport type { ReactNode } from 'react';\n\nimport { Ban } from 'lucide-react';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/Button/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuTrigger,\n} from '@/components/ui/DropdownMenu/dropdown-menu';\n\n/**\n * One entry in the palette.\n *\n * `mark` is a mark name, not a colour value: a consumer's document contract\n * decides which marks exist, and a palette of named marks costs nothing to\n * validate server-side — unlike a mark carrying an arbitrary colour, which would\n * change the shape of every stored span.\n */\ninterface ColorSwatch {\n /** The Tiptap mark this swatch toggles, e.g. `colorPrimary`. */\n mark: string;\n /** Already translated name, used as the swatch's accessible label. */\n label: string;\n /** CSS colour for the swatch preview only. */\n preview: string;\n}\n\ninterface ColorMenuLabels {\n trigger: string;\n /** Heading above the swatches. */\n heading: string;\n /** Clears whichever colour mark is applied. */\n clear: string;\n}\n\ninterface ColorMenuProps {\n editor: Editor | null;\n labels: ColorMenuLabels;\n icon: ReactNode;\n swatches: ColorSwatch[];\n}\n\n/**\n * A palette dropdown that toggles one mark at a time.\n *\n * Deliberately not the design system's `ColorPicker`: a free picker offers\n * millions of values, and an editor whose authors can pick any colour produces\n * articles that no longer look like one publication. A short list of brand\n * shades is the constraint that keeps them consistent.\n */\nfunction ColorMenu({ editor, labels, icon, swatches }: ColorMenuProps) {\n const active = swatches.find((swatch) => editor?.isActive(swatch.mark));\n\n function apply(mark: string) {\n if (!editor) return;\n\n // Colours are mutually exclusive, so every other one is cleared first.\n // Two nested colour spans would leave the outer one dead weight, and the\n // author would have no way to tell which is winning.\n const chain = editor.chain().focus();\n for (const swatch of swatches) chain.unsetMark(swatch.mark);\n if (mark) chain.setMark(mark);\n chain.run();\n }\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type='button'\n size='sm'\n variant={active ? 'secondary' : 'ghost'}\n disabled={!editor}\n title={labels.trigger}\n aria-label={labels.trigger}\n data-slot='color-menu-trigger'>\n {icon}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align='start' className='w-auto'>\n {/* role='group' rather than menuitems: these are swatches, and a\n grid of buttons is not a menu in ARIA terms. */}\n <div\n role='group'\n aria-label={labels.heading}\n className='flex items-center gap-1.5 px-1.5 py-1'>\n {swatches.map((swatch) => (\n <button\n key={swatch.mark}\n type='button'\n aria-label={swatch.label}\n aria-pressed={editor?.isActive(swatch.mark) ?? false}\n title={swatch.label}\n style={{ backgroundColor: swatch.preview }}\n className={cn(\n 'h-7 w-7 cursor-pointer rounded-full border transition-transform',\n 'focus-visible:ring-ring/50 focus-visible:ring-2 focus-visible:outline-none',\n editor?.isActive(swatch.mark)\n ? 'border-primary scale-110 border-2'\n : 'border-border/60 hover:scale-110',\n )}\n onClick={() => apply(swatch.mark)}\n />\n ))}\n {/* Separated from the swatches: it is the absence of a colour,\n not one more choice. Without it an applied colour could\n only be undone by retyping the text. */}\n <span aria-hidden='true' className='bg-border mx-0.5 h-5 w-px' />\n <button\n type='button'\n aria-label={labels.clear}\n title={labels.clear}\n disabled={!active}\n className={cn(\n 'text-muted-foreground flex h-7 w-7 cursor-pointer items-center justify-center rounded-full',\n 'focus-visible:ring-ring/50 focus-visible:ring-2 focus-visible:outline-none',\n 'hover:text-foreground disabled:cursor-default disabled:opacity-40',\n )}\n onClick={() => apply('')}>\n <Ban className='h-4 w-4' />\n </button>\n </div>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport { ColorMenu };\nexport type { ColorMenuProps, ColorMenuLabels, ColorSwatch };\n","import { useId } from 'react';\n\nimport { Button } from '@/components/ui/Button/button';\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/Dialog/dialog';\nimport { Input } from '@/components/ui/Input/input';\nimport { Label } from '@/components/ui/Label/label';\n\ninterface InsertLinkDialogLabels {\n title: string;\n urlLabel: string;\n urlPlaceholder: string;\n /** Explains that clearing the field removes an existing link. */\n hint: string;\n /** Field for the visible text, shown only when there is no selection to wrap. */\n textLabel: string;\n textPlaceholder: string;\n cancel: string;\n apply: string;\n}\n\ninterface InsertLinkDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n labels: InsertLinkDialogLabels;\n url: string;\n onUrlChange: (url: string) => void;\n /**\n * The visible text for a brand-new link. Pass these three together with\n * `needsText` when the editor has no selection to turn into a link — without\n * them the dialog can only re-point an existing one.\n */\n text?: string;\n onTextChange?: (text: string) => void;\n /**\n * True when there is nothing selected, so the link needs its own text.\n * Reveals the text field and requires it before applying.\n */\n needsText?: boolean;\n onApply: () => void;\n onCancel?: () => void;\n}\n\n/**\n * A controlled form for inserting or editing a link.\n *\n * Clearing the URL and applying is how a link is removed — the consumer decides\n * what that means for its document, so this dialog only reports the values.\n */\nfunction InsertLinkDialog({\n open,\n onOpenChange,\n labels,\n url,\n onUrlChange,\n text = '',\n onTextChange,\n needsText = false,\n onApply,\n onCancel,\n}: InsertLinkDialogProps) {\n const urlId = useId();\n const textId = useId();\n\n // With a selection, an empty URL is meaningful: it unsets the link. Without\n // one there is nothing to unset, so both fields have to carry a value or\n // applying would insert an empty anchor.\n const canApply = needsText ? Boolean(url.trim()) && Boolean(text.trim()) : true;\n\n function submitOnEnter(event: React.KeyboardEvent<HTMLInputElement>) {\n if (event.key === 'Enter' && canApply) {\n event.preventDefault();\n onApply();\n }\n }\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className='px-4 py-2' data-slot='insert-link-dialog'>\n <DialogHeader>\n <DialogTitle>{labels.title}</DialogTitle>\n </DialogHeader>\n <div className='mt-4 flex flex-col gap-3'>\n {needsText && onTextChange && (\n <div className='flex flex-col gap-1'>\n <Label htmlFor={textId}>{labels.textLabel}</Label>\n <Input\n id={textId}\n placeholder={labels.textPlaceholder}\n value={text}\n onChange={(event) => onTextChange(event.target.value)}\n onKeyDown={submitOnEnter}\n />\n </div>\n )}\n <div className='flex flex-col gap-1'>\n <Label htmlFor={urlId}>{labels.urlLabel}</Label>\n <Input\n id={urlId}\n placeholder={labels.urlPlaceholder}\n value={url}\n onChange={(event) => onUrlChange(event.target.value)}\n onKeyDown={submitOnEnter}\n />\n {!needsText && (\n <p className='text-muted-foreground text-xs'>{labels.hint}</p>\n )}\n </div>\n </div>\n <DialogFooter>\n <Button\n type='button'\n variant='outline'\n onClick={() => {\n if (onCancel) onCancel();\n else onOpenChange(false);\n }}>\n {labels.cancel}\n </Button>\n <Button type='button' onClick={onApply} disabled={!canApply}>\n {labels.apply}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport { InsertLinkDialog };\nexport type { InsertLinkDialogProps, InsertLinkDialogLabels };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/components/ui/Label/label.tsx","../src/components/ui/Button/button.tsx","../src/components/compounds/RichTextEditor/rich-text-toolbar.tsx","../src/components/compounds/RichTextEditor/rich-text-editor.tsx","../src/components/ui/DropdownMenu/dropdown-menu.tsx","../src/components/compounds/RichTextEditor/table-menu.tsx","../src/tokens/animation.ts","../src/components/ui/Dialog/dialog.tsx","../src/components/ui/Dropzone/dropzone.tsx","../src/components/ui/Input/input.tsx","../src/components/compounds/RichTextEditor/insert-image-dialog.tsx","../src/components/compounds/RichTextEditor/resizable-image.tsx","../src/components/compounds/RichTextEditor/link-bubble-menu.tsx","../src/components/compounds/RichTextEditor/list-menu.tsx","../src/components/compounds/RichTextEditor/use-rich-text-editor.tsx","../src/components/compounds/RichTextEditor/color-menu.tsx","../src/components/compounds/RichTextEditor/insert-link-dialog.tsx"],"names":["twMerge","clsx","jsx","LabelPrimitive","cva","Slot","jsxs","LoaderCircle","useId","EditorContent","DropdownMenuPrimitive","useState","createContext","DialogPrimitive","useContext","AnimatePresence","motion","XIcon","useDropzone","UploadIcon","Trash2","useRef","useCallback","useEffect","NodeViewWrapper","Image","ReactNodeViewRenderer","useEditorState","ExternalLink","Pencil","Unlink","useMemo","BubbleMenu","ChevronDown","Check","useEditor","StarterKit","Highlight","TableKit","Bold","Italic","Heading2","Highlighter","Underline","Strikethrough","Quote","List","ListOrdered","LinkIcon","ImagePlus","TableIcon","Ban"],"mappings":"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","file":"editor.cjs","sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { type ComponentProps } from 'react';\nimport { Label as LabelPrimitive } from 'radix-ui';\n\nimport { cn } from '@/lib/utils';\n\nfunction Label({ className, ...props }: ComponentProps<typeof LabelPrimitive.Root>) {\n return (\n <LabelPrimitive.Root\n data-slot='label'\n className={cn(\n 'text-foreground text-sm leading-6 font-medium transition-colors select-none',\n 'group-has-disabled/field:cursor-not-allowed group-has-disabled/field:opacity-50',\n 'peer-disabled:cursor-not-allowed peer-disabled:opacity-50',\n 'aria-invalid:text-destructive dark:aria-invalid:text-destructive/90',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport { Label };\n","import { type ComponentProps, type MouseEvent } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { Slot } from 'radix-ui';\nimport {LoaderCircle} from 'lucide-react'\n\nimport { cn } from '@/lib/utils';\n\nconst buttonVariants = cva(\n 'group/button inline-flex shrink-0 items-center justify-center gap-2 rounded-lg border border-transparent bg-clip-padding text-sm font-semibold whitespace-nowrap transition-all duration-150 outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 data-[loading]:cursor-not-allowed data-[loading]:opacity-80 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0',\n {\n variants: {\n variant: {\n primary:\n 'cursor-pointer bg-primary text-primary-foreground hover:bg-primary/80 focus-visible:ring-primary/30',\n secondary:\n 'cursor-pointer bg-secondary text-secondary-foreground hover:bg-[var(--color-orange-700)] focus-visible:ring-secondary/30',\n cancel: 'cursor-pointer bg-destructive text-secondary-foreground hover:bg-[var(--color-red-600)] focus-visible:ring-destructive/30',\n outline:\n 'border border-foreground/50 bg-transparent text-muted-foreground hover:bg-foreground/50 hover:text-white',\n ghost: 'cursor-pointer bg-transparent text-muted-foreground hover:bg-foreground/10 hover:text-primary focus-visible:ring-ring/30 border-none',\n cancelGhost:\n 'cursor-pointer bg-destructive/10 text-red-600 hover:bg-destructive/15 hover:text-red-600 focus-visible:ring-ring/30',\n },\n size: {\n sm: 'h-8 px-3 text-xs',\n md: 'h-9 px-4 text-sm',\n lg: 'h-10 px-6 text-sm',\n 'icon-sm': 'size-8 rounded-full p-0',\n },\n },\n defaultVariants: {\n variant: 'primary',\n size: 'md',\n },\n },\n);\n\n/**\n * Interactive button with 6 variants and 4 sizes. Use `asChild` to render as any element via Radix Slot.\n * When `isLoading` is true, a spinner is shown and clicks are blocked while keeping the not-allowed cursor.\n */\nfunction Button({\n className,\n variant = 'primary',\n size = 'md',\n asChild = false,\n isLoading = false,\n children,\n onClick,\n ...props\n}: ComponentProps<'button'> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n isLoading?: boolean;\n }) {\n const Comp = asChild ? Slot.Root : 'button';\n\n function handleClick(e: MouseEvent<HTMLButtonElement>) {\n if (isLoading) {\n e.preventDefault();\n return;\n }\n onClick?.(e);\n }\n\n return (\n <Comp\n data-slot='button'\n data-variant={variant}\n data-size={size}\n data-loading={isLoading || undefined}\n aria-busy={isLoading || undefined}\n className={cn(buttonVariants({ variant, size, className }))}\n onClick={handleClick}\n {...props}>\n {isLoading && <LoaderCircle size={16} className='animate-spin' aria-hidden='true' />}\n {children}\n </Comp>\n );\n}\n\nexport { Button, buttonVariants };\n","import type { Editor } from '@tiptap/react';\nimport type { ReactNode } from 'react';\n\nimport { Button } from '@/components/ui/Button/button';\n\n/**\n * A toolbar entry is data, never a mark.\n *\n * An editor's marks are ProseMirror extensions — code with serialization and\n * parsing rules — so they belong to whoever owns the document contract, not to\n * this package. A consumer declares what its buttons do here and keeps its own\n * custom marks; the toolbar only asks the editor whether something is active\n * and runs the callback it was handed.\n */\ntype ToolbarItem =\n | { kind: 'separator' }\n | {\n kind: 'button';\n id: string;\n /**\n * A node, not an icon name: keeps this package off any icon library\n * and lets a button pass bare text (a font's own name, say) instead.\n */\n icon: ReactNode;\n /** Already translated. Names the button for both `title` and `aria-label`. */\n label: string;\n /**\n * What to ask the editor for the pressed state. Omit for actions that\n * only open a dialog and are never \"on\" — announcing those as a\n * permanently-off toggle misleads a screen reader.\n */\n active?: { name: string; attrs?: Record<string, unknown> };\n run: (editor: Editor) => void;\n }\n /** Escape hatch for entries that own state or render their own popover. */\n | { kind: 'custom'; id: string; render: (editor: Editor | null) => ReactNode };\n\ninterface RichTextToolbarProps {\n /** Null while the editor mounts; every button disables itself until then. */\n editor: Editor | null;\n items: ToolbarItem[];\n}\n\n/** Renders a declarative toolbar for a Tiptap editor. */\nfunction RichTextToolbar({ editor, items }: RichTextToolbarProps) {\n return (\n <div\n role='toolbar'\n data-slot='rich-text-toolbar'\n className='flex items-center gap-1 rounded-t-md border border-b-0 p-1'>\n {items.map((item, index) => {\n if (item.kind === 'separator') {\n // Index is a stable key here: `items` is a static\n // declaration, not a reorderable list.\n return (\n <div\n key={`separator-${index}`}\n data-slot='rich-text-toolbar-separator'\n aria-hidden='true'\n className='bg-border mx-1 h-5 w-px'\n />\n );\n }\n\n if (item.kind === 'custom') {\n return <span key={item.id}>{item.render(editor)}</span>;\n }\n\n const active = item.active\n ? (editor?.isActive(item.active.name, item.active.attrs) ?? false)\n : false;\n\n return (\n <Button\n key={item.id}\n type='button'\n size='sm'\n variant={active ? 'secondary' : 'ghost'}\n disabled={!editor}\n title={item.label}\n aria-label={item.label}\n aria-pressed={item.active ? active : undefined}\n data-slot='rich-text-toolbar-button'\n onClick={() => editor && item.run(editor)}>\n {item.icon}\n </Button>\n );\n })}\n </div>\n );\n}\n\nexport { RichTextToolbar };\nexport type { RichTextToolbarProps, ToolbarItem };\n","'use client';\n\nimport { useId } from 'react';\nimport { EditorContent, type Editor } from '@tiptap/react';\nimport type { ReactNode } from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { Label } from '@/components/ui/Label/label';\nimport { RichTextToolbar, type ToolbarItem } from './rich-text-toolbar';\n\n/**\n * Base content styles for the editable area, exported so a consumer can pass\n * them to `useEditor({ editorProps: { attributes: { class } } })` — ProseMirror\n * needs that class at construction time, before this component renders.\n *\n * Compose rather than replace: `cn(EDITOR_CONTENT_STYLE, 'my-overrides')`.\n */\nconst EDITOR_CONTENT_STYLE = cn(\n 'min-h-[220px] px-3 py-2 text-sm outline-none',\n '[&_h2]:text-lg [&_h2]:font-semibold',\n '[&_ol]:my-4 [&_ol]:list-decimal [&_ol]:pl-5 [&_ul]:my-4 [&_ul]:list-disc [&_ul]:pl-5',\n '[&_blockquote]:border-secondary [&_blockquote]:my-4 [&_blockquote]:ml-4 [&_blockquote]:border-l-4 [&_blockquote]:pl-2',\n '[&_a]:text-primary [&_a]:underline',\n // last-of-type, not last-child: prosemirror-tables appends its\n // .column-resize-handle widget inside the hovered cell, which makes the\n // cell's <p> stop matching :last-child and springs mb-4 back on — the row\n // grows 16px on hover. The handle is absolutely positioned but still counts\n // as a child for structural selectors.\n '[&_p]:mb-4 [&_p]:min-h-[1.25em] [&_p:last-of-type]:mb-0',\n // Paragraphs inside a quote sit closer together than body copy. Every Enter\n // inside a blockquote opens a new <p>, and at the body's mb-4 the lines of a\n // single quote read as separate paragraphs. Declared after the rule above so\n // it wins on equal specificity.\n '[&_blockquote_p]:mb-1 [&_blockquote_p:last-of-type]:mb-0',\n '[&_img]:my-2 [&_img]:max-w-full [&_img]:rounded-md',\n '[&_table]:my-3 [&_table]:w-full [&_table]:table-fixed [&_table]:border-collapse',\n '[&_td]:relative [&_td]:border [&_td]:px-2 [&_td]:py-1 [&_td]:align-top',\n '[&_th]:bg-muted [&_th]:relative [&_th]:border [&_th]:px-2 [&_th]:py-1 [&_th]:text-left [&_th]:font-semibold',\n '[&_.selectedCell]:bg-primary/10',\n // prosemirror-tables renders one handle PER ROW, so the column reads as a\n // single bar down the table. At full primary it looked like the table had\n // broken rather than like something to grab — hence the muted tint and the\n // wider, border-straddling hit area (matches upstream's 4px).\n '[&_.column-resize-handle]:bg-primary/40 [&_.column-resize-handle]:pointer-events-none [&_.column-resize-handle]:absolute [&_.column-resize-handle]:top-0 [&_.column-resize-handle]:-right-0.5 [&_.column-resize-handle]:bottom-0 [&_.column-resize-handle]:z-20 [&_.column-resize-handle]:w-1',\n '[&.resize-cursor]:cursor-col-resize',\n // Selected-node outline, scoped away from images.\n //\n // ProseMirror marks whichever node is selected, and this ring is the only\n // cue for most of them — but an image already announces its selection with a\n // visible resize handle, so the extra box only framed the picture.\n //\n // Excluded via `.node-image`, the class Tiptap puts on the wrapper it\n // generates for a node view (`div.react-renderer.node-<name>`). That wrapper,\n // not the NodeViewWrapper inside it, is what receives\n // ProseMirror-selectednode — so a data-slot on our own element sits one level\n // too deep to match.\n '[&_.ProseMirror-selectednode:not(.node-image)]:outline-primary [&_.ProseMirror-selectednode:not(.node-image)]:outline-2 [&_.ProseMirror-selectednode:not(.node-image)]:outline-offset-2 [&_.ProseMirror-selectednode:not(.node-image)]:outline',\n);\n\ninterface RichTextEditorProps {\n /** Null while the editor mounts. Build it with Tiptap's `useEditor`. */\n editor: Editor | null;\n items: ToolbarItem[];\n /**\n * Already translated. Omit to render no visible label.\n *\n * Note that a visible label does NOT name the editable area on its own:\n * ProseMirror renders that as role='textbox', and EditorContent's props land\n * on a wrapper div rather than on the editable node. Give the editor its own\n * name where you construct it:\n *\n * ```ts\n * useEditor({\n * editorProps: { attributes: { class: EDITOR_CONTENT_STYLE, 'aria-label': t('body') } },\n * })\n * ```\n */\n label?: string;\n /** Already translated message. Drives the destructive border and the hint. */\n error?: string;\n /**\n * Slot under the editor for product-specific actions, so the editor itself\n * stays free of any one product's features.\n */\n footer?: ReactNode;\n className?: string;\n}\n\n/** Chrome for a Tiptap editor: a declarative toolbar, the editable area, and an error slot. */\nfunction RichTextEditor({ editor, items, label, error, footer, className }: RichTextEditorProps) {\n const errorId = useId();\n\n return (\n <div data-slot='rich-text-editor' className={cn('flex flex-col gap-1', className)}>\n {label && <Label>{label}</Label>}\n <RichTextToolbar editor={editor} items={items} />\n <EditorContent\n editor={editor}\n aria-invalid={!!error}\n aria-errormessage={error ? errorId : undefined}\n onClick={() => editor?.commands.focus()}\n className={cn(\n 'rounded-t-none rounded-b-md border shadow-xs',\n 'focus-within:border-ring focus-within:ring-ring/30 focus-within:ring-3',\n error && 'border-destructive',\n )}\n />\n {/* role='alert' rather than a plain span: aria-errormessage only\n counts if the referenced node is exposed to assistive tech, and\n an alert also announces the message when it appears. */}\n {error && (\n <span id={errorId} role='alert' className='text-destructive text-xs'>\n {error}\n </span>\n )}\n {footer}\n </div>\n );\n}\n\nexport { RichTextEditor, EDITOR_CONTENT_STYLE };\nexport type { RichTextEditorProps };\n","import { type ComponentProps } from 'react';\nimport { DropdownMenu as DropdownMenuPrimitive } from 'radix-ui';\n\nimport { cn } from '@/lib/utils';\nimport { CheckIcon, ChevronRightIcon } from 'lucide-react';\n\nfunction DropdownMenu({ ...props }: ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n return <DropdownMenuPrimitive.Root {...props} />;\n}\n\nfunction DropdownMenuPortal({\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Portal>) {\n return <DropdownMenuPrimitive.Portal {...props} />;\n}\n\nfunction DropdownMenuTrigger({\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n return <DropdownMenuPrimitive.Trigger data-slot='dropdown-menu-trigger' {...props} />;\n}\n\nfunction DropdownMenuContent({\n className,\n align = 'start',\n sideOffset = 4,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n data-slot='dropdown-menu-content'\n sideOffset={sideOffset}\n align={align}\n className={cn(\n 'bg-popover text-popover-foreground ring-foreground/5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:ring-foreground/10 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-48 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-3xl p-1.5 shadow-lg ring-1 duration-100 data-[state=closed]:overflow-hidden',\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n}\n\nfunction DropdownMenuGroup({ ...props }: ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n return <DropdownMenuPrimitive.Group data-slot='dropdown-menu-group' {...props} />;\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = 'default',\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: 'default' | 'destructive';\n}) {\n return (\n <DropdownMenuPrimitive.Item\n data-slot='dropdown-menu-item'\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"group/dropdown-menu-item focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:*:[svg]:text-destructive relative flex cursor-default items-center gap-2.5 rounded-2xl px-3 py-2 text-sm font-medium outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-9.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n inset,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & {\n inset?: boolean;\n}) {\n return (\n <DropdownMenuPrimitive.CheckboxItem\n data-slot='dropdown-menu-checkbox-item'\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground relative flex cursor-default items-center gap-2.5 rounded-2xl py-2 pr-8 pl-3 text-sm font-medium outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-9.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n checked={checked}\n {...props}>\n <span\n className='pointer-events-none absolute right-2 flex items-center justify-center'\n data-slot='dropdown-menu-checkbox-item-indicator'>\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon aria-hidden='true' />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n );\n}\n\nfunction DropdownMenuRadioGroup({\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {\n return <DropdownMenuPrimitive.RadioGroup data-slot='dropdown-menu-radio-group' {...props} />;\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n inset,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & {\n inset?: boolean;\n}) {\n return (\n <DropdownMenuPrimitive.RadioItem\n data-slot='dropdown-menu-radio-item'\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground relative flex cursor-default items-center gap-2.5 rounded-2xl py-2 pr-8 pl-3 text-sm font-medium outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-inset:pl-9.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}>\n <span\n className='pointer-events-none absolute right-2 flex items-center justify-center'\n data-slot='dropdown-menu-radio-item-indicator'>\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon aria-hidden='true' />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n );\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Label> & {\n inset?: boolean;\n}) {\n return (\n <DropdownMenuPrimitive.Label\n data-slot='dropdown-menu-label'\n data-inset={inset}\n className={cn('text-muted-foreground px-3 py-2.5 text-xs data-inset:pl-9.5', className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot='dropdown-menu-separator'\n className={cn('bg-border/50 -mx-1.5 my-1.5 h-px', className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuShortcut({ className, ...props }: ComponentProps<'span'>) {\n return (\n <span\n data-slot='dropdown-menu-shortcut'\n className={cn(\n 'text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground ml-auto text-xs tracking-widest',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSub({ ...props }: ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot='dropdown-menu-sub' {...props} />;\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n}) {\n return (\n <DropdownMenuPrimitive.SubTrigger\n data-slot='dropdown-menu-sub-trigger'\n data-inset={inset}\n className={cn(\n \"focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center gap-2 rounded-2xl px-3 py-2 text-sm font-medium outline-hidden select-none data-inset:pl-9.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className,\n )}\n {...props}>\n {children}\n <ChevronRightIcon className='ml-auto' aria-hidden='true' />\n </DropdownMenuPrimitive.SubTrigger>\n );\n}\n\nfunction DropdownMenuSubContent({\n className,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n return (\n <DropdownMenuPrimitive.SubContent\n data-slot='dropdown-menu-sub-content'\n className={cn(\n 'bg-popover text-popover-foreground ring-foreground/5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:ring-foreground/10 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 z-50 min-w-36 origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-3xl p-1.5 shadow-lg ring-1 duration-100',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport {\n DropdownMenu,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubTrigger,\n DropdownMenuSubContent,\n};\n","'use client';\n\nimport { useState } from 'react';\nimport type { Editor } from '@tiptap/react';\n// Type-only: Tiptap declares its table commands (insertTable, addRowAfter, …)\n// by module augmentation, so they exist on ChainedCommands only where the table\n// extension is in scope. `import type` pulls in those declarations without\n// adding the package to the bundle — the consumer supplies the runtime copy\n// through its own `extensions` array.\nimport type {} from '@tiptap/extension-table';\nimport type { ReactNode } from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/Button/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@/components/ui/DropdownMenu/dropdown-menu';\n\nconst DEFAULT_ROWS = 8;\nconst DEFAULT_COLUMNS = 10;\n\ninterface TableMenuLabels {\n trigger: string;\n insert: string;\n /**\n * A function, not a string: this is the only label with variables, and\n * formatting it here would mean reimplementing message interpolation. The\n * consumer keeps that in whatever i18n layer it already has.\n */\n dimensions: (rows: number, columns: number) => string;\n rowBefore: string;\n rowAfter: string;\n deleteRow: string;\n columnBefore: string;\n columnAfter: string;\n deleteColumn: string;\n toggleHeader: string;\n deleteTable: string;\n}\n\ninterface TableMenuProps {\n editor: Editor | null;\n labels: TableMenuLabels;\n icon: ReactNode;\n /**\n * The picker grid's extent. These bound the visual picker only — a\n * consumer whose document contract caps table size should also enforce\n * that ceiling where it validates the document.\n */\n maxRows?: number;\n maxColumns?: number;\n}\n\n/** Word-style table controls: a grid picker to insert, then row/column actions. */\nfunction TableMenu({\n editor,\n labels,\n icon,\n maxRows = DEFAULT_ROWS,\n maxColumns = DEFAULT_COLUMNS,\n}: TableMenuProps) {\n const [hovered, setHovered] = useState({ rows: 0, columns: 0 });\n\n // `can().deleteTable()` is the cheapest \"is the cursor in a table\" probe\n // Tiptap offers, and it gates every row/column action below.\n const insideTable = editor?.can().deleteTable() ?? false;\n\n function insert(rows: number, columns: number) {\n editor?.chain().focus().insertTable({ rows, cols: columns, withHeaderRow: true }).run();\n }\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type='button'\n size='sm'\n variant={editor?.isActive('table') ? 'secondary' : 'ghost'}\n disabled={!editor}\n title={labels.trigger}\n aria-label={labels.trigger}\n data-slot='table-menu-trigger'>\n {icon}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align='start' className='w-56'>\n {/* role='none' on the wrapper: a role='menu' subtree may only\n contain menuitem/group/separator, and this size picker is a\n grid of plain buttons plus a live counter. Presenting the\n wrapper as non-semantic takes it out of the menu's required\n -children contract while leaving its buttons reachable —\n which is what axe's aria-required-children rule wants. */}\n <div role='none' className='px-2 py-1.5'>\n <p className='text-muted-foreground mb-1.5 text-xs'>{labels.insert}</p>\n <div\n className='grid gap-0.5'\n style={{ gridTemplateColumns: `repeat(${maxColumns}, 1fr)` }}\n onMouseLeave={() => setHovered({ rows: 0, columns: 0 })}>\n {Array.from({ length: maxRows * maxColumns }, (_, index) => {\n const rows = Math.floor(index / maxColumns) + 1;\n const columns = (index % maxColumns) + 1;\n const active = rows <= hovered.rows && columns <= hovered.columns;\n\n return (\n <button\n key={index}\n type='button'\n aria-label={labels.dimensions(rows, columns)}\n className={cn(\n 'h-3.5 w-3.5 cursor-pointer rounded-[2px] border',\n active ? 'bg-primary border-primary' : 'bg-background',\n )}\n // onFocus mirrors onMouseEnter so the grid\n // is usable by keyboard, not just hover.\n onMouseEnter={() => setHovered({ rows, columns })}\n onFocus={() => setHovered({ rows, columns })}\n onClick={() => insert(rows, columns)}\n />\n );\n })}\n </div>\n <p\n aria-live='polite'\n data-slot='table-menu-dimensions'\n className='text-muted-foreground mt-1.5 text-xs tabular-nums'>\n {labels.dimensions(hovered.rows, hovered.columns)}\n </p>\n </div>\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem\n className='cursor-pointer'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().addRowBefore().run()}>\n {labels.rowBefore}\n </DropdownMenuItem>\n <DropdownMenuItem\n className='cursor-pointer'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().addRowAfter().run()}>\n {labels.rowAfter}\n </DropdownMenuItem>\n <DropdownMenuItem\n className='cursor-pointer'\n variant='destructive'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().deleteRow().run()}>\n {labels.deleteRow}\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem\n className='cursor-pointer'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().addColumnBefore().run()}>\n {labels.columnBefore}\n </DropdownMenuItem>\n <DropdownMenuItem\n className='cursor-pointer'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().addColumnAfter().run()}>\n {labels.columnAfter}\n </DropdownMenuItem>\n <DropdownMenuItem\n className='cursor-pointer'\n variant='destructive'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().deleteColumn().run()}>\n {labels.deleteColumn}\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n\n <DropdownMenuItem\n className='cursor-pointer'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().toggleHeaderRow().run()}>\n {labels.toggleHeader}\n </DropdownMenuItem>\n <DropdownMenuItem\n className='cursor-pointer'\n variant='destructive'\n disabled={!insideTable}\n onSelect={() => editor?.chain().focus().deleteTable().run()}>\n {labels.deleteTable}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport { TableMenu };\nexport type { TableMenuProps, TableMenuLabels };\n","// ─────────────────────────────────────────────\n// tcce-design-system · animation tokens\n// Motion (ex Framer Motion) — sutil y profesional\n// ─────────────────────────────────────────────\n\n// ── Durations ────────────────────────────────\n// Usa la escala más corta posible para cada caso.\n// instant → feedback táctil (hover, active, focus ring)\n// fast → elementos pequeños que entran/salen (badge, tooltip, switch)\n// normal → componentes de tamaño medio (dropdown, toast, input state)\n// slow → overlays y transiciones de página (modal backdrop, sidebar)\nexport const duration = {\n instant: 0.1,\n fast: 0.15,\n normal: 0.25,\n slow: 0.4,\n} as const;\n\n// ── Easings ──────────────────────────────────\n// Curvas estándar de Material Design adaptadas para uso profesional.\n// smooth → entrada y salida equilibrada (la más usada)\n// enter → aceleración suave al entrar (elementos que aparecen)\n// exit → desaceleración al salir (elementos que desaparecen)\n// linear → progreso, loaders, skeleton shimmer\nexport const ease = {\n smooth: [0.4, 0, 0.2, 1] as const,\n enter: [0.0, 0, 0.2, 1] as const,\n exit: [0.4, 0, 1.0, 1] as const,\n linear: [0.0, 0, 1.0, 1] as const,\n drawer: [0.22, 1, 0.36, 1] as const,\n} as const;\n\n// ── Spring configs ────────────────────────────\n// Solo para componentes que necesitan sensación física ligera.\n// gentle → modales, drawers, paneles deslizantes\n// snappy → switches, toggles, checkboxes\n// NO usar spring en: toasts, tooltips, dropdowns (demasiado movimiento)\nexport const spring = {\n gentle: { type: 'spring', stiffness: 260, damping: 28 } as const,\n snappy: { type: 'spring', stiffness: 400, damping: 30 } as const,\n} as const;\n\n// ── Transitions predefinidas ──────────────────\n// Combinaciones listas para usar en cada tipo de componente.\n// Importa la que corresponda en lugar de armar la config cada vez.\n\nexport const transition = {\n // Botones — feedback instantáneo en hover/tap\n button: {\n duration: duration.instant,\n ease: ease.smooth,\n },\n\n // Switch / toggle / checkbox\n toggle: {\n ...spring.snappy,\n },\n\n // Inputs — cambio de borde en focus, estados de error\n input: {\n duration: duration.fast,\n ease: ease.smooth,\n },\n\n // Dropdown / select / popover\n dropdown: {\n duration: duration.fast,\n ease: ease.enter,\n },\n\n // Toast / notification — entra rápido, sale más rápido aún\n toast: {\n duration: duration.fast,\n ease: ease.smooth,\n },\n\n // Modal / dialog — más lento para dar peso al overlay\n modal: {\n ...spring.gentle,\n },\n\n // Sidebar / navigation drawer\n sidebar: {\n duration: duration.slow,\n ease: ease.smooth,\n },\n\n // Cards — hover sutil, sin spring\n card: {\n duration: duration.fast,\n ease: ease.smooth,\n },\n\n // Drawer / slide panel — smooth enter, fast exit\n drawer: {\n duration: 0.3,\n ease: ease.drawer,\n },\n drawerExit: {\n duration: 0.2,\n ease: ease.exit,\n },\n} as const;\n\n// ── Variants Motion reutilizables ─────────────\n// Úsalos directamente en <motion.div variants={fadeIn}>\n\nexport const fadeIn = {\n hidden: { opacity: 0 },\n visible: { opacity: 1, transition: transition.dropdown },\n exit: { opacity: 0, transition: { duration: duration.fast, ease: ease.exit } },\n} as const;\n\nexport const slideUp = {\n hidden: { opacity: 0, y: 8 },\n visible: { opacity: 1, y: 0, transition: transition.dropdown },\n exit: { opacity: 0, y: 4, transition: { duration: duration.fast, ease: ease.exit } },\n} as const;\n\nexport const slideRight = {\n hidden: { opacity: 0, x: -12 },\n visible: { opacity: 1, x: 0, transition: transition.sidebar },\n exit: { opacity: 0, x: -12, transition: { duration: duration.normal, ease: ease.exit } },\n} as const;\n\nexport const scaleIn = {\n hidden: { opacity: 0, scale: 0.97 },\n visible: { opacity: 1, scale: 1, transition: transition.modal },\n exit: { opacity: 0, scale: 0.97, transition: { duration: duration.fast, ease: ease.exit } },\n} as const;\n\n// ── Stagger (para listas y grids) ─────────────\n// Úsalo en el contenedor padre con variants + staggerChildren\nexport const stagger = {\n container: {\n hidden: {},\n visible: { transition: { staggerChildren: 0.06, delayChildren: 0.05 } },\n },\n item: {\n hidden: { opacity: 0, y: 6 },\n visible: { opacity: 1, y: 0, transition: transition.card },\n },\n} as const;\n\n// ── Export agrupado ───────────────────────────\nexport const animation = {\n duration,\n ease,\n spring,\n transition,\n variants: { fadeIn, slideUp, slideRight, scaleIn, stagger },\n} as const;\n\nexport type AnimationTokens = typeof animation;\n","import { createContext, useContext, useState, type ComponentProps } from 'react';\nimport { Dialog as DialogPrimitive } from 'radix-ui';\nimport { motion, AnimatePresence } from 'motion/react';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/Button/button';\nimport { XIcon } from 'lucide-react';\nimport { transition, ease, duration } from '@/tokens/animation';\n\n// ─── Contexto interno ─────────────────────────────────────────────────────────\n\nconst DialogContext = createContext(false);\n\n// ─── Root ────────────────────────────────────────────────────────────────────\n\nfunction Dialog({ children, ...props }: ComponentProps<typeof DialogPrimitive.Root>) {\n const [internalOpen, setInternalOpen] = useState(props.defaultOpen ?? false);\n\n const isOpen = props.open !== undefined ? props.open : internalOpen;\n\n return (\n <DialogContext.Provider value={isOpen}>\n <DialogPrimitive.Root\n data-slot='dialog'\n open={isOpen}\n onOpenChange={(v) => {\n setInternalOpen(v);\n props.onOpenChange?.(v);\n }}\n {...props}>\n {children}\n </DialogPrimitive.Root>\n </DialogContext.Provider>\n );\n}\n\n// ─── Trigger ─────────────────────────────────────────────────────────────────\n\nfunction DialogTrigger({ ...props }: ComponentProps<typeof DialogPrimitive.Trigger>) {\n return <DialogPrimitive.Trigger data-slot='dialog-trigger' {...props} />;\n}\n\n// ─── Portal — AnimatePresence vive aquí ──────────────────────────────────────\n\nfunction DialogPortal({ children, ...props }: ComponentProps<typeof DialogPrimitive.Portal>) {\n const isOpen = useContext(DialogContext);\n\n return (\n <DialogPrimitive.Portal data-slot='dialog-portal' forceMount {...props}>\n <AnimatePresence mode='sync'>{isOpen && children}</AnimatePresence>\n </DialogPrimitive.Portal>\n );\n}\n\n// ─── Close ───────────────────────────────────────────────────────────────────\n\nfunction DialogClose({ ...props }: ComponentProps<typeof DialogPrimitive.Close>) {\n return <DialogPrimitive.Close data-slot='dialog-close' {...props} />;\n}\n\n// ─── Overlay — fade independiente ────────────────────────────────────────────\n\nfunction DialogOverlay({ className, ...props }: ComponentProps<typeof DialogPrimitive.Overlay>) {\n return (\n <DialogPrimitive.Overlay data-slot='dialog-overlay' asChild forceMount {...props}>\n <motion.div\n className={cn(\n 'fixed inset-0 isolate z-50 bg-black/30 supports-backdrop-filter:backdrop-blur-sm',\n className,\n )}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: duration.normal, ease: ease.smooth }}\n />\n </DialogPrimitive.Overlay>\n );\n}\n\n// ─── Content — scale + fade + slideUp con spring ─────────────────────────────\n\nfunction DialogContent({\n className,\n children,\n showCloseButton = false,\n ...props\n}: ComponentProps<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean;\n}) {\n return (\n <DialogPortal>\n <DialogOverlay key='dialog-overlay' />\n <DialogPrimitive.Content\n key='dialog-content'\n data-slot='dialog-content'\n asChild\n forceMount\n className={cn(\n 'bg-popover text-popover-foreground ring-foreground/5 dark:ring-foreground/10 fixed top-1/2 left-1/2 z-50 flex max-h-[85vh] w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 flex-col rounded-lg text-sm shadow-xl ring-1 outline-none sm:max-w-sm',\n className,\n )}\n {...props}>\n <motion.div\n className='flex max-h-[85vh] flex-col'\n initial={{ opacity: 0, scale: 0.96, y: 8 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.96, y: 4 }}\n transition={transition.modal}>\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close data-slot='dialog-close' asChild>\n <Button\n variant='ghost'\n className='absolute top-4 right-4'\n size='icon-sm'>\n <XIcon />\n <span className='sr-only'>Close</span>\n </Button>\n </DialogPrimitive.Close>\n )}\n </motion.div>\n </DialogPrimitive.Content>\n </DialogPortal>\n );\n}\n\n// ─── Header ──────────────────────────────────────────────────────────────────\n\nfunction DialogHeader({ className, ...props }: ComponentProps<'div'>) {\n return (\n <div\n data-slot='dialog-header'\n className={cn('flex shrink-0 flex-col gap-3 px-6 pt-6', className)}\n {...props}\n />\n );\n}\n\nfunction DialogBody({ className, ...props }: ComponentProps<'div'>) {\n return (\n <div\n data-slot='dialog-body'\n className={cn('flex-1 overflow-y-auto px-6 pb-6', className)}\n {...props}\n />\n );\n}\n\n// ─── Footer ──────────────────────────────────────────────────────────────────\n\nfunction DialogFooter({\n className,\n showCloseButton = false,\n children,\n ...props\n}: ComponentProps<'div'> & {\n showCloseButton?: boolean;\n}) {\n return (\n <div\n data-slot='dialog-footer'\n className={cn(\n 'border-border bg-muted/40 flex shrink-0 flex-wrap items-center justify-end gap-2 rounded-b-lg border-t px-6 pt-4 pb-4',\n className,\n )}\n {...props}>\n {children}\n {showCloseButton && (\n <DialogPrimitive.Close asChild>\n <Button variant='secondary'>Close</Button>\n </DialogPrimitive.Close>\n )}\n </div>\n );\n}\n\n// ─── Title ───────────────────────────────────────────────────────────────────\n\nfunction DialogTitle({ className, ...props }: ComponentProps<typeof DialogPrimitive.Title>) {\n return (\n <DialogPrimitive.Title\n data-slot='dialog-title'\n className={cn('font-heading text-lg leading-none font-bold wrap-anywhere', className)}\n {...props}\n />\n );\n}\n\n// ─── Description ─────────────────────────────────────────────────────────────\n\nfunction DialogDescription({\n className,\n ...props\n}: ComponentProps<typeof DialogPrimitive.Description>) {\n return (\n <DialogPrimitive.Description\n data-slot='dialog-description'\n className={cn(\n 'text-muted-foreground *:[a]:hover:text-foreground text-sm wrap-anywhere *:[a]:underline *:[a]:underline-offset-3',\n className,\n )}\n {...props}\n />\n );\n}\n\n// ─── Exports ─────────────────────────────────────────────────────────────────\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogBody,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n DialogTrigger,\n};\n","import { UploadIcon } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { createContext, useContext } from 'react';\nimport type { DropEvent, DropzoneOptions, FileRejection } from 'react-dropzone';\nimport { useDropzone } from 'react-dropzone';\nimport { cva } from 'class-variance-authority';\nimport { Button } from '@/components/ui/Button/button';\nimport { cn } from '@/lib/utils';\n\ninterface DropzoneContextType {\n src?: File[];\n accept?: DropzoneOptions['accept'];\n maxSize?: DropzoneOptions['maxSize'];\n minSize?: DropzoneOptions['minSize'];\n maxFiles?: DropzoneOptions['maxFiles'];\n}\n\nconst renderBytes = (bytes: number) => {\n const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];\n let size = bytes;\n let unitIndex = 0;\n\n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n\n return `${size.toFixed(2)}${units[unitIndex]}`;\n};\n\nconst DropzoneContext = createContext<DropzoneContextType | undefined>(undefined);\n\nconst dropzoneVariants = cva('', {\n variants: {\n border: {\n default: 'border border-solid border-foreground/15',\n dashed: 'border-dashed border-foreground/50',\n },\n },\n defaultVariants: {\n border: 'default',\n },\n});\n\nexport type DropzoneProps = Omit<DropzoneOptions, 'onDrop'> & {\n src?: File[];\n className?: string;\n border?: 'default' | 'dashed';\n onDrop?: (acceptedFiles: File[], fileRejections: FileRejection[], event: DropEvent) => void;\n children?: ReactNode;\n};\n\nexport const Dropzone = ({\n accept,\n maxFiles = 1,\n maxSize,\n minSize,\n onDrop,\n onError,\n disabled,\n src,\n className,\n children,\n border,\n ...props\n}: DropzoneProps) => {\n const { getRootProps, getInputProps, isDragActive } = useDropzone({\n accept,\n maxFiles,\n maxSize,\n minSize,\n onError,\n disabled,\n onDrop: (acceptedFiles, fileRejections, event) => {\n if (fileRejections.length > 0) {\n const message = fileRejections.at(0)?.errors.at(0)?.message;\n onError?.(new Error(message));\n }\n if (acceptedFiles.length > 0) {\n onDrop?.(acceptedFiles, fileRejections, event);\n }\n },\n ...props,\n });\n\n return (\n <DropzoneContext.Provider\n key={JSON.stringify(src)}\n value={{ src, accept, maxSize, minSize, maxFiles }}>\n <Button\n data-slot='dropzone'\n data-border={border ?? 'default'}\n className={cn(\n 'cursor-auto relative h-auto w-full flex-col overflow-hidden p-8',\n dropzoneVariants({ border }),\n isDragActive && 'bg-foreground/10 outline-none',\n className,\n )}\n disabled={disabled}\n type='button'\n variant='ghost'\n {...getRootProps()}>\n <input {...getInputProps()} disabled={disabled} />\n {children}\n </Button>\n </DropzoneContext.Provider>\n );\n};\n\nconst useDropzoneContext = () => {\n const context = useContext(DropzoneContext);\n\n if (!context) {\n throw new Error('useDropzoneContext must be used within a Dropzone');\n }\n\n return context;\n};\n\nexport interface DropzoneContentProps {\n children?: ReactNode;\n className?: string;\n}\n\nconst maxLabelItems = 3;\n\nexport const DropzoneContent = ({ children, className }: DropzoneContentProps) => {\n const { src } = useDropzoneContext();\n\n if (!src) {\n return null;\n }\n\n if (children) {\n return children;\n }\n\n return (\n <div className={cn('flex flex-col items-center justify-center', className)}>\n <div className='bg-muted text-muted-foreground flex size-8 items-center justify-center rounded-md'>\n <UploadIcon size={16} />\n </div>\n <p className='text-foreground my-2 w-full truncate text-sm font-medium'>\n {src.length > maxLabelItems\n ? `${new Intl.ListFormat('en').format(\n src.slice(0, maxLabelItems).map((file) => file.name),\n )} and ${src.length - maxLabelItems} more`\n : new Intl.ListFormat('en').format(src.map((file) => file.name))}\n </p>\n <p className='text-muted-foreground w-full text-xs font-normal text-wrap'>\n Drag and drop or click to replace\n </p>\n </div>\n );\n};\n\nexport interface DropzoneEmptyStateProps {\n children?: ReactNode;\n className?: string;\n}\n\nexport const DropzoneEmptyState = ({ children, className }: DropzoneEmptyStateProps) => {\n const { src, accept, maxSize, minSize, maxFiles } = useDropzoneContext();\n\n if (src) {\n return null;\n }\n\n if (children) {\n return children;\n }\n\n let caption = '';\n\n if (accept) {\n caption += 'Accepts ';\n caption += new Intl.ListFormat('en').format(Object.keys(accept));\n }\n\n if (minSize && maxSize) {\n caption += ` between ${renderBytes(minSize)} and ${renderBytes(maxSize)}`;\n } else if (minSize) {\n caption += ` at least ${renderBytes(minSize)}`;\n } else if (maxSize) {\n caption += ` less than ${renderBytes(maxSize)}`;\n }\n\n return (\n <div className={cn('flex flex-col items-center justify-center', className)}>\n <div className='bg-muted text-muted-foreground flex size-8 items-center justify-center rounded-md'>\n <UploadIcon size={16} />\n </div>\n <p className='text-foreground my-2 w-full text-center text-sm font-medium text-wrap'>\n Upload {maxFiles === 1 ? 'a file' : 'files'}\n </p>\n <p className='text-muted-foreground text-center text-xs font-normal text-wrap'>\n Drag and drop or click to upload\n </p>\n\n {caption && (\n <p className='text-muted-foreground text-xs font-normal text-wrap'>{caption}.</p>\n )}\n </div>\n );\n};\n","import { type ComponentProps } from 'react';\nimport { cn } from '@/lib/utils';\n\nfunction Input({ className, type, ...props }: ComponentProps<'input'>) {\n return (\n <input\n type={type}\n data-slot='input'\n className={cn(\n 'border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[border-color,box-shadow] outline-hidden md:text-sm',\n 'placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground',\n 'file:text-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium',\n 'focus-visible:border-ring focus-visible:ring-ring/30 focus-visible:ring-3',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-invalid:ring-3',\n 'dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40',\n className,\n )}\n {...props}\n />\n );\n}\n\nexport { Input };\n","import { useId } from 'react';\nimport { Trash2 } from 'lucide-react';\n\nimport { Button } from '@/components/ui/Button/button';\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/Dialog/dialog';\nimport { Dropzone, DropzoneContent, DropzoneEmptyState } from '@/components/ui/Dropzone/dropzone';\nimport { Input } from '@/components/ui/Input/input';\nimport { Label } from '@/components/ui/Label/label';\n\nconst DEFAULT_MAX_SIZE = 5 * 1024 * 1024;\nconst DEFAULT_ACCEPT = { 'image/*': ['.png', '.jpg', '.jpeg', '.webp'] };\n\ninterface InsertImageDialogLabels {\n title: string;\n urlLabel: string;\n urlPlaceholder: string;\n altLabel: string;\n hint: string;\n cancel: string;\n apply: string;\n remove: string;\n}\n\ninterface InsertImageDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n labels: InsertImageDialogLabels;\n url: string;\n onUrlChange: (url: string) => void;\n alt: string;\n onAltChange: (alt: string) => void;\n file: File | null;\n onFileChange: (file: File | null) => void;\n /** True while the consumer is transferring the picked file. Locks the form. */\n uploading: boolean;\n onApply: () => void;\n onCancel?: () => void;\n /**\n * True when editing an image already in the document — reveals the\n * destructive remove action beside the apply button.\n */\n removable?: boolean;\n onRemove?: () => void;\n /** Upload limits belong to whoever receives the file, not to this dialog. */\n maxSizeBytes?: number;\n accept?: Record<string, string[]>;\n}\n\n/**\n * A controlled form for inserting an image. It deliberately does NOT upload:\n * the consumer owns the transfer (its own API, its own storage) and drives\n * `uploading` / `onApply` from there, so this dialog stays reusable across\n * products with different backends.\n */\nfunction InsertImageDialog({\n open,\n onOpenChange,\n labels,\n url,\n onUrlChange,\n alt,\n onAltChange,\n file,\n onFileChange,\n uploading,\n onApply,\n onCancel,\n removable = false,\n onRemove,\n maxSizeBytes = DEFAULT_MAX_SIZE,\n accept = DEFAULT_ACCEPT,\n}: InsertImageDialogProps) {\n // Generated ids, not fixed strings: two dialogs on one page would otherwise\n // share an id and each label would point at the wrong input.\n const urlId = useId();\n const altId = useId();\n\n // Alt text is required by design, not by politeness — an image with no\n // alternative text is unusable to a screen reader, so the dialog refuses to\n // put one in the document at all. There is deliberately no prop to opt out.\n const canApply = Boolean(file || url.trim()) && Boolean(alt.trim()) && !uploading;\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className='px-4 py-2' data-slot='insert-image-dialog'>\n <DialogHeader>\n <DialogTitle>{labels.title}</DialogTitle>\n </DialogHeader>\n <div className='mt-4 flex flex-col gap-3'>\n <Dropzone\n accept={accept}\n maxFiles={1}\n maxSize={maxSizeBytes}\n disabled={uploading}\n src={file ? [file] : []}\n onDrop={(files) => onFileChange(files[0] ?? null)}>\n <DropzoneEmptyState />\n <DropzoneContent />\n </Dropzone>\n {file && <p className='text-muted-foreground text-xs'>{file.name}</p>}\n <div className='flex flex-col gap-1'>\n <Label htmlFor={urlId}>{labels.urlLabel}</Label>\n <Input\n id={urlId}\n placeholder={labels.urlPlaceholder}\n value={url}\n onChange={(event) => onUrlChange(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && canApply) {\n event.preventDefault();\n onApply();\n }\n }}\n />\n </div>\n <div className='flex flex-col gap-1'>\n <Label htmlFor={altId}>{labels.altLabel}</Label>\n <Input\n id={altId}\n value={alt}\n onChange={(event) => onAltChange(event.target.value)}\n />\n </div>\n <p className='text-muted-foreground text-xs'>{labels.hint}</p>\n </div>\n <DialogFooter>\n {removable && onRemove && (\n <Button\n type='button'\n variant='ghost'\n className='text-destructive'\n onClick={onRemove}>\n <Trash2 className='h-4 w-4' />\n {labels.remove}\n </Button>\n )}\n <Button\n type='button'\n variant='outline'\n onClick={() => {\n if (onCancel) onCancel();\n else onOpenChange(false);\n }}>\n {labels.cancel}\n </Button>\n <Button type='button' onClick={onApply} disabled={!canApply}>\n {labels.apply}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport { InsertImageDialog };\nexport type { InsertImageDialogProps, InsertImageDialogLabels };\n","'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { Image, type ImageOptions } from '@tiptap/extension-image';\nimport { NodeViewWrapper, ReactNodeViewRenderer, type NodeViewProps } from '@tiptap/react';\n\nimport { cn } from '@/lib/utils';\n\nconst DEFAULT_MIN_WIDTH = 120;\n/** Fallbacks for the brief window before the file reports its real dimensions. */\nconst DEFAULT_START_WIDTH = 400;\nconst DEFAULT_RATIO = 4 / 3;\n/** How much one arrow press resizes by: coarse enough to be useful, fine enough to aim. */\nconst KEYBOARD_STEP = 20;\n\ninterface ResizableImageOptions {\n /** Already translated: names the resize handle for assistive tech. */\n resizeLabel: string;\n minWidth?: number;\n}\n\ninterface ImageAttrs {\n src: string;\n alt: string;\n width: number;\n height: number;\n}\n\n/**\n * A resize-overlay NodeView. The stock Image extension renders its own view (a\n * draggable img); this one owns the DOM so the handle can sit on top of the\n * picture.\n *\n * `width`/`height` are applied as an inline style rather than HTML attributes,\n * so a consumer that declares them `rendered: false` keeps the size in the\n * document JSON only — which is where a serializer should read it from. On the\n * unmeasured path (0/0) the img falls back to its natural size instead of\n * collapsing to `width=\"0\"`.\n */\nfunction ResizableImageView({ node, updateAttributes, selected, extension }: NodeViewProps) {\n const { src, alt, width, height } = node.attrs as ImageAttrs;\n\n // A ref that always holds the node's current size. The destructured values\n // above are captured by the resize callbacks, and ProseMirror can apply\n // several transactions before React re-renders this view — so two arrow\n // presses in a row would both start from the same stale width. Repeated\n // presses have to compound.\n const sizeRef = useRef({ width, height });\n sizeRef.current = { width, height };\n\n const { resizeLabel, minWidth = DEFAULT_MIN_WIDTH } =\n extension.options as ResizableImageOptions;\n\n const dragRef = useRef<{\n startX: number;\n width: number;\n ratio: number;\n maxWidth: number;\n } | null>(null);\n const [dragging, setDragging] = useState(false);\n\n // Shared by the pointer drag and the arrow keys so both clamp identically.\n const resizeTo = useCallback(\n (nextWidth: number, ratio: number, maxWidth: number) => {\n const clamped = Math.max(minWidth, Math.min(Math.round(nextWidth), maxWidth));\n updateAttributes({ width: clamped, height: Math.round(clamped / ratio) });\n },\n [minWidth, updateAttributes],\n );\n\n // Reads the live DOM because width/height stay 0 until the first resize.\n const measure = useCallback((handle: HTMLElement) => {\n const image = handle.parentElement?.querySelector('img') ?? null;\n const current = sizeRef.current;\n\n // The ceiling is the EDITABLE AREA, never the wrapper: the wrapper is\n // inline-block, so its own width is the image's width — measuring it\n // made every shrink permanent, because the reduced size instantly\n // became the new maximum and growing back was impossible.\n const editable = handle.closest('.ProseMirror');\n const available = editable?.clientWidth ?? 0;\n\n const naturalWidth = image?.naturalWidth ?? 0;\n const naturalHeight = image?.naturalHeight ?? 0;\n\n // The ratio comes from whichever pair is known, but the starting\n // WIDTH must be what is on screen — capped to the column. Starting\n // from an unbounded natural width meant a 4000px photo computed\n // 3980 for the first shrink, clamped straight to the ceiling, and\n // then sat there: every later press recomputed the same way, so the\n // image could never be made smaller.\n const ratio =\n current.width > 0 && current.height > 0\n ? current.width / current.height\n : naturalWidth > 0 && naturalHeight > 0\n ? naturalWidth / naturalHeight\n : DEFAULT_RATIO;\n\n const unbounded = current.width > 0 ? current.width : naturalWidth || DEFAULT_START_WIDTH;\n const startWidth = available > 0 ? Math.min(unbounded, available) : unbounded;\n\n return {\n width: startWidth,\n ratio,\n // jsdom reports clientWidth as 0, so a zero measure means \"no\n // constraint\" — the real clamp only applies in a browser.\n maxWidth: available > 0 ? available : Infinity,\n };\n }, []);\n\n // An image arrives with width/height at 0, which renders it at its natural\n // size — a 4000px photo blows past the editor and looks broken. Fit it to the\n // column once, on mount, keeping its ratio.\n //\n // Deliberately an effect and NOT an onLoad handler: the write below is a\n // ProseMirror transaction, and a consumer running with\n // `shouldRerenderOnTransaction: true` re-renders this view on every\n // transaction. In a browser that remounts the <img>, which fires `load`\n // again, which writes again — React bailed out with \"Maximum update depth\n // exceeded\". jsdom does not re-fire load on re-render, so no test caught it;\n // an effect guarded by a ref cannot re-enter regardless.\n const imageRef = useRef<HTMLImageElement>(null);\n const fittedSrcRef = useRef<string | null>(null);\n\n useEffect(() => {\n const img = imageRef.current;\n if (!img) return;\n // Author already chose a size, or this src was fitted before.\n if (sizeRef.current.width > 0 || fittedSrcRef.current === src) return;\n\n const fit = () => {\n const available = img.closest('.ProseMirror')?.clientWidth ?? 0;\n // Nothing to measure yet. Returning without claiming the src leaves\n // the door open for the load event below — an image inserted right\n // after an upload has no dimensions on the first pass, and a silent\n // bail here left it stuck at its natural size until the author\n // happened to drag the handle.\n if (!img.naturalWidth || !img.naturalHeight || available <= 0) return false;\n\n fittedSrcRef.current = src;\n // Never upscale: a small image keeps its own size rather than being\n // stretched across the column and going soft.\n const nextWidth = Math.min(img.naturalWidth, available);\n updateAttributes({\n width: nextWidth,\n height: Math.round(nextWidth / (img.naturalWidth / img.naturalHeight)),\n });\n\n return true;\n };\n\n // `complete` covers a cached file and a data URI, both ready before the\n // effect runs, which would never fire a load event here. It is also true\n // for a broken image, so a successful fit is what ends the attempt.\n if (img.complete && fit()) return;\n\n // Not `{ once: true }`: a decode can report zero dimensions on the first\n // event, and giving up after one try is what made a freshly uploaded\n // image render at full size.\n const onLoad = () => {\n if (fit()) img.removeEventListener('load', onLoad);\n };\n img.addEventListener('load', onLoad);\n return () => img.removeEventListener('load', onLoad);\n }, [src, updateAttributes]);\n\n const onPointerDown = useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n event.preventDefault();\n event.stopPropagation();\n const start = measure(event.currentTarget);\n dragRef.current = { startX: event.clientX, ...start };\n setDragging(true);\n\n const onMove = (moveEvent: PointerEvent) => {\n const drag = dragRef.current;\n if (!drag) return;\n resizeTo(drag.width + (moveEvent.clientX - drag.startX), drag.ratio, drag.maxWidth);\n };\n const onUp = () => {\n dragRef.current = null;\n setDragging(false);\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onUp);\n };\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onUp);\n },\n [measure, resizeTo],\n );\n\n // A pointer-only handle leaves the image unresizable without a mouse, which\n // role='button' promises but does not deliver. Arrow keys drive the same\n // clamped resize.\n const onKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n const step =\n event.key === 'ArrowRight'\n ? KEYBOARD_STEP\n : event.key === 'ArrowLeft'\n ? -KEYBOARD_STEP\n : 0;\n if (step === 0) return;\n\n event.preventDefault();\n const start = measure(event.currentTarget);\n resizeTo(start.width + step, start.ratio, start.maxWidth);\n },\n [measure, resizeTo],\n );\n\n const sizeStyle =\n width > 0\n ? { width, height: height > 0 ? height : undefined, maxWidth: '100%' }\n : undefined;\n\n return (\n <NodeViewWrapper\n data-slot='resizable-image'\n className='group relative inline-block max-w-full'>\n <img\n ref={imageRef}\n src={src}\n alt={alt}\n className='max-w-full rounded-md'\n style={sizeStyle}\n draggable={false}\n />\n <div\n role='button'\n tabIndex={0}\n aria-label={resizeLabel}\n title={resizeLabel}\n data-slot='resizable-image-handle'\n onPointerDown={onPointerDown}\n onKeyDown={onKeyDown}\n className={cn(\n 'border-primary absolute -right-1 -bottom-1 h-4 w-4 cursor-se-resize touch-none rounded-full border-2 bg-white transition-opacity',\n 'focus-visible:ring-ring/50 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:outline-none',\n dragging || selected ? 'opacity-100' : 'opacity-0 group-hover:opacity-100',\n )}\n />\n </NodeViewWrapper>\n );\n}\n\n/**\n * Builds an Image extension whose node view carries a resize handle.\n *\n * A factory rather than a component because ProseMirror — not React —\n * instantiates the node view, so there is no place to hand it props. Options\n * ride on the extension instead, and the view reads them off `extension.options`.\n */\nfunction createResizableImage(options: ResizableImageOptions) {\n // The type argument REPLACES the options type rather than widening it, so it\n // has to spell out the intersection: without it `addOptions` may only return\n // ImageOptions (rejecting resizeLabel), and with a bare\n // ResizableImageOptions the stock options a consumer still configures\n // (inline, allowBase64) disappear.\n return Image.extend<ImageOptions & ResizableImageOptions>({\n addOptions() {\n // `this.parent!()`, not `this.parent?.()`: the optional call widens\n // every inherited field to `| undefined`, which no longer satisfies\n // ImageOptions' required `inline`. Image always defines addOptions.\n return { ...this.parent!(), ...options };\n },\n // The size attributes belong to the extension, not to the consumer: the\n // stock Image extension keeps width/height too, but they default to null\n // and render as HTML attributes, which pins the image to a fixed size.\n //\n // A numeric default with `rendered: false` is what makes resizing work\n // at all — Tiptap v3 gates DOM emission on `rendered`, so the size stays\n // out of the markup and lives only in the document JSON, where a\n // serializer can read it. Without these declarations the schema drops\n // every updateAttributes({ width }) call and the handle does nothing.\n addAttributes() {\n return {\n ...this.parent?.(),\n width: { default: 0, rendered: false },\n height: { default: 0, rendered: false },\n };\n },\n addNodeView() {\n return ReactNodeViewRenderer(ResizableImageView);\n },\n });\n}\n\nexport { createResizableImage };\nexport type { ResizableImageOptions };\n","'use client';\n\nimport { useCallback, useMemo } from 'react';\nimport { useEditorState } from '@tiptap/react';\nimport { BubbleMenu } from '@tiptap/react/menus';\n// Type-only: Tiptap declares setLink/unsetLink by module augmentation, so they\n// exist on ChainedCommands only where the link extension is in scope. This pulls\n// in the declarations without adding the package to the bundle — StarterKit\n// supplies the runtime copy through the consumer's own extensions array.\nimport type {} from '@tiptap/extension-link';\nimport { ExternalLink, Pencil, Unlink } from 'lucide-react';\n\nimport { Button } from '@/components/ui/Button/button';\n\nimport type { Editor } from '@tiptap/react';\n\ninterface LinkBubbleMenuLabels {\n open: string;\n edit: string;\n remove: string;\n}\n\ninterface LinkBubbleMenuProps {\n editor: Editor | null;\n labels: LinkBubbleMenuLabels;\n /** Opens the consumer's link dialog, pre-filled with the current href. */\n onEdit: () => void;\n /**\n * Follows the link. Left to the consumer for the cases this package cannot\n * judge — routing instead of navigating, or confirming first.\n *\n * Defaults to opening a new tab, which is also what Ctrl/Cmd-click does, so\n * the author never loses unsaved work just by checking a URL.\n */\n onOpen?: (href: string) => void;\n}\n\ninterface LinkActionsProps {\n editor: Editor;\n labels: LinkBubbleMenuLabels;\n onEdit: () => void;\n onOpen?: (href: string) => void;\n}\n\n/**\n * A floating bar that appears when the cursor sits inside a link, offering to\n * open, edit or unlink it.\n *\n * It exists because an editor cannot let a plain click navigate: clicking is how\n * you place the cursor to fix a typo, so `openOnClick` stays false and this\n * gives the author a deliberate way out to the URL. Ctrl/Cmd-click is wired\n * separately, on the editor itself, for people who expect the shortcut.\n */\n/**\n * The bar itself, without any positioning.\n *\n * Split out from the floating wrapper so its behaviour is reachable in a test:\n * BubbleMenu positions through Floating UI, which needs layout APIs jsdom does\n * not implement, and mounting it in jsdom fails before any button exists.\n */\nfunction LinkActions({ editor, labels, onEdit, onOpen }: LinkActionsProps) {\n // useEditorState, never a bare editor.getAttributes() in the render body:\n // reading editor state during render re-subscribes on every render, each\n // subscription emits, and the editor's notification loop never settles —\n // React aborts with \"Maximum update depth exceeded\" once a consumer sets\n // shouldRerenderOnTransaction. This subscribes once and re-renders only when\n // the href actually changes.\n // `canOpen`, not just a truthy href: this reads the STORED attribute, so it\n // never sees the blanking Tiptap applies to a disallowed href when it\n // renders. Asking the editor whether it would accept the URL reuses the\n // Link extension's own `protocols` / `isAllowedUri` configuration, and stops\n // a document built outside the insert-link dialog from turning this button\n // into a `javascript:` sink. Disabled rather than silently inert, so the\n // author can tell the difference.\n const { href, canOpen } = useEditorState({\n editor,\n selector: ({ editor: current }) => {\n const value = (current.getAttributes('link').href as string | undefined) ?? '';\n return { href: value, canOpen: !!value && current.can().setLink({ href: value }) };\n },\n });\n\n return (\n <div\n data-slot='link-bubble-menu'\n className='bg-popover text-popover-foreground flex items-center gap-1 rounded-md border p-1 shadow-md'>\n <span className='text-muted-foreground max-w-[16rem] truncate px-2 text-xs'>\n {href}\n </span>\n <Button\n type='button'\n size='sm'\n variant='ghost'\n title={labels.open}\n aria-label={labels.open}\n disabled={!canOpen}\n onClick={() => {\n if (!canOpen) return;\n if (onOpen) {\n onOpen(href);\n return;\n }\n // A new tab by default, matching Ctrl/Cmd-click: checking\n // where a link points should never cost the author unsaved\n // work. noopener/noreferrer keeps the opened page from\n // reaching back through window.opener.\n window.open(href, '_blank', 'noopener,noreferrer');\n }}>\n <ExternalLink className='h-4 w-4' />\n </Button>\n <Button\n type='button'\n size='sm'\n variant='ghost'\n title={labels.edit}\n aria-label={labels.edit}\n onClick={onEdit}>\n <Pencil className='h-4 w-4' />\n </Button>\n <Button\n type='button'\n size='sm'\n variant='ghost'\n className='text-destructive'\n title={labels.remove}\n aria-label={labels.remove}\n // extendMarkRange first: the caret is somewhere inside the link,\n // and unsetLink alone would only clear the character range under\n // it, leaving the rest of the anchor behind.\n onClick={() => editor.chain().focus().extendMarkRange('link').unsetLink().run()}>\n <Unlink className='h-4 w-4' />\n </Button>\n </div>\n );\n}\n\n/**\n * A floating bar that appears when the caret sits inside a link, offering to\n * open, edit or unlink it.\n *\n * It exists because an editor cannot let a plain click navigate: clicking is how\n * you place the caret to fix a typo, so `openOnClick` stays false and this gives\n * the author a deliberate way out to the URL. Ctrl/Cmd-click is wired separately,\n * on the editor itself, for people who expect the shortcut.\n */\nfunction LinkBubbleMenu({ editor, labels, onEdit, onOpen }: LinkBubbleMenuProps) {\n // Both props below MUST be referentially stable. BubbleMenu re-runs its\n // plugin setup whenever they change, and each setup emits a transaction —\n // so a fresh inline function or object literal per render feeds the editor's\n // notification loop until React aborts with \"Maximum update depth exceeded\".\n // The hooks run before the null check so their order never varies.\n const shouldShow = useCallback(\n // Only while the caret is actually in a link — otherwise this bar would\n // compete with any other bubble menu the consumer adds.\n ({ editor: current }: { editor: Editor }) => current.isActive('link'),\n [],\n );\n const options = useMemo(() => ({ placement: 'bottom' as const, offset: 8 }), []);\n\n if (!editor) return null;\n\n return (\n <BubbleMenu editor={editor} shouldShow={shouldShow} options={options}>\n <LinkActions editor={editor} labels={labels} onEdit={onEdit} onOpen={onOpen} />\n </BubbleMenu>\n );\n}\n\nexport { LinkBubbleMenu, LinkActions };\nexport type { LinkBubbleMenuProps, LinkActionsProps, LinkBubbleMenuLabels };\n","'use client';\n\nimport { Check, ChevronDown } from 'lucide-react';\n\nimport type { Editor } from '@tiptap/react';\nimport type { ReactNode } from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/Button/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@/components/ui/DropdownMenu/dropdown-menu';\n\n/** One list style the consumer offers. */\ninterface ListOption {\n /** The Tiptap node this entry toggles, e.g. `bulletList`. */\n node: string;\n /** Already translated name. */\n label: string;\n icon: ReactNode;\n run: (editor: Editor) => void;\n}\n\ninterface ListMenuProps {\n editor: Editor | null;\n /** Already translated. Names the trigger for assistive tech. */\n triggerLabel: string;\n /** Shown on the trigger when no list style is active. */\n icon: ReactNode;\n options: ListOption[];\n}\n\n/**\n * Groups the list styles behind one trigger.\n *\n * A row of separate buttons costs three toolbar slots for choices that are\n * mutually exclusive; one trigger showing the active style reads faster and\n * leaves room for the rest of the toolbar. The trigger swaps to the active\n * style's icon so the current state is visible without opening the menu.\n */\nfunction ListMenu({ editor, triggerLabel, icon, options }: ListMenuProps) {\n const active = options.find((option) => editor?.isActive(option.node));\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type='button'\n size='sm'\n variant={active ? 'secondary' : 'ghost'}\n disabled={!editor}\n title={active ? active.label : triggerLabel}\n aria-label={active ? active.label : triggerLabel}\n data-slot='list-menu-trigger'>\n {active ? active.icon : icon}\n {/* Marks the trigger as a disclosure: without it the button\n looks like the other toolbar toggles and nothing suggests\n there are more styles behind it. */}\n <ChevronDown className='h-3 w-3 opacity-60' />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align='start'>\n {options.map((option) => {\n const isActive = editor?.isActive(option.node) ?? false;\n\n return (\n <DropdownMenuItem\n key={option.node}\n disabled={!editor}\n className='cursor-pointer'\n onSelect={() => editor && option.run(editor)}>\n {option.icon}\n <span className='flex-1'>{option.label}</span>\n {/* A tick rather than a highlighted row: these\n toggle, so the menu has to say which is on. Kept\n mounted at zero opacity so rows do not shift\n width as the active style changes. */}\n <Check\n aria-hidden='true'\n className={cn('h-4 w-4', isActive ? 'opacity-100' : 'opacity-0')}\n />\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport { ListMenu };\nexport type { ListMenuProps, ListOption };\n","'use client';\n\nimport { useCallback, useMemo, useState } from 'react';\nimport Highlight from '@tiptap/extension-highlight';\nimport { TableKit } from '@tiptap/extension-table';\nimport { useEditor, type Editor, type JSONContent } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\nimport {\n Bold,\n Heading2,\n Highlighter,\n ImagePlus,\n Italic,\n Link as LinkIcon,\n List,\n ListOrdered,\n Quote,\n Strikethrough,\n Table as TableIcon,\n Underline,\n} from 'lucide-react';\n\nimport { createResizableImage } from './resizable-image';\nimport { LinkBubbleMenu, type LinkBubbleMenuLabels } from './link-bubble-menu';\nimport { EDITOR_CONTENT_STYLE } from './rich-text-editor';\nimport { ListMenu } from './list-menu';\nimport { TableMenu, type TableMenuLabels } from './table-menu';\n\nimport type { ReactNode } from 'react';\nimport type { EditorOptions } from '@tiptap/react';\nimport type { ToolbarItem } from './rich-text-toolbar';\n\n/**\n * Whatever `useEditor` accepts in its `extensions` array.\n *\n * Derived from Tiptap's own option rather than imported as AnyExtension: the\n * name resolves to a structurally different declaration depending on which copy\n * of @tiptap/core is in scope, and the two do not assign to each other.\n */\ntype EditorExtension = EditorOptions['extensions'][number];\n\n/** Every string the built-in toolbar and menus need. All already translated. */\ninterface RichTextEditorLabels {\n /** Names the editable area for assistive tech. Required — it has no visible label. */\n editor: string;\n bold: string;\n italic: string;\n heading: string;\n underline: string;\n strikethrough: string;\n quote: string;\n insertLink: string;\n insertImage: string;\n resizeImage: string;\n lists: { trigger: string; bullet: string; ordered: string };\n /** The floating bar shown while the caret sits inside a link. */\n link: LinkBubbleMenuLabels;\n table: TableMenuLabels;\n highlight: string;\n}\n\ninterface UseRichTextEditorOptions {\n labels: RichTextEditorLabels;\n /** Fires on every document change, with the current ProseMirror JSON. */\n onUpdate?: (doc: JSONContent) => void;\n /** Initial document. */\n content?: JSONContent | string;\n /** Opens the consumer's link dialog. Wire the toolbar's link button to it. */\n onInsertLink?: () => void;\n /** Opens the consumer's image dialog. */\n onInsertImage?: () => void;\n /**\n * Marks and nodes this product's document contract requires — a brand font,\n * a colour palette, anything a server-side whitelist validates. They are\n * appended to the built-in set rather than replacing it.\n */\n extraExtensions?: EditorExtension[];\n /**\n * Extra toolbar entries, and where they go. `after` names a built-in id\n * (`heading`, `highlight`, `strike`, `image`…); omit it to append at the end.\n */\n extraToolbar?: { after?: string; items: ToolbarItem[] }[];\n /**\n * Replaces a built-in entry, keyed by its id.\n *\n * For when a product needs a richer version of something the preset already\n * provides — swapping the single highlight button for a palette of shades,\n * say. Replacing rather than adding keeps the toolbar from carrying both.\n */\n replaceToolbar?: Record<string, ToolbarItem>;\n /** Merged on top of the built-in content styles. */\n contentClassName?: string;\n /** Allows data: URIs in images. Off by default: uploads belong in storage. */\n allowBase64Images?: boolean;\n /**\n * Merged into the editor's `editorProps`. For behaviour only a product can\n * define — clamping pasted tables to a contract's row limit, say.\n *\n * `attributes` and `handleClick` are set by the hook and are not overridable:\n * they carry the accessible name and the link shortcut, which are the\n * defaults consumers were getting wrong by hand.\n */\n editorProps?: Omit<NonNullable<EditorOptions['editorProps']>, 'attributes' | 'handleClick'>;\n}\n\ninterface UseRichTextEditorResult {\n editor: Editor | null;\n /**\n * The floating link bar, ready to render beside `<RichTextEditor />`.\n *\n * Returned as an element rather than left to the consumer because it is easy\n * to forget, and an editor without it gives the author no way to reach or\n * remove a link they have already inserted.\n */\n linkMenu: ReactNode;\n /** Ready for `<RichTextEditor items={...} />`. */\n toolbar: ToolbarItem[];\n /** True when the caret has no selection, so a new link needs its own text. */\n linkNeedsText: boolean;\n /** Reads the caret's current href — pre-fill the dialog with it. */\n currentLinkHref: () => string;\n /** Applies a link, inserting `text` when there is no selection to wrap. */\n applyLink: (href: string, text?: string) => void;\n}\n\n/**\n * Builds a configured Tiptap editor and its toolbar.\n *\n * Everything a rich text editor needs to behave correctly is set up here —\n * Ctrl/Cmd-click on links, the accessible name for the editable area, the\n * repaint-on-transaction the toolbar's pressed state depends on, the content\n * styles — so a consumer cannot end up with a subtly different editor by\n * forgetting one of them.\n *\n * What stays with the consumer is what only it can know: the marks its document\n * contract allows, and the copy. Both arrive as options.\n */\nfunction useRichTextEditor({\n labels,\n onUpdate,\n content,\n onInsertLink,\n onInsertImage,\n extraExtensions = [],\n extraToolbar = [],\n replaceToolbar,\n contentClassName,\n allowBase64Images = false,\n editorProps,\n}: UseRichTextEditorOptions): UseRichTextEditorResult {\n // Tracked here rather than by the consumer because it is derived from editor\n // state at the moment the dialog opens, which the consumer would otherwise\n // have to reach into the editor for.\n const [linkNeedsText, setLinkNeedsText] = useState(false);\n\n const editor = useEditor({\n extensions: [\n // openOnClick false: a plain click has to place the caret so the\n // author can edit link text. Left at its default, Tiptap navigates\n // the current tab and throws the author out of the editor.\n StarterKit.configure({ link: { openOnClick: false } }),\n Highlight,\n TableKit.configure({ table: { resizable: true } }),\n createResizableImage({ resizeLabel: labels.resizeImage }).configure({\n inline: false,\n allowBase64: allowBase64Images,\n }),\n ...extraExtensions,\n ],\n content,\n immediatelyRender: false,\n // Required for the toolbar's pressed state and the image node view to\n // repaint as the selection and attributes change.\n shouldRerenderOnTransaction: true,\n editorProps: {\n ...editorProps,\n attributes: {\n // ProseMirror's editable div needs its own accessible name: a\n // visible <Label> beside it is decoration, and a screen reader\n // would announce an unnamed box.\n role: 'textbox',\n 'aria-label': labels.editor,\n class: contentClassName\n ? `${EDITOR_CONTENT_STYLE} ${contentClassName}`\n : EDITOR_CONTENT_STYLE,\n },\n // Ctrl/Cmd-click opens the link in a new tab and leaves the author\n // where they were: the shortcut is a deliberate gesture, and keeping\n // the editor open means no unsaved work is at risk. A plain click\n // falls through to ProseMirror and just moves the caret.\n handleClick(_view, _pos, event) {\n if (!event.ctrlKey && !event.metaKey) return false;\n\n const href = (event.target as HTMLElement)?.closest('a')?.getAttribute('href');\n if (!href) return false;\n\n event.preventDefault();\n // noopener/noreferrer: the opened page must not get a handle on\n // the editor's window through window.opener.\n window.open(href, '_blank', 'noopener,noreferrer');\n return true;\n },\n },\n onUpdate: onUpdate ? ({ editor: current }) => onUpdate(current.getJSON()) : undefined,\n });\n\n const currentLinkHref = useCallback(\n () => (editor?.getAttributes('link').href as string | undefined) ?? '',\n [editor],\n );\n\n const openLink = useCallback(() => {\n if (editor) {\n const { from, to } = editor.state.selection;\n setLinkNeedsText(from === to && !editor.isActive('link'));\n }\n onInsertLink?.();\n }, [editor, onInsertLink]);\n\n const applyLink = useCallback(\n (href: string, text?: string) => {\n if (!editor) return;\n const url = href.trim();\n\n // Both branches below have to answer the same question: is this a\n // URL the document is allowed to point at? `setLink` refuses an\n // unsafe protocol (javascript:, data:, …) on its own, but the\n // no-selection branch builds the mark by hand and never reaches\n // that check — so an unsafe href used to land in the document JSON.\n // It stayed invisible in the editor, because Tiptap blanks a\n // disallowed href when it renders, and was handed to the consumer\n // intact through `onUpdate`.\n //\n // Asking the editor up front is what keeps the two paths honest,\n // and it reuses whatever `protocols` / `isAllowedUri` the consumer\n // configured on the Link extension rather than a second allowlist\n // of our own. An empty url is left to fall through: that is how a\n // link is removed.\n if (url && !editor.can().setLink({ href: url })) return;\n\n if (linkNeedsText) {\n // Nothing was selected, so there is no range to mark: insert the\n // text carrying the link in one transaction.\n if (url && text?.trim()) {\n editor\n .chain()\n .focus()\n .insertContent({\n type: 'text',\n text: text.trim(),\n marks: [{ type: 'link', attrs: { href: url } }],\n })\n .run();\n }\n return;\n }\n\n // extendMarkRange first: the caret may sit inside a link without a\n // selection, and without it only the character under it would change.\n if (url) editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run();\n else editor.chain().focus().extendMarkRange('link').unsetLink().run();\n },\n [editor, linkNeedsText],\n );\n\n const toolbar = useMemo(() => {\n const builtIn: ToolbarItem[] = [\n {\n kind: 'button',\n id: 'bold',\n icon: <Bold className='h-4 w-4' />,\n label: labels.bold,\n active: { name: 'bold' },\n run: (e) => e.chain().focus().toggleBold().run(),\n },\n {\n kind: 'button',\n id: 'italic',\n icon: <Italic className='h-4 w-4' />,\n label: labels.italic,\n active: { name: 'italic' },\n run: (e) => e.chain().focus().toggleItalic().run(),\n },\n {\n kind: 'button',\n id: 'heading',\n icon: <Heading2 className='h-4 w-4' />,\n label: labels.heading,\n active: { name: 'heading', attrs: { level: 2 } },\n run: (e) => e.chain().focus().toggleHeading({ level: 2 }).run(),\n },\n { kind: 'separator' },\n {\n kind: 'button',\n id: 'highlight',\n icon: <Highlighter className='h-4 w-4' />,\n label: labels.highlight,\n active: { name: 'highlight' },\n run: (e) => e.chain().focus().toggleHighlight().run(),\n },\n {\n kind: 'button',\n id: 'underline',\n icon: <Underline className='h-4 w-4' />,\n label: labels.underline,\n active: { name: 'underline' },\n run: (e) => e.chain().focus().toggleMark('underline').run(),\n },\n {\n kind: 'button',\n id: 'strike',\n icon: <Strikethrough className='h-4 w-4' />,\n label: labels.strikethrough,\n active: { name: 'strike' },\n run: (e) => e.chain().focus().toggleMark('strike').run(),\n },\n { kind: 'separator' },\n {\n kind: 'button',\n id: 'quote',\n icon: <Quote className='h-4 w-4' />,\n label: labels.quote,\n active: { name: 'blockquote' },\n run: (e) => e.chain().focus().toggleBlockquote().run(),\n },\n {\n kind: 'custom',\n id: 'lists',\n render: (current) => (\n <ListMenu\n editor={current}\n triggerLabel={labels.lists.trigger}\n icon={<List className='h-4 w-4' />}\n options={[\n {\n node: 'bulletList',\n label: labels.lists.bullet,\n icon: <List className='h-4 w-4' />,\n run: (e) => e.chain().focus().toggleBulletList().run(),\n },\n {\n node: 'orderedList',\n label: labels.lists.ordered,\n icon: <ListOrdered className='h-4 w-4' />,\n run: (e) => e.chain().focus().toggleOrderedList().run(),\n },\n ]}\n />\n ),\n },\n { kind: 'separator' },\n {\n kind: 'button',\n id: 'link',\n icon: <LinkIcon className='h-4 w-4' />,\n label: labels.insertLink,\n active: { name: 'link' },\n run: () => openLink(),\n },\n {\n kind: 'button',\n id: 'image',\n icon: <ImagePlus className='h-4 w-4' />,\n label: labels.insertImage,\n // No `active`: this opens a dialog, it is never a pressed state.\n run: () => onInsertImage?.(),\n },\n {\n kind: 'custom',\n id: 'table',\n render: (current) => (\n <TableMenu\n editor={current}\n icon={<TableIcon className='h-4 w-4' />}\n labels={labels.table}\n />\n ),\n },\n ];\n\n // Swap replaced entries first, so `after` anchors still resolve against\n // the same ids afterwards.\n let items = replaceToolbar\n ? builtIn.map((item) =>\n item.kind !== 'separator' && replaceToolbar[item.id]\n ? replaceToolbar[item.id]\n : item,\n )\n : builtIn;\n const appended: ToolbarItem[] = [];\n\n for (const group of extraToolbar) {\n if (!group.after) {\n appended.push(...group.items);\n continue;\n }\n const at = items.findIndex(\n (item) => item.kind !== 'separator' && item.id === group.after,\n );\n if (at === -1) {\n appended.push(...group.items);\n continue;\n }\n items = [...items.slice(0, at + 1), ...group.items, ...items.slice(at + 1)];\n }\n\n return [...items, ...appended];\n }, [labels, extraToolbar, replaceToolbar, onInsertImage, openLink]);\n\n const linkMenu = <LinkBubbleMenu editor={editor} labels={labels.link} onEdit={openLink} />;\n\n return { editor, toolbar, linkMenu, linkNeedsText, currentLinkHref, applyLink };\n}\n\nexport { useRichTextEditor };\nexport type { UseRichTextEditorOptions, UseRichTextEditorResult, RichTextEditorLabels };\n","'use client';\n\nimport type { Editor } from '@tiptap/react';\nimport type { ReactNode } from 'react';\n\nimport { Ban } from 'lucide-react';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/Button/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuTrigger,\n} from '@/components/ui/DropdownMenu/dropdown-menu';\n\n/**\n * One entry in the palette.\n *\n * `mark` is a mark name, not a colour value: a consumer's document contract\n * decides which marks exist, and a palette of named marks costs nothing to\n * validate server-side — unlike a mark carrying an arbitrary colour, which would\n * change the shape of every stored span.\n */\ninterface ColorSwatch {\n /** The Tiptap mark this swatch toggles, e.g. `colorPrimary`. */\n mark: string;\n /** Already translated name, used as the swatch's accessible label. */\n label: string;\n /** CSS colour for the swatch preview only. */\n preview: string;\n}\n\ninterface ColorMenuLabels {\n trigger: string;\n /** Heading above the swatches. */\n heading: string;\n /** Clears whichever colour mark is applied. */\n clear: string;\n}\n\ninterface ColorMenuProps {\n editor: Editor | null;\n labels: ColorMenuLabels;\n icon: ReactNode;\n swatches: ColorSwatch[];\n}\n\n/**\n * A palette dropdown that toggles one mark at a time.\n *\n * Deliberately not the design system's `ColorPicker`: a free picker offers\n * millions of values, and an editor whose authors can pick any colour produces\n * articles that no longer look like one publication. A short list of brand\n * shades is the constraint that keeps them consistent.\n */\nfunction ColorMenu({ editor, labels, icon, swatches }: ColorMenuProps) {\n const active = swatches.find((swatch) => editor?.isActive(swatch.mark));\n\n function apply(mark: string) {\n if (!editor) return;\n\n // Colours are mutually exclusive, so every other one is cleared first.\n // Two nested colour spans would leave the outer one dead weight, and the\n // author would have no way to tell which is winning.\n const chain = editor.chain().focus();\n for (const swatch of swatches) chain.unsetMark(swatch.mark);\n if (mark) chain.setMark(mark);\n chain.run();\n }\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type='button'\n size='sm'\n variant={active ? 'secondary' : 'ghost'}\n disabled={!editor}\n title={labels.trigger}\n aria-label={labels.trigger}\n data-slot='color-menu-trigger'>\n {icon}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align='start' className='w-auto'>\n {/* role='group' rather than menuitems: these are swatches, and a\n grid of buttons is not a menu in ARIA terms. */}\n <div\n role='group'\n aria-label={labels.heading}\n className='flex items-center gap-1.5 px-1.5 py-1'>\n {swatches.map((swatch) => (\n <button\n key={swatch.mark}\n type='button'\n aria-label={swatch.label}\n aria-pressed={editor?.isActive(swatch.mark) ?? false}\n title={swatch.label}\n style={{ backgroundColor: swatch.preview }}\n className={cn(\n 'h-7 w-7 cursor-pointer rounded-full border transition-transform',\n 'focus-visible:ring-ring/50 focus-visible:ring-2 focus-visible:outline-none',\n editor?.isActive(swatch.mark)\n ? 'border-primary scale-110 border-2'\n : 'border-border/60 hover:scale-110',\n )}\n onClick={() => apply(swatch.mark)}\n />\n ))}\n {/* Separated from the swatches: it is the absence of a colour,\n not one more choice. Without it an applied colour could\n only be undone by retyping the text. */}\n <span aria-hidden='true' className='bg-border mx-0.5 h-5 w-px' />\n <button\n type='button'\n aria-label={labels.clear}\n title={labels.clear}\n disabled={!active}\n className={cn(\n 'text-muted-foreground flex h-7 w-7 cursor-pointer items-center justify-center rounded-full',\n 'focus-visible:ring-ring/50 focus-visible:ring-2 focus-visible:outline-none',\n 'hover:text-foreground disabled:cursor-default disabled:opacity-40',\n )}\n onClick={() => apply('')}>\n <Ban className='h-4 w-4' />\n </button>\n </div>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport { ColorMenu };\nexport type { ColorMenuProps, ColorMenuLabels, ColorSwatch };\n","import { useId } from 'react';\n\nimport { Button } from '@/components/ui/Button/button';\nimport {\n Dialog,\n DialogContent,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/Dialog/dialog';\nimport { Input } from '@/components/ui/Input/input';\nimport { Label } from '@/components/ui/Label/label';\n\ninterface InsertLinkDialogLabels {\n title: string;\n urlLabel: string;\n urlPlaceholder: string;\n /** Explains that clearing the field removes an existing link. */\n hint: string;\n /** Field for the visible text, shown only when there is no selection to wrap. */\n textLabel: string;\n textPlaceholder: string;\n cancel: string;\n apply: string;\n}\n\ninterface InsertLinkDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n labels: InsertLinkDialogLabels;\n url: string;\n onUrlChange: (url: string) => void;\n /**\n * The visible text for a brand-new link. Pass these three together with\n * `needsText` when the editor has no selection to turn into a link — without\n * them the dialog can only re-point an existing one.\n */\n text?: string;\n onTextChange?: (text: string) => void;\n /**\n * True when there is nothing selected, so the link needs its own text.\n * Reveals the text field and requires it before applying.\n */\n needsText?: boolean;\n onApply: () => void;\n onCancel?: () => void;\n}\n\n/**\n * A controlled form for inserting or editing a link.\n *\n * Clearing the URL and applying is how a link is removed — the consumer decides\n * what that means for its document, so this dialog only reports the values.\n */\nfunction InsertLinkDialog({\n open,\n onOpenChange,\n labels,\n url,\n onUrlChange,\n text = '',\n onTextChange,\n needsText = false,\n onApply,\n onCancel,\n}: InsertLinkDialogProps) {\n const urlId = useId();\n const textId = useId();\n\n // With a selection, an empty URL is meaningful: it unsets the link. Without\n // one there is nothing to unset, so both fields have to carry a value or\n // applying would insert an empty anchor.\n const canApply = needsText ? Boolean(url.trim()) && Boolean(text.trim()) : true;\n\n function submitOnEnter(event: React.KeyboardEvent<HTMLInputElement>) {\n if (event.key === 'Enter' && canApply) {\n event.preventDefault();\n onApply();\n }\n }\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className='px-4 py-2' data-slot='insert-link-dialog'>\n <DialogHeader>\n <DialogTitle>{labels.title}</DialogTitle>\n </DialogHeader>\n <div className='mt-4 flex flex-col gap-3'>\n {needsText && onTextChange && (\n <div className='flex flex-col gap-1'>\n <Label htmlFor={textId}>{labels.textLabel}</Label>\n <Input\n id={textId}\n placeholder={labels.textPlaceholder}\n value={text}\n onChange={(event) => onTextChange(event.target.value)}\n onKeyDown={submitOnEnter}\n />\n </div>\n )}\n <div className='flex flex-col gap-1'>\n <Label htmlFor={urlId}>{labels.urlLabel}</Label>\n <Input\n id={urlId}\n placeholder={labels.urlPlaceholder}\n value={url}\n onChange={(event) => onUrlChange(event.target.value)}\n onKeyDown={submitOnEnter}\n />\n {!needsText && (\n <p className='text-muted-foreground text-xs'>{labels.hint}</p>\n )}\n </div>\n </div>\n <DialogFooter>\n <Button\n type='button'\n variant='outline'\n onClick={() => {\n if (onCancel) onCancel();\n else onOpenChange(false);\n }}>\n {labels.cancel}\n </Button>\n <Button type='button' onClick={onApply} disabled={!canApply}>\n {labels.apply}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport { InsertLinkDialog };\nexport type { InsertLinkDialogProps, InsertLinkDialogLabels };\n"]}
|