@texion/react 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +34 -2
- package/dist/RichMarkdownEditor-OAHLD4XC.js +9 -0
- package/dist/RichMarkdownEditor-OAHLD4XC.js.map +1 -0
- package/dist/chunk-JZO3KR6A.js +169 -0
- package/dist/chunk-JZO3KR6A.js.map +1 -0
- package/dist/chunk-LSFUTTAB.js +390 -0
- package/dist/chunk-LSFUTTAB.js.map +1 -0
- package/dist/chunk-T56S7VW3.js +52 -0
- package/dist/chunk-T56S7VW3.js.map +1 -0
- package/dist/csv-COGONMFA.js +36 -0
- package/dist/csv-COGONMFA.js.map +1 -0
- package/dist/image-TKOV52M6.js +61 -0
- package/dist/image-TKOV52M6.js.map +1 -0
- package/dist/index.d.ts +1126 -0
- package/dist/index.js +1304 -0
- package/dist/index.js.map +1 -0
- package/dist/json-BEWG6XTV.js +46 -0
- package/dist/json-BEWG6XTV.js.map +1 -0
- package/dist/markdown-QTRYMUXO.js +10 -0
- package/dist/markdown-QTRYMUXO.js.map +1 -0
- package/dist/markdown.d.ts +7 -0
- package/dist/markdown.js +9 -0
- package/dist/markdown.js.map +1 -0
- package/dist/rich.d.ts +7 -0
- package/dist/rich.js +8 -0
- package/dist/rich.js.map +1 -0
- package/dist/styles.css +243 -0
- package/dist/types-D4zTiC0I.d.ts +21 -0
- package/dist/types-DRXx1QAT.d.ts +10 -0
- package/package.json +77 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useTexion.ts","../src/controllers/attachments.ts","../src/dom/drop.ts","../src/dom/paste.ts","../src/dom/picker.ts","../src/controllers/presentation.ts","../src/hooks/useSourceInput.ts","../src/controllers/text.ts","../src/hooks/useDocument.ts","../src/components/TexionInput.tsx","../src/components/AttachmentList.tsx","../src/components/DocumentViewer.tsx","../src/renderers/registry.ts","../src/components/HighlightedTextarea.tsx","../src/hooks/useMarkdownInput.ts","../src/components/TexionViewer.tsx","../src/hooks/useTexionAttachments.ts","../src/components/TexionMessageViewer.tsx","../src/hooks/useOcrApproval.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport type { TextareaHTMLAttributes } from 'react';\nimport {\n createContent,\n isTextFormat,\n isTexionContent,\n createRegistry,\n} from '@texion/core';\nimport type {\n TexionContent,\n TexionDocument,\n ContentFormat,\n} from '@texion/core';\nimport type { RichMarkdownEditorProps } from '../editors/rich/RichMarkdownEditor';\nimport { useAttachmentController } from '../controllers/attachments';\nimport type { AttachmentOptions } from '../controllers/attachments';\nimport { useSourceInput } from './useSourceInput';\n\nexport interface Submission {\n readonly content: TexionContent;\n readonly attachments: readonly TexionDocument[];\n readonly text: string;\n readonly documents: readonly TexionDocument[];\n readonly textDocument?: TexionDocument;\n}\n\nexport interface UseTexionOptions extends AttachmentOptions {\n readonly defaultValue?: string;\n /** Portable text content used to initialize an editor. Remount to reopen another draft. */\n readonly defaultContent?: TexionContent;\n readonly format?: ContentFormat | 'auto';\n readonly formats?: readonly ContentFormat[];\n readonly highlight?: boolean;\n readonly maxHighlightCharacters?: number;\n readonly submitOnEnter?: boolean;\n readonly onSubmit?: (submission: Submission) => void | Promise<void>;\n}\n\nexport function useTexion(options: UseTexionOptions = {}) {\n const [adapters] = useState(() => createRegistry(options.adapters));\n if (\n options.formats &&\n (!options.formats.length ||\n options.formats.some(\n (format) => !adapters.some((adapter) => adapter.format === format),\n ))\n ) {\n throw new RangeError('Choose at least one registered format.');\n }\n if (\n options.defaultContent !== undefined &&\n !isTexionContent(options.defaultContent)\n ) {\n throw new TypeError('Invalid initial Texion content.');\n }\n const attachments = useAttachmentController(\n options.formats && !options.acceptedFormats\n ? { ...options, acceptedFormats: options.formats }\n : options,\n );\n const { controller, snapshot } = attachments;\n const submitting = useRef(false);\n const richComposing = useRef(false);\n const originalSource = useRef(\n options.defaultContent\n ? options.defaultContent.originalSource\n : options.defaultValue,\n );\n const [isSubmitting, setSubmitting] = useState(false);\n const [submitError, setSubmitError] = useState<string>();\n const preferredFormats = options.formats ?? [\n 'markdown',\n ...adapters.map((adapter) => adapter.format),\n ];\n const allowedSourceFormats = [...new Set(preferredFormats)].filter((format) =>\n adapters.some(\n (adapter) => adapter.kind !== 'binary' && adapter.format === format,\n ),\n );\n const allowedTextFormats = allowedSourceFormats.filter(isTextFormat);\n const defaultValue = options.defaultContent?.source ?? options.defaultValue;\n const input = useSourceInput({\n language: options.format ?? options.defaultContent?.format ?? 'auto',\n allowedFormats: allowedSourceFormats,\n adapters,\n ...(defaultValue === undefined ? {} : { defaultValue }),\n highlight: options.highlight ?? false,\n ...(options.maxHighlightCharacters === undefined\n ? {}\n : { maxHighlightCharacters: options.maxHighlightCharacters }),\n onChange: () => controller.remove('text'),\n submitOnEnter: options.submitOnEnter !== false,\n onSubmit: () => {\n void submit();\n },\n });\n useEffect(() => {\n const document = controller\n .getSnapshot()\n .documents.find((candidate) => candidate.id === 'text');\n if (document && document.format !== input.format) {\n controller.remove('text');\n }\n }, [controller, input.format]);\n const textDocument = snapshot.documents.find(\n (document) => document.id === 'text',\n );\n\n async function submit(): Promise<boolean> {\n if (input.isComposingNow() || richComposing.current || submitting.current) {\n return false;\n }\n const text = input.getValue();\n const format = input.getFormat();\n\n if (!text.trim() && !attachments.documents.length) {\n return false;\n }\n submitting.current = true;\n setSubmitting(true);\n setSubmitError(undefined);\n\n try {\n // Editing stays in its editor. Only requested processing enters the document lifecycle.\n controller.setText(text.trim() ? text : '', format);\n const captured = controller.getSnapshot().documents;\n const settled = await Promise.all(\n captured.map((document) => controller.whenSettled(document.id)),\n );\n const current = controller.getSnapshot().documents;\n\n const textChanged =\n input.getValue() !== text || input.getFormat() !== format;\n const hasUnreadyDocuments = settled.some(\n (document) => !document || document.status !== 'ready',\n );\n const documentsChanged =\n settled.length !== current.length ||\n settled.some((document, index) => document !== current[index]);\n\n if (textChanged || hasUnreadyDocuments || documentsChanged) {\n return false;\n }\n\n const primary = current.find((document) => document.id === 'text');\n const documents = Object.freeze(\n current.filter((document) => document.id !== 'text'),\n );\n await options.onSubmit?.({\n text,\n documents,\n attachments: documents,\n content: createContent(\n text,\n originalSource.current === undefined\n ? { format }\n : { format, originalSource: originalSource.current },\n ),\n ...(primary ? { textDocument: primary } : {}),\n });\n\n return true;\n } catch (error) {\n setSubmitError(\n error instanceof Error ? error.message : 'Submission failed.',\n );\n\n return false;\n } finally {\n submitting.current = false;\n setSubmitting(false);\n }\n }\n\n function getTextareaProps(\n props: TextareaHTMLAttributes<HTMLTextAreaElement> = {},\n ) {\n return input.getTextareaProps({\n ...props,\n onPaste(event) {\n props.onPaste?.(event);\n\n if (!input.isComposingNow()) {\n attachments.handlePaste(event);\n }\n },\n });\n }\n\n function getRichEditorProps(\n props: Partial<RichMarkdownEditorProps> = {},\n ): RichMarkdownEditorProps {\n if (input.format !== 'markdown') {\n throw new Error(\n 'Plain text, JSON and CSV use source editing; only Markdown supports rich conversion.',\n );\n }\n return {\n formats:\n options.format && options.format !== 'auto'\n ? [options.format].filter(isTextFormat)\n : (allowedTextFormats ?? ['markdown', 'json', 'csv']),\n ...props,\n value: input.value,\n onChange(source) {\n props.onChange?.(source);\n input.setValue(source);\n },\n onImport(source) {\n originalSource.current ??= source;\n props.onImport?.(source);\n },\n onCompositionChange(composing) {\n richComposing.current = composing;\n props.onCompositionChange?.(composing);\n },\n onSubmit() {\n props.onSubmit?.();\n void submit();\n },\n submitOnEnter: options.submitOnEnter ?? false,\n ...(options.attachments === false\n ? {}\n : {\n onFiles(files: readonly File[]) {\n files.forEach(attachments.addDocument);\n props.onFiles?.(files);\n },\n }),\n };\n }\n\n return {\n content: createContent(\n input.value,\n originalSource.current === undefined\n ? { format: input.format }\n : { format: input.format, originalSource: originalSource.current },\n ),\n format: input.format,\n warnings: input.warnings,\n getRichEditorProps,\n text: input.value,\n textDocument,\n selection: input.selection,\n isComposing: input.isComposing,\n highlightModel: input.highlightModel,\n documents: attachments.documents,\n isDragging: attachments.isDragging,\n isSubmitting,\n inputError: attachments.inputError,\n submitError,\n setText: input.setValue,\n addDocument: attachments.addDocument,\n removeDocument: controller.remove,\n cancelDocument: controller.cancel,\n clear() {\n input.setValue('');\n originalSource.current = undefined;\n richComposing.current = false;\n controller.clear();\n },\n submit,\n openPicker: attachments.openPicker,\n getRootProps: attachments.getRootProps,\n getTextareaProps,\n getInputProps: attachments.getInputProps,\n };\n}\n","import {\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\nimport type {\n ChangeEvent,\n ClipboardEvent,\n HTMLAttributes,\n InputHTMLAttributes,\n} from 'react';\nimport { createController } from '@texion/core';\nimport type { ControllerOptions, DocumentInput } from '@texion/core';\nimport { filesFromDrop, isFileDrag } from '../dom/drop';\nimport { readClipboard } from '../dom/paste';\nimport { acceptForFormats, takeFiles } from '../dom/picker';\nimport { defaultPasteThreshold } from './presentation';\n\nexport interface AttachmentOptions extends ControllerOptions {\n readonly attachments?: boolean;\n /** Inputs resolved by the host when reopening a saved message. Read on mount. */\n readonly initialAttachments?: readonly DocumentInput[];\n readonly pasteAsAttachment?: boolean;\n readonly pasteAttachmentThreshold?: number;\n}\n\nexport function useAttachmentController(options: AttachmentOptions) {\n const [controller] = useState(() => createController(options));\n const snapshot = useSyncExternalStore(\n controller.subscribe,\n controller.getSnapshot,\n controller.getSnapshot,\n );\n const documents = useMemo(\n () =>\n Object.freeze(\n snapshot.documents.filter((document) => document.id !== 'text'),\n ),\n [snapshot],\n );\n const inputRef = useRef<HTMLInputElement>(null);\n const dragDepth = useRef(0);\n const [isDragging, setDragging] = useState(false);\n const [inputError, setInputError] = useState<string>();\n const initialAttachments = useRef([...(options.initialAttachments ?? [])]);\n useEffect(() => {\n initialAttachments.current.forEach(addDocument);\n return () => controller.clear();\n }, [controller]);\n const enabled = options.attachments !== false;\n\n function addDocument(input: DocumentInput) {\n return controller.add(\n typeof input === 'string'\n ? { text: input, source: 'paste', name: 'Pasted Markdown' }\n : input,\n );\n }\n\n function getRootProps(\n props: HTMLAttributes<HTMLDivElement> = {},\n ): HTMLAttributes<HTMLDivElement> {\n return {\n ...props,\n 'data-dragging': isDragging || undefined,\n onDragEnter(event) {\n props.onDragEnter?.(event);\n\n if (\n !event.defaultPrevented &&\n enabled &&\n isFileDrag(event.dataTransfer)\n ) {\n event.preventDefault();\n dragDepth.current++;\n setDragging(true);\n }\n },\n onDragOver(event) {\n props.onDragOver?.(event);\n\n if (\n !event.defaultPrevented &&\n enabled &&\n isFileDrag(event.dataTransfer)\n ) {\n event.preventDefault();\n }\n },\n onDragLeave(event) {\n props.onDragLeave?.(event);\n\n if (enabled && isFileDrag(event.dataTransfer)) {\n dragDepth.current = Math.max(0, dragDepth.current - 1);\n\n if (!dragDepth.current) {\n setDragging(false);\n }\n }\n },\n onDrop(event) {\n props.onDrop?.(event);\n dragDepth.current = 0;\n setDragging(false);\n\n if (\n event.defaultPrevented ||\n !enabled ||\n !isFileDrag(event.dataTransfer)\n ) {\n return;\n }\n event.preventDefault();\n const result = filesFromDrop(event.dataTransfer);\n setInputError(\n result.hasFolders\n ? 'Folders are not supported. Select individual supported files.'\n : undefined,\n );\n result.files.forEach(addDocument);\n },\n } as HTMLAttributes<HTMLDivElement>;\n }\n\n function getInputProps(props: InputHTMLAttributes<HTMLInputElement> = {}) {\n return {\n ...props,\n ref: inputRef,\n type: 'file' as const,\n multiple: true,\n accept:\n props.accept ??\n acceptForFormats(\n options.acceptedFormats ??\n options.adapters?.map((adapter) => adapter.format),\n options.adapters,\n ),\n disabled: !enabled || props.disabled,\n onChange(event: ChangeEvent<HTMLInputElement>) {\n props.onChange?.(event);\n const files = takeFiles(event.currentTarget);\n\n if (enabled && !event.defaultPrevented) {\n files.forEach(addDocument);\n }\n },\n };\n }\n\n function handlePaste(event: ClipboardEvent<HTMLTextAreaElement>) {\n if (event.defaultPrevented || !enabled) {\n return;\n }\n const clipboard = readClipboard(\n event.clipboardData,\n options.pasteAsAttachment\n ? (options.pasteAttachmentThreshold ?? defaultPasteThreshold)\n : undefined,\n );\n\n if (clipboard.files.length || clipboard.attachmentText !== undefined) {\n event.preventDefault();\n clipboard.files.forEach(addDocument);\n\n if (clipboard.attachmentText !== undefined) {\n addDocument(clipboard.attachmentText);\n }\n }\n }\n\n return {\n controller,\n snapshot,\n documents,\n isDragging,\n inputError,\n addDocument,\n getRootProps,\n getInputProps,\n handlePaste,\n openPicker: () => inputRef.current?.click(),\n };\n}\n","export function isFileDrag(transfer: DataTransfer): boolean {\n return Array.from(transfer.types).includes('Files');\n}\n\nexport function filesFromDrop(transfer: DataTransfer): {\n files: File[];\n hasFolders: boolean;\n} {\n const items = Array.from(transfer.items ?? []);\n const hasFolders = items.some(\n (item) => item.webkitGetAsEntry?.()?.isDirectory,\n );\n const files = items.length\n ? items.flatMap((item) => {\n if (item.webkitGetAsEntry?.()?.isDirectory) {\n return [];\n }\n const file = item.getAsFile();\n\n return file ? [file] : [];\n })\n : Array.from(transfer.files);\n\n return { files, hasFolders };\n}\n","import { detectMarkdown } from '@texion/core';\n\nexport function readClipboard(\n clipboard: DataTransfer,\n threshold?: number,\n): { files: File[]; attachmentText?: string } {\n const files = Array.from(clipboard.files ?? []);\n\n if (files.length) {\n return { files };\n }\n if (threshold === undefined) {\n return { files };\n }\n const text = clipboard.getData('text/plain');\n\n return threshold !== undefined &&\n text.length >= threshold &&\n detectMarkdown(text)\n ? { files, attachmentText: text }\n : { files };\n}\n","import type { FormatAdapter } from '@texion/core';\nexport const markdownAccept =\n '.md,.markdown,.mdown,.mkd,text/markdown,text/x-markdown';\nconst accepted: Readonly<Record<string, string>> = {\n markdown: markdownAccept,\n text: '.txt,text/plain',\n pdf: '.pdf,application/pdf',\n docx: '.docx,application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n json: '.json,application/json,text/json',\n csv: '.csv,text/csv,application/csv',\n image: '.png,.jpg,.jpeg,.gif,.webp,image/png,image/jpeg,image/gif,image/webp',\n};\nexport function acceptForFormats(\n formats: readonly string[] = Object.keys(accepted),\n adapters?: readonly FormatAdapter[],\n): string {\n if (adapters)\n return adapters\n .filter((adapter) => formats.includes(adapter.format))\n .flatMap((adapter) => [\n ...adapter.extensions.map((extension) => `.${extension}`),\n ...adapter.mimeTypes,\n ])\n .join(',');\n return formats.flatMap((format) => accepted[format] ?? []).join(',');\n}\nexport function takeFiles(input: HTMLInputElement): File[] {\n const files = Array.from(input.files ?? []);\n input.value = '';\n return files;\n}\n","export const defaultHighlightLimit = 20_000;\n\nexport const defaultPasteThreshold = 10_000;\n","import { useMemo, useRef, useState } from 'react';\nimport type { TextareaHTMLAttributes } from 'react';\nimport {\n createHighlightModel,\n defaultHighlightLimits,\n sourceWarnings,\n detectTextFormat,\n isTextFormat,\n} from '@texion/core';\nimport type { ContentFormat, FormatAdapter } from '@texion/core';\nimport { shouldSubmit } from '../controllers/text';\n\nexport interface UseSourceInputOptions {\n readonly value?: string;\n readonly defaultValue?: string;\n readonly onChange?: (value: string) => void;\n readonly language?: ContentFormat | 'auto';\n readonly allowedFormats?: readonly ContentFormat[];\n readonly adapters?: readonly FormatAdapter[];\n readonly highlight?: boolean;\n readonly maxHighlightCharacters?: number;\n readonly submitOnEnter?: boolean;\n readonly onSubmit?: () => void;\n}\n\nexport interface TextSelection {\n readonly start: number;\n readonly end: number;\n readonly direction: 'forward' | 'backward' | 'none';\n}\n\n// HTML textarea values normalize line endings; token offsets must use that same string.\nconst nativeValue = (value: string) => value.replace(/\\r\\n?/g, '\\n');\n\nexport function useSourceInput(options: UseSourceInputOptions = {}) {\n const [internalValue, setInternalValue] = useState(\n nativeValue(options.defaultValue ?? ''),\n );\n const value = nativeValue(options.value ?? internalValue);\n const valueRef = useRef(value);\n valueRef.current = value;\n const composing = useRef(false);\n const [isComposing, setComposing] = useState(false);\n const [selection, setSelection] = useState<TextSelection>({\n start: 0,\n end: 0,\n direction: 'none',\n });\n const maxCharacters =\n options.maxHighlightCharacters ?? defaultHighlightLimits.maxCharacters;\n const highlight = options.highlight !== false && !isComposing;\n const language = options.language ?? 'markdown';\n const getFormat = () =>\n language === 'auto'\n ? detectTextFormat(\n valueRef.current,\n options.allowedFormats,\n options.adapters ?? [],\n )\n : language;\n const format = getFormat();\n const warnings = useMemo(\n () => (isComposing ? [] : sourceWarnings(value, format, maxCharacters)),\n [value, format, maxCharacters, isComposing],\n );\n const highlightModel = useMemo(\n () =>\n createHighlightModel(value, {\n enabled: highlight,\n maxCharacters,\n format: isTextFormat(format) ? format : 'text',\n }),\n [value, highlight, maxCharacters, format],\n );\n\n function setValue(next: string) {\n next = nativeValue(next);\n\n if (next === valueRef.current) {\n return;\n }\n valueRef.current = next;\n\n if (options.value === undefined) {\n setInternalValue(next);\n }\n options.onChange?.(next);\n }\n\n function readSelection(element: HTMLTextAreaElement) {\n const next = {\n start: element.selectionStart,\n end: element.selectionEnd,\n direction: element.selectionDirection,\n };\n setSelection((previous) =>\n previous.start === next.start &&\n previous.end === next.end &&\n previous.direction === next.direction\n ? previous\n : next,\n );\n }\n\n function getTextareaProps(\n props: TextareaHTMLAttributes<HTMLTextAreaElement> = {},\n ): TextareaHTMLAttributes<HTMLTextAreaElement> {\n return {\n ...props,\n value,\n onChange(event) {\n props.onChange?.(event);\n\n if (!event.defaultPrevented) {\n setValue(event.currentTarget.value);\n }\n readSelection(event.currentTarget);\n },\n onSelect(event) {\n props.onSelect?.(event);\n readSelection(event.currentTarget);\n },\n onCompositionStart(event) {\n composing.current = true;\n setComposing(true);\n props.onCompositionStart?.(event);\n },\n onCompositionEnd(event) {\n composing.current = false;\n setComposing(false);\n\n if (event.currentTarget.value !== valueRef.current) {\n setValue(event.currentTarget.value);\n }\n props.onCompositionEnd?.(event);\n },\n onKeyDown(event) {\n props.onKeyDown?.(event);\n\n if (\n !event.defaultPrevented &&\n options.onSubmit &&\n options.submitOnEnter &&\n shouldSubmit(event, composing.current)\n ) {\n event.preventDefault();\n options.onSubmit();\n }\n },\n };\n }\n\n return {\n value,\n format,\n getFormat,\n warnings,\n setValue,\n selection,\n isComposing,\n isComposingNow: () => composing.current,\n getValue: () => valueRef.current,\n highlightModel,\n getTextareaProps,\n };\n}\n","import type { KeyboardEvent } from 'react';\n\nexport function shouldSubmit(\n event: KeyboardEvent<HTMLTextAreaElement>,\n composing: boolean,\n): boolean {\n return (\n event.key === 'Enter' &&\n !event.shiftKey &&\n !event.ctrlKey &&\n !event.altKey &&\n !event.metaKey &&\n !composing &&\n !event.nativeEvent.isComposing &&\n event.nativeEvent.keyCode !== 229\n );\n}\n","import { useEffect, useState, useSyncExternalStore } from 'react';\nimport { createController } from '@texion/core';\nimport type { ControllerOptions, DocumentInput } from '@texion/core';\n\nexport function useDocument(\n input?: DocumentInput,\n options: ControllerOptions = {},\n) {\n const [controller] = useState(() => createController(options));\n const [current, setCurrent] = useState<{\n input: DocumentInput;\n id: string;\n }>();\n const snapshot = useSyncExternalStore(\n controller.subscribe,\n controller.getSnapshot,\n controller.getSnapshot,\n );\n useEffect(() => {\n if (input === undefined) {\n setCurrent(undefined);\n\n return;\n }\n\n const id = controller.add(input);\n setCurrent({ input, id });\n\n return () => {\n controller.remove(id);\n };\n }, [controller, input]);\n\n return current?.input === input\n ? snapshot.documents.find((document) => document.id === current?.id)\n : undefined;\n}\n","import type { RendererRegistry } from '../renderers/types';\nimport { isTextFormat } from '@texion/core';\nimport { Suspense, lazy, useEffect, useId, useState } from 'react';\nimport type { UseTexionOptions } from '../hooks/useTexion';\nimport { useTexion } from '../hooks/useTexion';\nimport { AttachmentList } from './AttachmentList';\nimport { DocumentViewer } from './DocumentViewer';\nimport { HighlightedTextareaSurface } from './HighlightedTextarea';\n\nconst RichEditor = lazy(() => import('../editors/rich/RichMarkdownEditor'));\n\nexport interface TexionInputProps extends UseTexionOptions {\n readonly placeholder?: string;\n readonly renderers?: RendererRegistry;\n readonly label?: string;\n readonly preview?: boolean;\n /** Show local image previews automatically as attachments become ready. */\n readonly previewImages?: boolean;\n /** Initial placement of previews, attachments and input feedback. */\n readonly previewPosition?: 'above' | 'below';\n readonly className?: string;\n readonly mode?: 'source' | 'rich';\n readonly live?: boolean;\n readonly modeSwitch?: boolean;\n readonly submitLabel?: string;\n readonly maxRichCharacters?: number;\n}\n\nexport function TexionInput({\n placeholder = 'Drop a file, paste, or write…',\n renderers,\n label = 'Message',\n preview = false,\n previewImages = false,\n previewPosition = 'above',\n className = 'texion-input',\n mode = 'source',\n live = true,\n modeSwitch = mode === 'rich',\n submitLabel = 'Submit',\n maxRichCharacters = 50_000,\n ...options\n}: TexionInputProps) {\n const [position, setPosition] = useState(previewPosition);\n useEffect(() => setPosition(previewPosition), [previewPosition]);\n const [editorMode, setEditorMode] = useState(mode);\n useEffect(() => setEditorMode(mode), [mode]);\n const texion = useTexion({\n ...options,\n format:\n options.format ??\n options.defaultContent?.format ??\n (editorMode === 'rich' ? 'markdown' : 'auto'),\n highlight: editorMode === 'source' && !!options.highlight,\n });\n const canUseRich = texion.format === 'markdown';\n const id = useId();\n const [previewId, setPreviewId] = useState<string>();\n const [showTextPreview, setShowTextPreview] = useState(false);\n const [showImagePreviews, setShowImagePreviews] = useState(previewImages);\n useEffect(() => setShowImagePreviews(previewImages), [previewImages]);\n const images = texion.documents.filter(\n (document) => document.format === 'image' && document.status === 'ready',\n );\n const selected = texion.documents.find(\n (document) => document.id === previewId,\n );\n\n const previews = (\n <div className=\"texion-input-previews\">\n {texion.warnings.map((warning, index) => (\n <p role=\"status\" key={index}>\n {warning.message}\n </p>\n ))}\n {texion.textDocument?.error && (\n <p role=\"alert\">{texion.textDocument.error.message}</p>\n )}\n {preview && !!texion.text.trim() && (\n <button\n type=\"button\"\n aria-expanded={showTextPreview}\n onClick={() => setShowTextPreview((value) => !value)}\n >\n {showTextPreview ? 'Hide message preview' : 'Preview message'}\n </button>\n )}\n {preview && showTextPreview && !!texion.text.trim() && (\n <DocumentViewer\n format={texion.format}\n content={texion.text}\n options={\n options.formats && !options.acceptedFormats\n ? { ...options, acceptedFormats: options.formats }\n : options\n }\n {...(renderers ? { renderers } : {})}\n />\n )}\n {texion.isDragging && <p role=\"status\">Drop supported files here</p>}\n {texion.inputError && <p role=\"alert\">{texion.inputError}</p>}\n {images.length > 0 && (\n <label>\n <input\n type=\"checkbox\"\n checked={showImagePreviews}\n onChange={(event) => {\n setShowImagePreviews(event.currentTarget.checked);\n setPreviewId(undefined);\n }}\n />\n Show image previews\n </label>\n )}\n <AttachmentList\n documents={texion.documents}\n onRemove={texion.removeDocument}\n onCancel={texion.cancelDocument}\n onPreview={preview ? setPreviewId : undefined}\n />\n {showImagePreviews &&\n images.map((document) => (\n <DocumentViewer\n key={document.id}\n document={document}\n {...(renderers ? { renderers } : {})}\n />\n ))}\n {preview &&\n selected &&\n !(showImagePreviews && selected.format === 'image') && (\n <>\n <button type=\"button\" onClick={() => setPreviewId(undefined)}>\n Close preview\n </button>\n <DocumentViewer\n document={selected}\n {...(renderers ? { renderers } : {})}\n />\n </>\n )}\n </div>\n );\n\n return (\n <div {...texion.getRootProps({ className })}>\n <label>\n Preview position\n <select\n value={position}\n onChange={(event) =>\n setPosition(event.currentTarget.value as 'above' | 'below')\n }\n >\n <option value=\"above\">Above input</option>\n <option value=\"below\">Below input</option>\n </select>\n </label>\n {position === 'above' && previews}\n <label htmlFor={id}>{label}</label>\n {modeSwitch && canUseRich && (\n <button\n type=\"button\"\n onClick={() =>\n setEditorMode((value) => (value === 'rich' ? 'source' : 'rich'))\n }\n >\n {editorMode === 'rich' ? 'Edit Markdown source' : 'Edit rich content'}\n </button>\n )}\n {editorMode === 'rich' && canUseRich ? (\n <Suspense fallback={<p role=\"status\">Loading rich editor…</p>}>\n <RichEditor\n {...texion.getRichEditorProps({\n formats:\n options.format && options.format !== 'auto'\n ? [options.format].filter(isTextFormat)\n : (options.formats?.filter(isTextFormat) ?? [\n 'markdown',\n 'json',\n 'csv',\n ]),\n id,\n label,\n placeholder,\n live,\n maxCharacters: maxRichCharacters,\n onRequestSource: () => setEditorMode('source'),\n })}\n />\n </Suspense>\n ) : (\n <HighlightedTextareaSurface\n textareaProps={texion.getTextareaProps({ id, placeholder })}\n model={texion.highlightModel}\n />\n )}\n {position === 'below' && previews}\n {options.attachments !== false && (\n <>\n <input\n {...texion.getInputProps({\n hidden: true,\n 'aria-label': 'Choose files',\n })}\n />\n <button type=\"button\" onClick={texion.openPicker}>\n Attach files\n </button>\n </>\n )}\n {texion.submitError && <p role=\"alert\">{texion.submitError}</p>}\n <button\n type=\"button\"\n onClick={() => {\n void texion.submit();\n }}\n disabled={texion.isSubmitting}\n >\n {texion.isSubmitting ? 'Submitting…' : submitLabel}\n </button>\n </div>\n );\n}\n","import type { TexionDocument } from '@texion/core';\n\nexport interface AttachmentListProps {\n readonly documents: readonly TexionDocument[];\n readonly onCancel?: (id: string) => void;\n readonly onRemove: (id: string) => void;\n readonly onPreview?: ((id: string) => void) | undefined;\n}\n\nexport function AttachmentList({\n documents,\n onRemove,\n onCancel,\n onPreview,\n}: AttachmentListProps) {\n if (!documents.length) {\n return null;\n }\n return (\n <ul className=\"texion-attachments\" aria-label=\"Attachments\">\n {documents.map((document) => (\n <li key={document.id}>\n <span>{document.name}</span>{' '}\n <span role=\"status\">{document.status}</span>\n {document.status === 'processing' && document.progress && (\n <span className=\"texion-document-progress\" role=\"status\">\n {document.progress.phase === 'pending-consent'\n ? 'Waiting for OCR approval'\n : document.progress.phase === 'initializing-ocr'\n ? 'Loading OCR engine'\n : document.progress.phase === 'ocr'\n ? `Recognizing page ${document.progress.pageNumber ?? document.progress.done + 1} · ${document.progress.done}/${document.progress.total} complete`\n : `Extracting page ${document.progress.done} of ${document.progress.total}`}\n <progress\n aria-label={`Processing ${document.name}`}\n value={document.progress.done}\n max={Math.max(1, document.progress.total)}\n />\n </span>\n )}\n {document.error && <span role=\"alert\">{document.error.message}</span>}\n {document.warnings.map((warning, i) => (\n <span role=\"status\" key={i}>\n {warning.message}\n </span>\n ))}\n {onPreview && document.status === 'ready' && (\n <button\n type=\"button\"\n onClick={() => onPreview(document.id)}\n aria-label={`Preview ${document.name}`}\n >\n Preview\n </button>\n )}\n {onCancel &&\n (document.status === 'pending' ||\n document.status === 'processing') && (\n <button\n type=\"button\"\n onClick={() => onCancel(document.id)}\n aria-label={`Cancel ${document.name}`}\n >\n Cancel\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => onRemove(document.id)}\n aria-label={`Remove ${document.name}`}\n >\n Remove\n </button>\n </li>\n ))}\n </ul>\n );\n}\n","import { Suspense, useMemo } from 'react';\nimport type { ComponentType } from 'react';\nimport type {\n ControllerOptions,\n DocumentInput,\n TexionDocument,\n ContentFormat,\n} from '@texion/core';\nimport { useDocument } from '../hooks/useDocument';\nimport { defaultRenderer } from '../renderers/registry';\nimport type {\n PreviewRendererProps,\n RendererRegistry,\n} from '../renderers/types';\n\nexport interface DocumentViewerProps {\n readonly document?: TexionDocument;\n readonly input?: DocumentInput;\n readonly content?: string;\n readonly format?: ContentFormat;\n readonly options?: ControllerOptions;\n readonly className?: string;\n readonly renderer?: ComponentType<PreviewRendererProps>;\n readonly renderers?: RendererRegistry;\n}\n\nexport function DocumentViewer({\n document: supplied,\n input,\n content,\n format,\n options,\n className,\n renderer,\n renderers,\n}: DocumentViewerProps) {\n const documentInput = useMemo(() => {\n const value = input ?? content;\n if (typeof value === 'string' && format) {\n return { text: value, format };\n }\n if (\n value &&\n typeof value === 'object' &&\n 'text' in value &&\n typeof value.text === 'string' &&\n format\n ) {\n return { ...value, format };\n }\n return value;\n }, [input, content, format]);\n const processed = useDocument(supplied ? undefined : documentInput, options);\n const document = supplied ?? processed;\n const Renderer =\n renderer ??\n (document ? renderers?.[document.format] : undefined) ??\n defaultRenderer(document?.format);\n const preview = useMemo(\n () => (document?.status === 'ready' ? document.getPreview?.() : undefined),\n [document],\n );\n\n if (document?.status === 'error') {\n return <p role=\"alert\">{document.error?.message}</p>;\n }\n if (!document || document.status !== 'ready') {\n return <p role=\"status\">Preparing document…</p>;\n }\n return (\n <section\n className={className ?? 'texion-viewer'}\n aria-label={`Preview of ${document.name}`}\n >\n {document.warnings.map((warning, i) => (\n <p role=\"status\" key={i}>\n {warning.message}\n </p>\n ))}\n {preview?.warnings\n .filter(\n (warning) =>\n !document.warnings.some(\n (existing) =>\n existing.code === warning.code &&\n existing.message === warning.message,\n ),\n )\n .map((warning, i) => (\n <p role=\"status\" key={i}>\n {warning.message}\n </p>\n ))}\n {preview && (\n <Suspense fallback={<p role=\"status\">Loading preview…</p>}>\n <Renderer preview={preview} document={document} />\n </Suspense>\n )}\n </section>\n );\n}\n","import { lazy } from 'react';\n\nexport const DefaultMarkdownRenderer = lazy(() => import('./markdown'));\nconst JsonRenderer = lazy(() => import('./json'));\nconst CsvRenderer = lazy(() => import('./csv'));\nconst ImageRenderer = lazy(() => import('./image'));\nexport function defaultRenderer(format?: string) {\n switch (format) {\n case 'json':\n return JsonRenderer;\n case 'csv':\n return CsvRenderer;\n case 'image':\n return ImageRenderer;\n default:\n return DefaultMarkdownRenderer;\n }\n}\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport type { CSSProperties, TextareaHTMLAttributes } from 'react';\nimport type { HighlightModel, TextFormat } from '@texion/core';\nimport { useSourceInput } from '../hooks/useSourceInput';\nimport { HighlightOverlay } from '../rendering/HighlightOverlay';\n\nconst useClientLayoutEffect =\n typeof window === 'undefined' ? useEffect : useLayoutEffect;\n\nconst mirrorProperties = [\n 'fontFamily',\n 'fontSize',\n 'fontWeight',\n 'fontStyle',\n 'fontVariant',\n 'fontStretch',\n 'fontKerning',\n 'fontFeatureSettings',\n 'fontVariationSettings',\n 'fontVariantLigatures',\n 'lineHeight',\n 'letterSpacing',\n 'wordSpacing',\n 'textAlign',\n 'textIndent',\n 'textTransform',\n 'textRendering',\n 'tabSize',\n 'direction',\n 'unicodeBidi',\n 'writingMode',\n 'paddingTop',\n 'paddingRight',\n 'paddingBottom',\n 'paddingLeft',\n 'color',\n 'wordBreak',\n 'overflowWrap',\n 'lineBreak',\n] as const;\n\ninterface Layout {\n readonly left: number;\n readonly top: number;\n readonly width: number;\n readonly height: number;\n readonly content: CSSProperties;\n}\n\ninterface SurfaceProps {\n readonly textareaProps: TextareaHTMLAttributes<HTMLTextAreaElement>;\n readonly model: HighlightModel;\n readonly wrapperClassName?: string | undefined;\n}\n\n/** Shared presentation only; both public components use the same native text controller. */\nexport const HighlightedTextareaSurface = forwardRef<\n HTMLTextAreaElement,\n SurfaceProps\n>(function HighlightedTextareaSurface(\n { textareaProps, model, wrapperClassName },\n forwardedRef,\n) {\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n const viewportRef = useRef<HTMLDivElement>(null);\n const [layout, setLayout] = useState<Layout>();\n const [forcedColors, setForcedColors] = useState(false);\n const value = String(textareaProps.value ?? '');\n const requested =\n model.enabled && !!value && model.text === value && !forcedColors;\n const syncScroll = useCallback(() => {\n const textarea = textareaRef.current;\n\n if (textarea && viewportRef.current) {\n viewportRef.current.scrollTop = textarea.scrollTop;\n viewportRef.current.scrollLeft = textarea.scrollLeft;\n }\n }, []);\n const synchronize = useCallback(() => {\n const textarea = textareaRef.current;\n const view = textarea?.ownerDocument.defaultView;\n\n if (!textarea || !view) {\n return;\n }\n const computed = view.getComputedStyle(textarea);\n const content: CSSProperties = {\n ...Object.fromEntries(\n mirrorProperties.map((property) => [property, computed[property]]),\n ),\n boxSizing: 'border-box',\n margin: 0,\n border: 0,\n width: textarea.clientWidth,\n minHeight: textarea.clientHeight,\n whiteSpace: textarea.wrap === 'off' ? 'pre' : 'pre-wrap',\n WebkitTextFillColor: 'currentColor',\n };\n const next = {\n left: textarea.offsetLeft + textarea.clientLeft,\n top: textarea.offsetTop + textarea.clientTop,\n width: textarea.clientWidth,\n height: textarea.clientHeight,\n content,\n };\n setLayout((previous) =>\n JSON.stringify(previous) === JSON.stringify(next) ? previous : next,\n );\n syncScroll();\n }, [syncScroll]);\n useClientLayoutEffect(() => {\n if (requested) {\n synchronize();\n }\n });\n useClientLayoutEffect(() => {\n if (!requested) {\n return;\n }\n const textarea = textareaRef.current;\n const view = textarea?.ownerDocument.defaultView;\n\n if (!textarea || !view) {\n return;\n }\n let mounted = true;\n const refresh = () => {\n if (mounted) {\n synchronize();\n }\n };\n const resize =\n typeof ResizeObserver === 'undefined'\n ? undefined\n : new ResizeObserver(refresh);\n resize?.observe(textarea);\n\n if (textarea.parentElement) {\n resize?.observe(textarea.parentElement);\n }\n const mutation = new MutationObserver(refresh);\n\n for (\n let element: HTMLElement | null = textarea;\n element;\n element = element.parentElement\n ) {\n mutation.observe(element, {\n attributes: true,\n attributeFilter: ['style', 'class', 'dir', 'wrap'],\n });\n }\n view.addEventListener('resize', refresh);\n const fonts = textarea.ownerDocument.fonts;\n void fonts?.ready.then(refresh);\n fonts?.addEventListener('loadingdone', refresh);\n\n return () => {\n mounted = false;\n resize?.disconnect();\n mutation.disconnect();\n view.removeEventListener('resize', refresh);\n fonts?.removeEventListener('loadingdone', refresh);\n };\n }, [requested, synchronize]);\n useEffect(() => {\n const media = textareaRef.current?.ownerDocument.defaultView?.matchMedia?.(\n '(forced-colors: active)',\n );\n\n if (!media) {\n return;\n }\n const update = () => setForcedColors(media.matches);\n update();\n media.addEventListener('change', update);\n\n return () => media.removeEventListener('change', update);\n }, []);\n const active = requested && !!layout;\n\n return (\n <div\n className={['texion-highlighted-textarea', wrapperClassName]\n .filter(Boolean)\n .join(' ')}\n data-highlighted={active || undefined}\n data-highlight-reason={model.reason}\n style={{ position: 'relative', display: 'grid', minWidth: 0 }}\n >\n <textarea\n {...textareaProps}\n ref={(node) => {\n textareaRef.current = node;\n\n if (typeof forwardedRef === 'function') {\n forwardedRef(node);\n } else if (forwardedRef) {\n forwardedRef.current = node;\n }\n }}\n style={{\n display: 'block',\n boxSizing: 'border-box',\n minWidth: 0,\n width: '100%',\n ...textareaProps.style,\n ...(active\n ? { WebkitTextFillColor: 'transparent', caretColor: 'currentColor' }\n : {}),\n }}\n onScroll={(event) => {\n syncScroll();\n textareaProps.onScroll?.(event);\n }}\n />\n {active && (\n <div\n ref={viewportRef}\n data-texion-overlay-viewport=\"\"\n aria-hidden=\"true\"\n style={{\n position: 'absolute',\n pointerEvents: 'none',\n userSelect: 'none',\n overflow: 'hidden',\n direction: layout.content.direction,\n left: layout.left,\n top: layout.top,\n width: layout.width,\n height: layout.height,\n }}\n >\n <HighlightOverlay model={model} style={layout.content} />\n </div>\n )}\n </div>\n );\n});\n\nexport interface HighlightedTextareaProps extends Omit<\n TextareaHTMLAttributes<HTMLTextAreaElement>,\n 'value' | 'defaultValue' | 'onChange' | 'children'\n> {\n readonly value?: string;\n readonly defaultValue?: string;\n readonly onChange?: (value: string) => void;\n readonly language?: TextFormat;\n readonly highlight?: boolean;\n readonly maxHighlightCharacters?: number;\n readonly wrapperClassName?: string;\n}\n\nexport const HighlightedTextarea = forwardRef<\n HTMLTextAreaElement,\n HighlightedTextareaProps\n>(function HighlightedTextarea(\n {\n value,\n defaultValue,\n onChange,\n language = 'markdown',\n highlight = true,\n maxHighlightCharacters,\n wrapperClassName,\n ...props\n },\n ref,\n) {\n const input = useSourceInput({\n language,\n highlight,\n ...(value === undefined ? {} : { value }),\n ...(defaultValue === undefined ? {} : { defaultValue }),\n ...(onChange === undefined ? {} : { onChange }),\n ...(maxHighlightCharacters === undefined ? {} : { maxHighlightCharacters }),\n });\n\n return (\n <>\n <HighlightedTextareaSurface\n ref={ref}\n textareaProps={input.getTextareaProps(props)}\n model={input.highlightModel}\n wrapperClassName={wrapperClassName}\n />\n {input.warnings.map((warning, index) => (\n <p role=\"status\" key={index}>\n {warning.message}\n </p>\n ))}\n </>\n );\n});\n","import { useSourceInput } from './useSourceInput';\nimport type { UseSourceInputOptions } from './useSourceInput';\n\nexport type { TextSelection } from './useSourceInput';\nexport interface UseMarkdownInputOptions extends Omit<\n UseSourceInputOptions,\n 'language'\n> {\n readonly language?: 'markdown';\n}\nexport function useMarkdownInput(options: UseMarkdownInputOptions = {}) {\n return useSourceInput({ ...options, language: 'markdown' });\n}\n","import { isTexionContent } from '@texion/core';\nimport type { TexionContent } from '@texion/core';\nimport { DocumentViewer } from './DocumentViewer';\nimport type { DocumentViewerProps } from './DocumentViewer';\n\nexport interface TexionViewerProps extends Omit<\n DocumentViewerProps,\n 'content' | 'input' | 'document' | 'format'\n> {\n readonly content: TexionContent;\n}\n\nexport function TexionViewer({ content, ...props }: TexionViewerProps) {\n if (!isTexionContent(content)) {\n return <p role=\"alert\">Unsupported Texion content.</p>;\n }\n return (\n <DocumentViewer\n {...props}\n content={content.source}\n format={content.format}\n />\n );\n}\n","import type { TextareaHTMLAttributes } from 'react';\nimport { useAttachmentController } from '../controllers/attachments';\nimport type { AttachmentOptions } from '../controllers/attachments';\n\nexport type UseTexionAttachmentsOptions = AttachmentOptions;\n\n/** File behavior independent of draft editing, rendering and submission. */\nexport function useTexionAttachments(\n options: UseTexionAttachmentsOptions = {},\n) {\n const attachments = useAttachmentController(options);\n function getTextareaProps(\n props: TextareaHTMLAttributes<HTMLTextAreaElement> = {},\n ) {\n return {\n ...props,\n onPaste(event: Parameters<NonNullable<typeof props.onPaste>>[0]) {\n props.onPaste?.(event);\n attachments.handlePaste(event);\n },\n };\n }\n return {\n documents: attachments.documents,\n isDragging: attachments.isDragging,\n inputError: attachments.inputError,\n addDocument: attachments.addDocument,\n removeDocument: attachments.controller.remove,\n cancelDocument: attachments.controller.cancel,\n clear: attachments.controller.clear,\n whenSettled: attachments.controller.whenSettled,\n waitForIdle: attachments.controller.waitForIdle,\n openPicker: attachments.openPicker,\n getRootProps: attachments.getRootProps,\n getInputProps: attachments.getInputProps,\n getTextareaProps,\n handlePaste: attachments.handlePaste,\n };\n}\n","import { useEffect, useState } from 'react';\nimport { isTexionMessage } from '@texion/core';\nimport type {\n ControllerOptions,\n DocumentInput,\n TexionAttachmentReference,\n TexionMessage,\n} from '@texion/core';\nimport type { RendererRegistry } from '../renderers/types';\nimport { TexionViewer } from './TexionViewer';\nimport { DocumentViewer } from './DocumentViewer';\n\nexport type AttachmentResolver = (\n attachment: TexionAttachmentReference,\n signal: AbortSignal,\n) => DocumentInput | undefined | Promise<DocumentInput | undefined>;\nexport interface TexionMessageViewerProps {\n readonly message: TexionMessage;\n readonly resolveAttachment?: AttachmentResolver;\n readonly options?: ControllerOptions;\n readonly renderers?: RendererRegistry;\n readonly className?: string;\n}\n\nfunction SavedAttachment({\n attachment,\n resolve,\n options,\n renderers,\n}: {\n attachment: TexionAttachmentReference;\n resolve: AttachmentResolver | undefined;\n options: ControllerOptions | undefined;\n renderers: RendererRegistry | undefined;\n}) {\n const [open, setOpen] = useState(false);\n const [result, setResult] = useState<{\n attachment: TexionAttachmentReference;\n input?: DocumentInput;\n error?: string;\n }>();\n useEffect(() => {\n if (!open || !resolve) return;\n const operation = new AbortController();\n setResult(undefined);\n void Promise.resolve()\n .then(() => resolve(attachment, operation.signal))\n .then((input) => {\n if (operation.signal.aborted) return;\n // Storage often returns a Blob; retain the saved filename for format detection.\n const value =\n input && typeof input === 'object' && 'arrayBuffer' in input\n ? new File([input as Blob], attachment.name, {\n type: attachment.mimeType || (input as Blob).type,\n })\n : input;\n setResult({\n attachment,\n ...(value === undefined ? {} : { input: value }),\n });\n })\n .catch((error: unknown) => {\n if (!operation.signal.aborted)\n setResult({\n attachment,\n error:\n error instanceof Error\n ? error.message\n : 'The attachment could not be restored.',\n });\n });\n return () => operation.abort();\n }, [open, resolve, attachment]);\n const current = result?.attachment === attachment ? result : undefined;\n return (\n <li className=\"texion-saved-attachment\">\n <div>\n <strong>{attachment.name}</strong>\n <span>\n {attachment.format} · {attachment.size.toLocaleString()} bytes\n </span>\n </div>\n {resolve ? (\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen((value) => !value)}\n >\n {open ? `Close ${attachment.name}` : `Preview ${attachment.name}`}\n </button>\n ) : (\n <p>Original attachment requires a host resolver.</p>\n )}\n {open && resolve && (\n <div className=\"texion-saved-attachment-preview\">\n {!current ? (\n <p role=\"status\">Restoring attachment…</p>\n ) : current.error ? (\n <p role=\"alert\">{current.error}</p>\n ) : current.input === undefined ? (\n <p role=\"status\">The original attachment is not available.</p>\n ) : (\n <DocumentViewer\n input={current.input}\n format={attachment.format}\n {...(options ? { options } : {})}\n {...(renderers ? { renderers } : {})}\n />\n )}\n </div>\n )}\n </li>\n );\n}\n\n/** Renders portable content; attachment keys are never fetched or opened automatically. */\nexport function TexionMessageViewer({\n message,\n resolveAttachment,\n options,\n renderers,\n className = 'texion-message',\n}: TexionMessageViewerProps) {\n if (!isTexionMessage(message))\n return <p role=\"alert\">Invalid Texion message.</p>;\n return (\n <section className={className} aria-label=\"Saved message\">\n {message.content.source.trim() && (\n <TexionViewer\n content={message.content}\n {...(options ? { options } : {})}\n {...(renderers ? { renderers } : {})}\n />\n )}\n {message.attachments.length > 0 && (\n <ul aria-label=\"Saved attachments\">\n {message.attachments.map((attachment) => (\n <SavedAttachment\n key={attachment.id}\n attachment={attachment}\n resolve={resolveAttachment}\n options={options}\n renderers={renderers}\n />\n ))}\n </ul>\n )}\n </section>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport type { OcrApproval } from '@texion/core';\n\nexport interface PendingOcrApproval {\n readonly id: string;\n readonly request: OcrApproval;\n}\n/** Host-controlled consent presentation. No dialog or remote request is opened automatically. */\nexport function useOcrApproval() {\n const [pending, setPending] = useState<readonly PendingOcrApproval[]>([]);\n const requests = useRef(\n new Map<string, { finish(approved: boolean): void }>(),\n );\n const next = useRef(0);\n const requestApproval = useCallback(\n (request: OcrApproval): Promise<boolean> => {\n if (request.signal.aborted) return Promise.resolve(false);\n const id = `ocr-approval-${++next.current}`;\n return new Promise((resolve) => {\n const abort = () => finish(false);\n function finish(approved: boolean) {\n if (!requests.current.delete(id)) return;\n request.signal.removeEventListener('abort', abort);\n setPending((values) => values.filter((value) => value.id !== id));\n resolve(approved);\n }\n requests.current.set(id, { finish });\n request.signal.addEventListener('abort', abort, { once: true });\n setPending((values) => [...values, { id, request }]);\n });\n },\n [],\n );\n const approve = useCallback(\n (id: string) => requests.current.get(id)?.finish(true),\n [],\n );\n const deny = useCallback(\n (id: string) => requests.current.get(id)?.finish(false),\n [],\n );\n useEffect(\n () => () => {\n for (const request of [...requests.current.values()])\n request.finish(false);\n },\n [],\n );\n return { pending, requestApproval, approve, deny };\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","isTextFormat","useMemo","useRef","useState","useState","useRef","useMemo","useState","useRef","isTextFormat","useEffect","useEffect","useState","useSyncExternalStore","createController","isTextFormat","Suspense","lazy","useEffect","useState","useMemo","jsx","jsxs","useMemo","useEffect","useRef","useState","jsx","jsxs","useEffect","HighlightedTextareaSurface","useRef","useState","HighlightedTextarea","Fragment","jsx","jsxs","lazy","useState","useEffect","Suspense","isTextFormat","isTexionContent","jsx","isTexionContent","useEffect","useState","jsx","jsxs","useState","useEffect","useCallback","useEffect","useRef","useState"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// src/renderers/json/index.tsx
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
function JsonValue({
|
|
4
|
+
node,
|
|
5
|
+
depth = 0
|
|
6
|
+
}) {
|
|
7
|
+
const children = node.children ?? [];
|
|
8
|
+
if (node.type === "code" || node.type === "text") {
|
|
9
|
+
return /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: node.value }) });
|
|
10
|
+
}
|
|
11
|
+
if (node.type === "json-object") {
|
|
12
|
+
return /* @__PURE__ */ jsxs("details", { open: depth < 2, className: "texion-json-branch", children: [
|
|
13
|
+
/* @__PURE__ */ jsxs("summary", { children: [
|
|
14
|
+
"Object (",
|
|
15
|
+
children.length,
|
|
16
|
+
" ",
|
|
17
|
+
children.length === 1 ? "property" : "properties",
|
|
18
|
+
")"
|
|
19
|
+
] }),
|
|
20
|
+
/* @__PURE__ */ jsx("dl", { children: children.map((property, index) => /* @__PURE__ */ jsxs("div", { children: [
|
|
21
|
+
/* @__PURE__ */ jsx("dt", { children: /* @__PURE__ */ jsx("code", { children: property.value }) }),
|
|
22
|
+
/* @__PURE__ */ jsx("dd", { children: property.children?.[0] ? /* @__PURE__ */ jsx(JsonValue, { node: property.children[0], depth: depth + 1 }) : "\u2026" })
|
|
23
|
+
] }, index)) })
|
|
24
|
+
] });
|
|
25
|
+
}
|
|
26
|
+
if (node.type === "json-array") {
|
|
27
|
+
return /* @__PURE__ */ jsxs("details", { open: depth < 2, className: "texion-json-branch", children: [
|
|
28
|
+
/* @__PURE__ */ jsxs("summary", { children: [
|
|
29
|
+
"Array (",
|
|
30
|
+
children.length,
|
|
31
|
+
" items)"
|
|
32
|
+
] }),
|
|
33
|
+
/* @__PURE__ */ jsx("ol", { start: 0, children: children.map((child, index) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(JsonValue, { node: child, depth: depth + 1 }) }, index)) })
|
|
34
|
+
] });
|
|
35
|
+
}
|
|
36
|
+
return /* @__PURE__ */ jsx("code", { className: `texion-${node.type}`, children: node.value });
|
|
37
|
+
}
|
|
38
|
+
function JsonRenderer({ preview }) {
|
|
39
|
+
return /* @__PURE__ */ jsx("div", { className: "texion-json-viewer", children: preview.nodes.map((node, index) => /* @__PURE__ */ jsx(JsonValue, { node }, index)) });
|
|
40
|
+
}
|
|
41
|
+
var json_default = JsonRenderer;
|
|
42
|
+
export {
|
|
43
|
+
JsonRenderer,
|
|
44
|
+
json_default as default
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=json-BEWG6XTV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/renderers/json/index.tsx"],"sourcesContent":["import type { PreviewNode } from '@texion/core';\nimport type { PreviewRendererProps } from '../types';\n\nfunction JsonValue({\n node,\n depth = 0,\n}: {\n readonly node: PreviewNode;\n readonly depth?: number;\n}) {\n const children = node.children ?? [];\n if (node.type === 'code' || node.type === 'text') {\n return (\n <pre>\n <code>{node.value}</code>\n </pre>\n );\n }\n if (node.type === 'json-object') {\n return (\n <details open={depth < 2} className=\"texion-json-branch\">\n <summary>\n Object ({children.length}{' '}\n {children.length === 1 ? 'property' : 'properties'})\n </summary>\n <dl>\n {children.map((property, index) => (\n <div key={index}>\n <dt>\n <code>{property.value}</code>\n </dt>\n <dd>\n {property.children?.[0] ? (\n <JsonValue node={property.children[0]} depth={depth + 1} />\n ) : (\n '…'\n )}\n </dd>\n </div>\n ))}\n </dl>\n </details>\n );\n }\n if (node.type === 'json-array') {\n return (\n <details open={depth < 2} className=\"texion-json-branch\">\n <summary>Array ({children.length} items)</summary>\n <ol start={0}>\n {children.map((child, index) => (\n <li key={index}>\n <JsonValue node={child} depth={depth + 1} />\n </li>\n ))}\n </ol>\n </details>\n );\n }\n return <code className={`texion-${node.type}`}>{node.value}</code>;\n}\nexport function JsonRenderer({ preview }: PreviewRendererProps) {\n return (\n <div className=\"texion-json-viewer\">\n {preview.nodes.map((node, index) => (\n <JsonValue node={node} key={index} />\n ))}\n </div>\n );\n}\nexport default JsonRenderer;\n"],"mappings":";AAcQ,cAOA,YAPA;AAXR,SAAS,UAAU;AAAA,EACjB;AAAA,EACA,QAAQ;AACV,GAGG;AACD,QAAM,WAAW,KAAK,YAAY,CAAC;AACnC,MAAI,KAAK,SAAS,UAAU,KAAK,SAAS,QAAQ;AAChD,WACE,oBAAC,SACC,8BAAC,UAAM,eAAK,OAAM,GACpB;AAAA,EAEJ;AACA,MAAI,KAAK,SAAS,eAAe;AAC/B,WACE,qBAAC,aAAQ,MAAM,QAAQ,GAAG,WAAU,sBAClC;AAAA,2BAAC,aAAQ;AAAA;AAAA,QACE,SAAS;AAAA,QAAQ;AAAA,QACzB,SAAS,WAAW,IAAI,aAAa;AAAA,QAAa;AAAA,SACrD;AAAA,MACA,oBAAC,QACE,mBAAS,IAAI,CAAC,UAAU,UACvB,qBAAC,SACC;AAAA,4BAAC,QACC,8BAAC,UAAM,mBAAS,OAAM,GACxB;AAAA,QACA,oBAAC,QACE,mBAAS,WAAW,CAAC,IACpB,oBAAC,aAAU,MAAM,SAAS,SAAS,CAAC,GAAG,OAAO,QAAQ,GAAG,IAEzD,UAEJ;AAAA,WAVQ,KAWV,CACD,GACH;AAAA,OACF;AAAA,EAEJ;AACA,MAAI,KAAK,SAAS,cAAc;AAC9B,WACE,qBAAC,aAAQ,MAAM,QAAQ,GAAG,WAAU,sBAClC;AAAA,2BAAC,aAAQ;AAAA;AAAA,QAAQ,SAAS;AAAA,QAAO;AAAA,SAAO;AAAA,MACxC,oBAAC,QAAG,OAAO,GACR,mBAAS,IAAI,CAAC,OAAO,UACpB,oBAAC,QACC,8BAAC,aAAU,MAAM,OAAO,OAAO,QAAQ,GAAG,KADnC,KAET,CACD,GACH;AAAA,OACF;AAAA,EAEJ;AACA,SAAO,oBAAC,UAAK,WAAW,UAAU,KAAK,IAAI,IAAK,eAAK,OAAM;AAC7D;AACO,SAAS,aAAa,EAAE,QAAQ,GAAyB;AAC9D,SACE,oBAAC,SAAI,WAAU,sBACZ,kBAAQ,MAAM,IAAI,CAAC,MAAM,UACxB,oBAAC,aAAU,QAAiB,KAAO,CACpC,GACH;AAEJ;AACA,IAAO,eAAQ;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { P as PreviewRendererProps } from './types-DRXx1QAT.js';
|
|
3
|
+
import '@texion/core';
|
|
4
|
+
|
|
5
|
+
declare function MarkdownRenderer({ preview }: PreviewRendererProps): react.JSX.Element;
|
|
6
|
+
|
|
7
|
+
export { MarkdownRenderer, MarkdownRenderer as default };
|
package/dist/markdown.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/rich.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { R as RichMarkdownEditorProps } from './types-D4zTiC0I.js';
|
|
3
|
+
import '@texion/core';
|
|
4
|
+
|
|
5
|
+
declare function RichMarkdownEditor(props: RichMarkdownEditorProps): react.JSX.Element;
|
|
6
|
+
|
|
7
|
+
export { RichMarkdownEditor, RichMarkdownEditorProps, RichMarkdownEditor as default };
|
package/dist/rich.js
ADDED
package/dist/rich.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--texion-border: #cbd5e1;
|
|
3
|
+
--texion-background: #fff;
|
|
4
|
+
--texion-foreground: #172033;
|
|
5
|
+
--texion-accent: #2563eb;
|
|
6
|
+
--texion-radius: 0.5rem;
|
|
7
|
+
}
|
|
8
|
+
.texion-input {
|
|
9
|
+
color: var(--texion-foreground);
|
|
10
|
+
background: var(--texion-background);
|
|
11
|
+
border: 1px solid var(--texion-border);
|
|
12
|
+
border-radius: var(--texion-radius);
|
|
13
|
+
padding: 1rem;
|
|
14
|
+
}
|
|
15
|
+
.texion-input textarea {
|
|
16
|
+
display: block;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
width: 100%;
|
|
19
|
+
min-height: 7rem;
|
|
20
|
+
resize: none;
|
|
21
|
+
font: inherit;
|
|
22
|
+
margin-block: 0.5rem;
|
|
23
|
+
}
|
|
24
|
+
.texion-input[data-dragging] {
|
|
25
|
+
outline: 2px solid var(--texion-accent);
|
|
26
|
+
}
|
|
27
|
+
.texion-input button {
|
|
28
|
+
margin: 0.25rem;
|
|
29
|
+
}
|
|
30
|
+
.texion-input :focus-visible {
|
|
31
|
+
outline: 2px solid var(--texion-accent);
|
|
32
|
+
outline-offset: 2px;
|
|
33
|
+
}
|
|
34
|
+
.texion-attachments {
|
|
35
|
+
padding-inline-start: 1.25rem;
|
|
36
|
+
}
|
|
37
|
+
.texion-viewer {
|
|
38
|
+
overflow-wrap: anywhere;
|
|
39
|
+
}
|
|
40
|
+
.texion-viewer pre,
|
|
41
|
+
.texion-viewer table {
|
|
42
|
+
display: block;
|
|
43
|
+
overflow-x: auto;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Token colors never change glyph metrics. Layout is mirrored from the native textarea. */
|
|
47
|
+
.texion-highlight-overlay span {
|
|
48
|
+
font: inherit;
|
|
49
|
+
letter-spacing: inherit;
|
|
50
|
+
word-spacing: inherit;
|
|
51
|
+
}
|
|
52
|
+
@media (forced-colors: active) {
|
|
53
|
+
.texion-highlighted-textarea textarea {
|
|
54
|
+
-webkit-text-fill-color: currentColor !important;
|
|
55
|
+
}
|
|
56
|
+
.texion-highlight-overlay {
|
|
57
|
+
display: none;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.texion-rich-editor {
|
|
62
|
+
position: relative;
|
|
63
|
+
}
|
|
64
|
+
.texion-rich-content {
|
|
65
|
+
min-height: 7rem;
|
|
66
|
+
padding: 0.75rem;
|
|
67
|
+
border: 1px solid var(--texion-border);
|
|
68
|
+
border-radius: var(--texion-radius);
|
|
69
|
+
outline-offset: 2px;
|
|
70
|
+
white-space: pre-wrap;
|
|
71
|
+
overflow-wrap: anywhere;
|
|
72
|
+
}
|
|
73
|
+
.texion-rich-placeholder {
|
|
74
|
+
position: absolute;
|
|
75
|
+
inset-block-start: 0.75rem;
|
|
76
|
+
inset-inline-start: 0.75rem;
|
|
77
|
+
opacity: 0.6;
|
|
78
|
+
pointer-events: none;
|
|
79
|
+
}
|
|
80
|
+
.texion-rich-content p {
|
|
81
|
+
margin-block: 0.5rem;
|
|
82
|
+
}
|
|
83
|
+
.texion-rich-content h1 {
|
|
84
|
+
font-size: 1.75em;
|
|
85
|
+
}
|
|
86
|
+
.texion-rich-content h2 {
|
|
87
|
+
font-size: 1.5em;
|
|
88
|
+
}
|
|
89
|
+
.texion-rich-content h3 {
|
|
90
|
+
font-size: 1.25em;
|
|
91
|
+
}
|
|
92
|
+
.texion-rich-content blockquote {
|
|
93
|
+
border-inline-start: 3px solid var(--texion-border);
|
|
94
|
+
margin-inline-start: 0;
|
|
95
|
+
padding-inline-start: 1rem;
|
|
96
|
+
}
|
|
97
|
+
.texion-rich-bold {
|
|
98
|
+
font-weight: bold;
|
|
99
|
+
}
|
|
100
|
+
.texion-rich-italic {
|
|
101
|
+
font-style: italic;
|
|
102
|
+
}
|
|
103
|
+
.texion-rich-strikethrough {
|
|
104
|
+
text-decoration: line-through;
|
|
105
|
+
}
|
|
106
|
+
.texion-rich-inline-code,
|
|
107
|
+
.texion-rich-code {
|
|
108
|
+
font-family: monospace;
|
|
109
|
+
}
|
|
110
|
+
.texion-rich-code {
|
|
111
|
+
display: block;
|
|
112
|
+
padding: 0.5rem;
|
|
113
|
+
background: color-mix(
|
|
114
|
+
in srgb,
|
|
115
|
+
var(--texion-foreground) 6%,
|
|
116
|
+
var(--texion-background)
|
|
117
|
+
);
|
|
118
|
+
overflow-x: auto;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.texion-json-branch {
|
|
122
|
+
margin-block: 0.35rem;
|
|
123
|
+
}
|
|
124
|
+
.texion-json-branch summary {
|
|
125
|
+
cursor: pointer;
|
|
126
|
+
}
|
|
127
|
+
.texion-json-branch dl {
|
|
128
|
+
margin-inline-start: 1rem;
|
|
129
|
+
}
|
|
130
|
+
.texion-json-branch dt {
|
|
131
|
+
font-weight: 600;
|
|
132
|
+
}
|
|
133
|
+
.texion-json-branch dd {
|
|
134
|
+
margin-inline-start: 1rem;
|
|
135
|
+
overflow-wrap: anywhere;
|
|
136
|
+
}
|
|
137
|
+
.texion-csv-viewer {
|
|
138
|
+
overflow: auto;
|
|
139
|
+
max-height: 30rem;
|
|
140
|
+
}
|
|
141
|
+
.texion-csv-viewer table {
|
|
142
|
+
border-collapse: collapse;
|
|
143
|
+
width: max-content;
|
|
144
|
+
min-width: 100%;
|
|
145
|
+
}
|
|
146
|
+
.texion-csv-viewer th,
|
|
147
|
+
.texion-csv-viewer td {
|
|
148
|
+
border: 1px solid var(--texion-border);
|
|
149
|
+
padding: 0.4rem 0.65rem;
|
|
150
|
+
text-align: start;
|
|
151
|
+
vertical-align: top;
|
|
152
|
+
white-space: pre-wrap;
|
|
153
|
+
}
|
|
154
|
+
.texion-image-viewer {
|
|
155
|
+
margin: 0;
|
|
156
|
+
}
|
|
157
|
+
.texion-image-viewer img {
|
|
158
|
+
display: block;
|
|
159
|
+
max-width: 100%;
|
|
160
|
+
max-height: 30rem;
|
|
161
|
+
width: auto;
|
|
162
|
+
height: auto;
|
|
163
|
+
object-fit: contain;
|
|
164
|
+
}
|
|
165
|
+
.texion-image-viewer figcaption {
|
|
166
|
+
margin-block-start: 0.5rem;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.texion-code-block {
|
|
170
|
+
margin-block: 0.75rem;
|
|
171
|
+
border: 1px solid var(--texion-border);
|
|
172
|
+
border-radius: var(--texion-radius);
|
|
173
|
+
overflow: hidden;
|
|
174
|
+
}
|
|
175
|
+
.texion-code-toolbar {
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-wrap: wrap;
|
|
178
|
+
align-items: center;
|
|
179
|
+
gap: 0.5rem;
|
|
180
|
+
padding: 0.5rem 0.75rem;
|
|
181
|
+
font:
|
|
182
|
+
0.75rem ui-monospace,
|
|
183
|
+
monospace;
|
|
184
|
+
background: color-mix(in srgb, currentColor 4%, transparent);
|
|
185
|
+
}
|
|
186
|
+
.texion-code-toolbar > span {
|
|
187
|
+
margin-inline-end: auto;
|
|
188
|
+
}
|
|
189
|
+
.texion-code-toolbar button {
|
|
190
|
+
font: inherit;
|
|
191
|
+
color: var(--texion-accent);
|
|
192
|
+
padding: 0.25rem 0.5rem;
|
|
193
|
+
border: 1px solid var(--texion-border);
|
|
194
|
+
border-radius: 0.25rem;
|
|
195
|
+
}
|
|
196
|
+
.texion-code-block pre {
|
|
197
|
+
margin: 0;
|
|
198
|
+
padding: 0.75rem;
|
|
199
|
+
}
|
|
200
|
+
.texion-code-block pre[hidden] {
|
|
201
|
+
display: none;
|
|
202
|
+
}
|
|
203
|
+
.texion-code-block > p {
|
|
204
|
+
padding-inline: 0.75rem;
|
|
205
|
+
font-size: 0.8rem;
|
|
206
|
+
}
|
|
207
|
+
.texion-message > ul {
|
|
208
|
+
list-style: none;
|
|
209
|
+
padding: 0;
|
|
210
|
+
}
|
|
211
|
+
.texion-saved-attachment {
|
|
212
|
+
border: 1px solid var(--texion-border);
|
|
213
|
+
border-radius: var(--texion-radius);
|
|
214
|
+
padding: 0.75rem;
|
|
215
|
+
margin-block: 0.5rem;
|
|
216
|
+
}
|
|
217
|
+
.texion-saved-attachment > div:first-child {
|
|
218
|
+
display: flex;
|
|
219
|
+
flex-wrap: wrap;
|
|
220
|
+
justify-content: space-between;
|
|
221
|
+
gap: 0.5rem;
|
|
222
|
+
}
|
|
223
|
+
.texion-saved-attachment > div > span {
|
|
224
|
+
font-size: 0.8rem;
|
|
225
|
+
opacity: 0.75;
|
|
226
|
+
}
|
|
227
|
+
.texion-saved-attachment > button {
|
|
228
|
+
color: var(--texion-accent);
|
|
229
|
+
font-size: 0.8rem;
|
|
230
|
+
margin-block-start: 0.5rem;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.texion-document-progress {
|
|
234
|
+
display: inline-flex;
|
|
235
|
+
flex-direction: column;
|
|
236
|
+
gap: 0.25rem;
|
|
237
|
+
font-size: 0.8rem;
|
|
238
|
+
}
|
|
239
|
+
.texion-document-progress progress {
|
|
240
|
+
width: 10rem;
|
|
241
|
+
max-width: 100%;
|
|
242
|
+
accent-color: var(--texion-accent);
|
|
243
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TextFormat } from '@texion/core';
|
|
2
|
+
|
|
3
|
+
interface RichMarkdownEditorProps {
|
|
4
|
+
readonly value: string;
|
|
5
|
+
readonly formats?: readonly TextFormat[];
|
|
6
|
+
readonly onChange: (source: string) => void;
|
|
7
|
+
readonly onImport?: (source: string) => void;
|
|
8
|
+
readonly onSubmit?: () => void;
|
|
9
|
+
readonly onCompositionChange?: (composing: boolean) => void;
|
|
10
|
+
readonly onFiles?: (files: readonly File[]) => void;
|
|
11
|
+
readonly onRequestSource?: () => void;
|
|
12
|
+
readonly id?: string;
|
|
13
|
+
readonly label?: string;
|
|
14
|
+
readonly placeholder?: string;
|
|
15
|
+
readonly live?: boolean;
|
|
16
|
+
readonly readOnly?: boolean;
|
|
17
|
+
readonly submitOnEnter?: boolean;
|
|
18
|
+
readonly maxCharacters?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type { RichMarkdownEditorProps as R };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
|
+
import { DocumentPreview, TexionDocument } from '@texion/core';
|
|
3
|
+
|
|
4
|
+
interface PreviewRendererProps {
|
|
5
|
+
readonly preview: DocumentPreview;
|
|
6
|
+
readonly document?: TexionDocument;
|
|
7
|
+
}
|
|
8
|
+
type RendererRegistry = Readonly<Record<string, ComponentType<PreviewRendererProps>>>;
|
|
9
|
+
|
|
10
|
+
export type { PreviewRendererProps as P, RendererRegistry as R };
|