@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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/editors/rich/RichMarkdownEditor.tsx","../src/editors/rich/compatibility.ts","../src/editors/rich/extension.ts","../src/editors/rich/link-policy.ts","../src/editors/rich/RichEditorBridge.tsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport { LexicalExtensionComposer } from '@lexical/react/LexicalExtensionComposer';\nimport { ContentEditable } from '@lexical/react/LexicalContentEditable';\nimport { ListPlugin } from '@lexical/react/LexicalListPlugin';\nimport { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';\nimport {\n DEFAULT_TRANSFORMERS,\n MarkdownShortcutPlugin,\n} from '@lexical/react/LexicalMarkdownShortcutPlugin';\nimport { safeUrl } from '@texion/core';\nimport { richImportIssue } from './compatibility';\nimport { createRichExtension } from './extension';\nimport { RichEditorBridge } from './RichEditorBridge';\nimport type { RichMarkdownEditorProps } from './types';\n\nexport type { RichMarkdownEditorProps } from './types';\n\nconst validateUrl = (url: string) => safeUrl(url) !== undefined;\n\nexport function RichMarkdownEditor(props: RichMarkdownEditorProps) {\n const [error, setError] = useState('');\n const [importIssue, setImportIssue] = useState(() =>\n richImportIssue(props.value, props.maxCharacters ?? 50_000),\n );\n useEffect(() => {\n if (importIssue) {\n setImportIssue(\n richImportIssue(props.value, props.maxCharacters ?? 50_000),\n );\n }\n }, [props.value, props.maxCharacters, importIssue]);\n const initialValue = useRef(props.value);\n initialValue.current = props.value;\n const currentLimit = useRef(props.maxCharacters ?? 50_000);\n currentLimit.current = props.maxCharacters ?? 50_000;\n const maxCharacters = props.maxCharacters ?? 50_000;\n\n if (!Number.isSafeInteger(maxCharacters) || maxCharacters < 1) {\n throw new RangeError('maxCharacters must be a positive safe integer');\n }\n const extension = useMemo(\n () =>\n createRichExtension({\n getSource: () => initialValue.current,\n getLimit: () => currentLimit.current,\n onError: (error) => setError(error.message),\n }),\n [],\n );\n\n if (props.value.length > maxCharacters || importIssue) {\n return (\n <div>\n <p role=\"status\">\n {importIssue ??\n 'This content exceeds the rich editor limit. Use source mode to edit the complete source.'}\n </p>\n {props.onRequestSource && (\n <button type=\"button\" onClick={props.onRequestSource}>\n Edit source\n </button>\n )}\n </div>\n );\n }\n const placeholder = props.placeholder ?? 'Write something…';\n\n return (\n <div className=\"texion-rich-editor\">\n <LexicalExtensionComposer extension={extension} contentEditable={null}>\n <ContentEditable\n id={props.id}\n role=\"textbox\"\n aria-label={props.label ?? 'Message'}\n aria-multiline=\"true\"\n aria-placeholder={placeholder}\n placeholder={\n <span className=\"texion-rich-placeholder\">{placeholder}</span>\n }\n className=\"texion-rich-content\"\n onCompositionStart={() => props.onCompositionChange?.(true)}\n onCompositionEnd={() => props.onCompositionChange?.(false)}\n />\n <RichEditorBridge\n options={props}\n reportError={setError}\n reportImportIssue={setImportIssue}\n />\n <ListPlugin />\n <LinkPlugin validateUrl={validateUrl} />\n {props.live !== false && (\n <MarkdownShortcutPlugin transformers={DEFAULT_TRANSFORMERS} />\n )}\n </LexicalExtensionComposer>\n {error && <p role=\"alert\">{error}</p>}\n {error && props.onRequestSource && (\n <button type=\"button\" onClick={props.onRequestSource}>\n Edit source\n </button>\n )}\n </div>\n );\n}\n\nexport default RichMarkdownEditor;\n","import { inspectMarkdownSource } from '@texion/core';\n\nconst sourceOnlyNodes = new Set([\n 'yaml',\n 'toml',\n 'table',\n 'footnoteDefinition',\n 'footnoteReference',\n 'definition',\n 'linkReference',\n 'imageReference',\n 'taskList',\n]);\n\nexport function richImportIssue(\n source: string,\n maxCharacters = 50_000,\n): string | undefined {\n const features = inspectMarkdownSource(source, maxCharacters);\n\n if (features.limited) {\n return 'This content exceeds the rich editor complexity limits. Use source mode.';\n }\n if (features.nodeTypes.some((type) => sourceOnlyNodes.has(type))) {\n return 'This Markdown uses syntax that requires source mode to preserve its meaning.';\n }\n return undefined;\n}\n","import { defineExtension } from 'lexical';\nimport { $convertFromMarkdownString } from '@lexical/markdown';\nimport { HistoryExtension } from '@lexical/history';\nimport { CodeNode } from '@lexical/code';\nimport { LinkNode } from '@lexical/link';\nimport { ListItemNode, ListNode } from '@lexical/list';\nimport { HeadingNode, QuoteNode, RichTextExtension } from '@lexical/rich-text';\nimport { DEFAULT_TRANSFORMERS } from '@lexical/react/LexicalMarkdownShortcutPlugin';\nimport { HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode';\nimport { richImportIssue } from './compatibility';\nimport { registerLinkPolicy } from './link-policy';\n\ninterface RichExtensionOptions {\n readonly getSource: () => string;\n readonly getLimit: () => number;\n readonly onError: (error: Error) => void;\n}\n\nexport function createRichExtension(options: RichExtensionOptions) {\n return defineExtension({\n name: '@texion/rich-markdown',\n namespace: 'Texion Markdown',\n dependencies: [RichTextExtension, HistoryExtension],\n nodes: [\n HeadingNode,\n QuoteNode,\n ListNode,\n ListItemNode,\n CodeNode,\n LinkNode,\n HorizontalRuleNode,\n ],\n theme: {\n text: {\n bold: 'texion-rich-bold',\n italic: 'texion-rich-italic',\n code: 'texion-rich-inline-code',\n strikethrough: 'texion-rich-strikethrough',\n },\n code: 'texion-rich-code',\n },\n onError: options.onError,\n $initialEditorState() {\n const source = options.getSource();\n const limit = options.getLimit();\n const exceedsLimit = source.length > limit;\n const isUnsupported = richImportIssue(source, limit);\n const initialSource = exceedsLimit || isUnsupported ? '' : source;\n\n $convertFromMarkdownString(initialSource, DEFAULT_TRANSFORMERS);\n },\n register: registerLinkPolicy,\n });\n}\n","import { $getNodeByKey, mergeRegister } from 'lexical';\nimport type { LexicalEditor } from 'lexical';\nimport { LinkNode } from '@lexical/link';\nimport { safeUrl } from '@texion/core';\n\nfunction normalizeLink(node: LinkNode): void {\n const url = safeUrl(node.getURL());\n\n if (!url) {\n for (const child of node.getChildren()) {\n node.insertBefore(child);\n }\n\n node.remove();\n\n return;\n }\n\n if (node.getURL() !== url) {\n node.setURL(url);\n }\n\n if (node.getRel() !== 'noopener noreferrer') {\n node.setRel('noopener noreferrer');\n }\n}\n\nexport function registerLinkPolicy(editor: LexicalEditor): () => void {\n const removeTransform = editor.registerNodeTransform(LinkNode, normalizeLink);\n const removeListener = editor.registerMutationListener(\n LinkNode,\n (mutations) => {\n editor.getEditorState().read(() => {\n for (const [key, change] of mutations) {\n if (change === 'destroyed') {\n continue;\n }\n\n const node = $getNodeByKey(key);\n const element = editor.getElementByKey(key);\n\n if (!(node instanceof LinkNode) || !element) {\n continue;\n }\n\n // Apply core's relative-URL rules instead of Lexical's URL guessing.\n const url = safeUrl(node.getURL());\n\n if (url) {\n element.setAttribute('href', url);\n } else {\n element.removeAttribute('href');\n }\n }\n });\n },\n );\n\n return mergeRegister(removeTransform, removeListener);\n}\n","import { useEffect, useRef } from 'react';\nimport {\n $addUpdateTag,\n $createTextNode,\n $getRoot,\n $getSelection,\n $insertNodes,\n $isRangeSelection,\n COMMAND_PRIORITY_HIGH,\n HISTORY_PUSH_TAG,\n KEY_ENTER_COMMAND,\n PASTE_COMMAND,\n mergeRegister,\n} from 'lexical';\nimport type { UpdateListener, PasteCommandType } from 'lexical';\nimport {\n $convertFromMarkdownString,\n $convertToMarkdownString,\n $generateNodesFromMarkdownString,\n} from '@lexical/markdown';\nimport { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';\nimport { DEFAULT_TRANSFORMERS } from '@lexical/react/LexicalMarkdownShortcutPlugin';\nimport { $createCodeNode } from '@lexical/code';\nimport { detectTextFormat } from '@texion/core';\nimport { richImportIssue } from './compatibility';\nimport type { RichMarkdownEditorProps } from './types';\n\nconst externalUpdateTag = 'texion:external';\n\nexport function RichEditorBridge({\n options,\n reportError,\n reportImportIssue,\n}: {\n readonly options: RichMarkdownEditorProps;\n readonly reportError: (message: string) => void;\n readonly reportImportIssue: (message: string | undefined) => void;\n}) {\n const [editor] = useLexicalComposerContext();\n const current = useRef(options);\n current.current = options;\n const lastValue = useRef(options.value);\n useEffect(() => {\n const handleUpdate: UpdateListener = ({\n editorState,\n dirtyElements,\n dirtyLeaves,\n tags,\n }) => {\n if (\n tags.has(externalUpdateTag) ||\n (!dirtyElements.size && !dirtyLeaves.size)\n ) {\n return;\n }\n const source = editorState.read(() =>\n $convertToMarkdownString(DEFAULT_TRANSFORMERS),\n );\n\n if (source === lastValue.current) {\n return;\n }\n lastValue.current = source;\n current.current.onChange(source);\n };\n const handlePaste = (event: PasteCommandType) => {\n if (editor.isComposing()) {\n return false;\n }\n const clipboard = 'clipboardData' in event ? event.clipboardData : null;\n\n if (!clipboard) {\n return false;\n }\n event.preventDefault();\n\n if (clipboard.files.length) {\n if (current.current.onFiles) {\n current.current.onFiles(Array.from(clipboard.files));\n } else {\n reportError('Use source mode or the attachment picker for files.');\n }\n return true;\n }\n\n const text = clipboard.getData('text/plain');\n\n if (!text) {\n return true;\n }\n if (\n $getRoot().getTextContentSize() + text.length >\n (current.current.maxCharacters ?? 50_000)\n ) {\n reportError(\n 'This paste exceeds the rich editor limit. Use source mode to edit it.',\n );\n\n return true;\n }\n\n const wasEmpty = $getRoot().getTextContentSize() === 0;\n const recognized = detectTextFormat(text, current.current.formats);\n if (recognized !== 'markdown') {\n if (wasEmpty && current.current.onRequestSource) {\n current.current.onImport?.(text);\n current.current.onChange(text);\n current.current.onRequestSource();\n } else {\n if (!$isRangeSelection($getSelection())) {\n $getRoot().selectEnd();\n }\n $addUpdateTag(HISTORY_PUSH_TAG);\n $insertNodes([\n $createCodeNode(recognized).append($createTextNode(text)),\n ]);\n }\n return true;\n }\n const issue = richImportIssue(\n text,\n current.current.maxCharacters ?? 50_000,\n );\n\n if (issue) {\n if (wasEmpty && current.current.onRequestSource) {\n current.current.onImport?.(text);\n current.current.onChange(text);\n current.current.onRequestSource();\n } else {\n reportError(issue + ' Paste it in source mode.');\n }\n return true;\n }\n\n if (!$isRangeSelection($getSelection())) {\n $getRoot().selectEnd();\n }\n $addUpdateTag(HISTORY_PUSH_TAG);\n\n if (current.current.live === false) {\n const selection = $getSelection();\n\n if ($isRangeSelection(selection)) {\n selection.insertRawText(text);\n }\n } else {\n $insertNodes(\n $generateNodesFromMarkdownString(text, DEFAULT_TRANSFORMERS),\n );\n }\n if (wasEmpty) {\n current.current.onImport?.(text);\n }\n reportError('');\n\n return true;\n };\n const handleEnter = (event: KeyboardEvent | null) => {\n if (\n !event ||\n editor.isComposing() ||\n event.isComposing ||\n event.keyCode === 229 ||\n event.shiftKey ||\n !current.current.onSubmit\n ) {\n return false;\n }\n const submit = current.current.submitOnEnter\n ? !event.altKey && !event.ctrlKey && !event.metaKey\n : (event.ctrlKey || event.metaKey) && !event.altKey;\n\n if (!submit) {\n return false;\n }\n event.preventDefault();\n current.current.onSubmit();\n\n return true;\n };\n\n return mergeRegister(\n editor.registerUpdateListener(handleUpdate),\n editor.registerCommand(PASTE_COMMAND, handlePaste, COMMAND_PRIORITY_HIGH),\n editor.registerCommand(\n KEY_ENTER_COMMAND,\n handleEnter,\n COMMAND_PRIORITY_HIGH,\n ),\n () => current.current.onCompositionChange?.(false),\n );\n }, [editor, reportError]);\n\n useEffect(() => {\n if (options.value === lastValue.current) {\n return;\n }\n const issue = richImportIssue(\n options.value,\n options.maxCharacters ?? 50_000,\n );\n\n if (issue) {\n reportImportIssue(issue);\n\n return;\n }\n\n lastValue.current = options.value;\n editor.update(\n () => $convertFromMarkdownString(options.value, DEFAULT_TRANSFORMERS),\n {\n tag: externalUpdateTag,\n },\n );\n }, [editor, options.value, options.maxCharacters, reportImportIssue]);\n useEffect(() => {\n editor.setEditable(!options.readOnly);\n }, [editor, options.readOnly]);\n\n return null;\n}\n"],"mappings":";AAAA,SAAS,aAAAA,YAAW,SAAS,UAAAC,SAAQ,gBAAgB;AACrD,SAAS,gCAAgC;AACzC,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAC3B,SAAS,kBAAkB;AAC3B;AAAA,EACE,wBAAAC;AAAA,EACA;AAAA,OACK;AACP,SAAS,WAAAC,gBAAe;;;ACTxB,SAAS,6BAA6B;AAEtC,IAAM,kBAAkB,oBAAI,IAAI;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAAS,gBACd,QACA,gBAAgB,KACI;AACpB,QAAM,WAAW,sBAAsB,QAAQ,aAAa;AAE5D,MAAI,SAAS,SAAS;AACpB,WAAO;AAAA,EACT;AACA,MAAI,SAAS,UAAU,KAAK,CAAC,SAAS,gBAAgB,IAAI,IAAI,CAAC,GAAG;AAChE,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;AC3BA,SAAS,uBAAuB;AAChC,SAAS,kCAAkC;AAC3C,SAAS,wBAAwB;AACjC,SAAS,gBAAgB;AACzB,SAAS,YAAAC,iBAAgB;AACzB,SAAS,cAAc,gBAAgB;AACvC,SAAS,aAAa,WAAW,yBAAyB;AAC1D,SAAS,4BAA4B;AACrC,SAAS,0BAA0B;;;ACRnC,SAAS,eAAe,qBAAqB;AAE7C,SAAS,gBAAgB;AACzB,SAAS,eAAe;AAExB,SAAS,cAAc,MAAsB;AAC3C,QAAM,MAAM,QAAQ,KAAK,OAAO,CAAC;AAEjC,MAAI,CAAC,KAAK;AACR,eAAW,SAAS,KAAK,YAAY,GAAG;AACtC,WAAK,aAAa,KAAK;AAAA,IACzB;AAEA,SAAK,OAAO;AAEZ;AAAA,EACF;AAEA,MAAI,KAAK,OAAO,MAAM,KAAK;AACzB,SAAK,OAAO,GAAG;AAAA,EACjB;AAEA,MAAI,KAAK,OAAO,MAAM,uBAAuB;AAC3C,SAAK,OAAO,qBAAqB;AAAA,EACnC;AACF;AAEO,SAAS,mBAAmB,QAAmC;AACpE,QAAM,kBAAkB,OAAO,sBAAsB,UAAU,aAAa;AAC5E,QAAM,iBAAiB,OAAO;AAAA,IAC5B;AAAA,IACA,CAAC,cAAc;AACb,aAAO,eAAe,EAAE,KAAK,MAAM;AACjC,mBAAW,CAAC,KAAK,MAAM,KAAK,WAAW;AACrC,cAAI,WAAW,aAAa;AAC1B;AAAA,UACF;AAEA,gBAAM,OAAO,cAAc,GAAG;AAC9B,gBAAM,UAAU,OAAO,gBAAgB,GAAG;AAE1C,cAAI,EAAE,gBAAgB,aAAa,CAAC,SAAS;AAC3C;AAAA,UACF;AAGA,gBAAM,MAAM,QAAQ,KAAK,OAAO,CAAC;AAEjC,cAAI,KAAK;AACP,oBAAQ,aAAa,QAAQ,GAAG;AAAA,UAClC,OAAO;AACL,oBAAQ,gBAAgB,MAAM;AAAA,UAChC;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,cAAc,iBAAiB,cAAc;AACtD;;;ADzCO,SAAS,oBAAoB,SAA+B;AACjE,SAAO,gBAAgB;AAAA,IACrB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,cAAc,CAAC,mBAAmB,gBAAgB;AAAA,IAClD,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACAC;AAAA,MACA;AAAA,IACF;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,eAAe;AAAA,MACjB;AAAA,MACA,MAAM;AAAA,IACR;AAAA,IACA,SAAS,QAAQ;AAAA,IACjB,sBAAsB;AACpB,YAAM,SAAS,QAAQ,UAAU;AACjC,YAAM,QAAQ,QAAQ,SAAS;AAC/B,YAAM,eAAe,OAAO,SAAS;AACrC,YAAM,gBAAgB,gBAAgB,QAAQ,KAAK;AACnD,YAAM,gBAAgB,gBAAgB,gBAAgB,KAAK;AAE3D,iCAA2B,eAAe,oBAAoB;AAAA,IAChE;AAAA,IACA,UAAU;AAAA,EACZ,CAAC;AACH;;;AErDA,SAAS,WAAW,cAAc;AAClC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAAC;AAAA,OACK;AAEP;AAAA,EACE,8BAAAC;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,iCAAiC;AAC1C,SAAS,wBAAAC,6BAA4B;AACrC,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AAIjC,IAAM,oBAAoB;AAEnB,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,CAAC,MAAM,IAAI,0BAA0B;AAC3C,QAAM,UAAU,OAAO,OAAO;AAC9B,UAAQ,UAAU;AAClB,QAAM,YAAY,OAAO,QAAQ,KAAK;AACtC,YAAU,MAAM;AACd,UAAM,eAA+B,CAAC;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAAM;AACJ,UACE,KAAK,IAAI,iBAAiB,KACzB,CAAC,cAAc,QAAQ,CAAC,YAAY,MACrC;AACA;AAAA,MACF;AACA,YAAM,SAAS,YAAY;AAAA,QAAK,MAC9B,yBAAyBC,qBAAoB;AAAA,MAC/C;AAEA,UAAI,WAAW,UAAU,SAAS;AAChC;AAAA,MACF;AACA,gBAAU,UAAU;AACpB,cAAQ,QAAQ,SAAS,MAAM;AAAA,IACjC;AACA,UAAM,cAAc,CAAC,UAA4B;AAC/C,UAAI,OAAO,YAAY,GAAG;AACxB,eAAO;AAAA,MACT;AACA,YAAM,YAAY,mBAAmB,QAAQ,MAAM,gBAAgB;AAEnE,UAAI,CAAC,WAAW;AACd,eAAO;AAAA,MACT;AACA,YAAM,eAAe;AAErB,UAAI,UAAU,MAAM,QAAQ;AAC1B,YAAI,QAAQ,QAAQ,SAAS;AAC3B,kBAAQ,QAAQ,QAAQ,MAAM,KAAK,UAAU,KAAK,CAAC;AAAA,QACrD,OAAO;AACL,sBAAY,qDAAqD;AAAA,QACnE;AACA,eAAO;AAAA,MACT;AAEA,YAAM,OAAO,UAAU,QAAQ,YAAY;AAE3C,UAAI,CAAC,MAAM;AACT,eAAO;AAAA,MACT;AACA,UACE,SAAS,EAAE,mBAAmB,IAAI,KAAK,UACtC,QAAQ,QAAQ,iBAAiB,MAClC;AACA;AAAA,UACE;AAAA,QACF;AAEA,eAAO;AAAA,MACT;AAEA,YAAM,WAAW,SAAS,EAAE,mBAAmB,MAAM;AACrD,YAAM,aAAa,iBAAiB,MAAM,QAAQ,QAAQ,OAAO;AACjE,UAAI,eAAe,YAAY;AAC7B,YAAI,YAAY,QAAQ,QAAQ,iBAAiB;AAC/C,kBAAQ,QAAQ,WAAW,IAAI;AAC/B,kBAAQ,QAAQ,SAAS,IAAI;AAC7B,kBAAQ,QAAQ,gBAAgB;AAAA,QAClC,OAAO;AACL,cAAI,CAAC,kBAAkB,cAAc,CAAC,GAAG;AACvC,qBAAS,EAAE,UAAU;AAAA,UACvB;AACA,wBAAc,gBAAgB;AAC9B,uBAAa;AAAA,YACX,gBAAgB,UAAU,EAAE,OAAO,gBAAgB,IAAI,CAAC;AAAA,UAC1D,CAAC;AAAA,QACH;AACA,eAAO;AAAA,MACT;AACA,YAAM,QAAQ;AAAA,QACZ;AAAA,QACA,QAAQ,QAAQ,iBAAiB;AAAA,MACnC;AAEA,UAAI,OAAO;AACT,YAAI,YAAY,QAAQ,QAAQ,iBAAiB;AAC/C,kBAAQ,QAAQ,WAAW,IAAI;AAC/B,kBAAQ,QAAQ,SAAS,IAAI;AAC7B,kBAAQ,QAAQ,gBAAgB;AAAA,QAClC,OAAO;AACL,sBAAY,QAAQ,2BAA2B;AAAA,QACjD;AACA,eAAO;AAAA,MACT;AAEA,UAAI,CAAC,kBAAkB,cAAc,CAAC,GAAG;AACvC,iBAAS,EAAE,UAAU;AAAA,MACvB;AACA,oBAAc,gBAAgB;AAE9B,UAAI,QAAQ,QAAQ,SAAS,OAAO;AAClC,cAAM,YAAY,cAAc;AAEhC,YAAI,kBAAkB,SAAS,GAAG;AAChC,oBAAU,cAAc,IAAI;AAAA,QAC9B;AAAA,MACF,OAAO;AACL;AAAA,UACE,iCAAiC,MAAMA,qBAAoB;AAAA,QAC7D;AAAA,MACF;AACA,UAAI,UAAU;AACZ,gBAAQ,QAAQ,WAAW,IAAI;AAAA,MACjC;AACA,kBAAY,EAAE;AAEd,aAAO;AAAA,IACT;AACA,UAAM,cAAc,CAAC,UAAgC;AACnD,UACE,CAAC,SACD,OAAO,YAAY,KACnB,MAAM,eACN,MAAM,YAAY,OAClB,MAAM,YACN,CAAC,QAAQ,QAAQ,UACjB;AACA,eAAO;AAAA,MACT;AACA,YAAM,SAAS,QAAQ,QAAQ,gBAC3B,CAAC,MAAM,UAAU,CAAC,MAAM,WAAW,CAAC,MAAM,WACzC,MAAM,WAAW,MAAM,YAAY,CAAC,MAAM;AAE/C,UAAI,CAAC,QAAQ;AACX,eAAO;AAAA,MACT;AACA,YAAM,eAAe;AACrB,cAAQ,QAAQ,SAAS;AAEzB,aAAO;AAAA,IACT;AAEA,WAAOC;AAAA,MACL,OAAO,uBAAuB,YAAY;AAAA,MAC1C,OAAO,gBAAgB,eAAe,aAAa,qBAAqB;AAAA,MACxE,OAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,MAAM,QAAQ,QAAQ,sBAAsB,KAAK;AAAA,IACnD;AAAA,EACF,GAAG,CAAC,QAAQ,WAAW,CAAC;AAExB,YAAU,MAAM;AACd,QAAI,QAAQ,UAAU,UAAU,SAAS;AACvC;AAAA,IACF;AACA,UAAM,QAAQ;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ,iBAAiB;AAAA,IAC3B;AAEA,QAAI,OAAO;AACT,wBAAkB,KAAK;AAEvB;AAAA,IACF;AAEA,cAAU,UAAU,QAAQ;AAC5B,WAAO;AAAA,MACL,MAAMC,4BAA2B,QAAQ,OAAOF,qBAAoB;AAAA,MACpE;AAAA,QACE,KAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,QAAQ,OAAO,QAAQ,eAAe,iBAAiB,CAAC;AACpE,YAAU,MAAM;AACd,WAAO,YAAY,CAAC,QAAQ,QAAQ;AAAA,EACtC,GAAG,CAAC,QAAQ,QAAQ,QAAQ,CAAC;AAE7B,SAAO;AACT;;;AJ1KM,SACE,KADF;AAnCN,IAAM,cAAc,CAAC,QAAgBG,SAAQ,GAAG,MAAM;AAE/C,SAAS,mBAAmB,OAAgC;AACjE,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,CAAC,aAAa,cAAc,IAAI;AAAA,IAAS,MAC7C,gBAAgB,MAAM,OAAO,MAAM,iBAAiB,GAAM;AAAA,EAC5D;AACA,EAAAC,WAAU,MAAM;AACd,QAAI,aAAa;AACf;AAAA,QACE,gBAAgB,MAAM,OAAO,MAAM,iBAAiB,GAAM;AAAA,MAC5D;AAAA,IACF;AAAA,EACF,GAAG,CAAC,MAAM,OAAO,MAAM,eAAe,WAAW,CAAC;AAClD,QAAM,eAAeC,QAAO,MAAM,KAAK;AACvC,eAAa,UAAU,MAAM;AAC7B,QAAM,eAAeA,QAAO,MAAM,iBAAiB,GAAM;AACzD,eAAa,UAAU,MAAM,iBAAiB;AAC9C,QAAM,gBAAgB,MAAM,iBAAiB;AAE7C,MAAI,CAAC,OAAO,cAAc,aAAa,KAAK,gBAAgB,GAAG;AAC7D,UAAM,IAAI,WAAW,+CAA+C;AAAA,EACtE;AACA,QAAM,YAAY;AAAA,IAChB,MACE,oBAAoB;AAAA,MAClB,WAAW,MAAM,aAAa;AAAA,MAC9B,UAAU,MAAM,aAAa;AAAA,MAC7B,SAAS,CAACC,WAAU,SAASA,OAAM,OAAO;AAAA,IAC5C,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAEA,MAAI,MAAM,MAAM,SAAS,iBAAiB,aAAa;AACrD,WACE,qBAAC,SACC;AAAA,0BAAC,OAAE,MAAK,UACL,yBACC,4FACJ;AAAA,MACC,MAAM,mBACL,oBAAC,YAAO,MAAK,UAAS,SAAS,MAAM,iBAAiB,yBAEtD;AAAA,OAEJ;AAAA,EAEJ;AACA,QAAM,cAAc,MAAM,eAAe;AAEzC,SACE,qBAAC,SAAI,WAAU,sBACb;AAAA,yBAAC,4BAAyB,WAAsB,iBAAiB,MAC/D;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAI,MAAM;AAAA,UACV,MAAK;AAAA,UACL,cAAY,MAAM,SAAS;AAAA,UAC3B,kBAAe;AAAA,UACf,oBAAkB;AAAA,UAClB,aACE,oBAAC,UAAK,WAAU,2BAA2B,uBAAY;AAAA,UAEzD,WAAU;AAAA,UACV,oBAAoB,MAAM,MAAM,sBAAsB,IAAI;AAAA,UAC1D,kBAAkB,MAAM,MAAM,sBAAsB,KAAK;AAAA;AAAA,MAC3D;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,aAAa;AAAA,UACb,mBAAmB;AAAA;AAAA,MACrB;AAAA,MACA,oBAAC,cAAW;AAAA,MACZ,oBAAC,cAAW,aAA0B;AAAA,MACrC,MAAM,SAAS,SACd,oBAAC,0BAAuB,cAAcC,uBAAsB;AAAA,OAEhE;AAAA,IACC,SAAS,oBAAC,OAAE,MAAK,SAAS,iBAAM;AAAA,IAChC,SAAS,MAAM,mBACd,oBAAC,YAAO,MAAK,UAAS,SAAS,MAAM,iBAAiB,yBAEtD;AAAA,KAEJ;AAEJ;AAEA,IAAO,6BAAQ;","names":["useEffect","useRef","DEFAULT_TRANSFORMERS","safeUrl","LinkNode","LinkNode","mergeRegister","$convertFromMarkdownString","DEFAULT_TRANSFORMERS","DEFAULT_TRANSFORMERS","mergeRegister","$convertFromMarkdownString","safeUrl","useEffect","useRef","error","DEFAULT_TRANSFORMERS"]}
@@ -0,0 +1,52 @@
1
+ // src/rendering/HighlightOverlay.tsx
2
+ import { forwardRef } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ var highlightColors = {
5
+ keyword: "var(--texion-highlight-keyword, #1d4ed8)",
6
+ comment: "var(--texion-highlight-comment, #64748b)",
7
+ property: "var(--texion-highlight-property, #7e22ce)",
8
+ string: "var(--texion-highlight-string, #047857)",
9
+ number: "var(--texion-highlight-number, #b45309)",
10
+ boolean: "var(--texion-highlight-boolean, #1d4ed8)",
11
+ null: "var(--texion-highlight-null, #a21caf)",
12
+ punctuation: "var(--texion-highlight-punctuation, #64748b)",
13
+ heading: "var(--texion-highlight-heading, #1d4ed8)",
14
+ bold: "var(--texion-highlight-bold, #7e22ce)",
15
+ italic: "var(--texion-highlight-italic, #a21caf)",
16
+ code: "var(--texion-highlight-code, #047857)",
17
+ link: "var(--texion-highlight-link, #0369a1)",
18
+ strikethrough: "var(--texion-highlight-strikethrough, #64748b)",
19
+ "list-marker": "var(--texion-highlight-marker, #b45309)",
20
+ blockquote: "var(--texion-highlight-quote, #64748b)",
21
+ frontmatter: "var(--texion-highlight-frontmatter, #64748b)",
22
+ "thematic-break": "var(--texion-highlight-marker, #b45309)"
23
+ };
24
+ var HighlightOverlay = forwardRef(function HighlightOverlay2({ model, style }, ref) {
25
+ return /* @__PURE__ */ jsxs(
26
+ "div",
27
+ {
28
+ ref,
29
+ className: "texion-highlight-overlay",
30
+ "data-texion-highlight-overlay": "",
31
+ style,
32
+ children: [
33
+ model.segments.map((segment) => /* @__PURE__ */ jsx(
34
+ "span",
35
+ {
36
+ "data-highlight-kind": segment.kind,
37
+ style: segment.kind ? { color: highlightColors[segment.kind] } : void 0,
38
+ children: model.text.slice(segment.start, segment.end)
39
+ },
40
+ segment.start
41
+ )),
42
+ /* @__PURE__ */ jsx("span", { "data-texion-highlight-sentinel": "", children: "\u200B" })
43
+ ]
44
+ }
45
+ );
46
+ });
47
+
48
+ export {
49
+ highlightColors,
50
+ HighlightOverlay
51
+ };
52
+ //# sourceMappingURL=chunk-T56S7VW3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/rendering/HighlightOverlay.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport type { CSSProperties } from 'react';\nimport type { HighlightKind, HighlightModel } from '@texion/core';\n\nexport const highlightColors: Record<HighlightKind, string> = {\n keyword: 'var(--texion-highlight-keyword, #1d4ed8)',\n comment: 'var(--texion-highlight-comment, #64748b)',\n property: 'var(--texion-highlight-property, #7e22ce)',\n string: 'var(--texion-highlight-string, #047857)',\n number: 'var(--texion-highlight-number, #b45309)',\n boolean: 'var(--texion-highlight-boolean, #1d4ed8)',\n null: 'var(--texion-highlight-null, #a21caf)',\n punctuation: 'var(--texion-highlight-punctuation, #64748b)',\n heading: 'var(--texion-highlight-heading, #1d4ed8)',\n bold: 'var(--texion-highlight-bold, #7e22ce)',\n italic: 'var(--texion-highlight-italic, #a21caf)',\n code: 'var(--texion-highlight-code, #047857)',\n link: 'var(--texion-highlight-link, #0369a1)',\n strikethrough: 'var(--texion-highlight-strikethrough, #64748b)',\n 'list-marker': 'var(--texion-highlight-marker, #b45309)',\n blockquote: 'var(--texion-highlight-quote, #64748b)',\n frontmatter: 'var(--texion-highlight-frontmatter, #64748b)',\n 'thematic-break': 'var(--texion-highlight-marker, #b45309)',\n};\n\nexport const HighlightOverlay = forwardRef<\n HTMLDivElement,\n { readonly model: HighlightModel; readonly style: CSSProperties }\n>(function HighlightOverlay({ model, style }, ref) {\n return (\n <div\n ref={ref}\n className=\"texion-highlight-overlay\"\n data-texion-highlight-overlay=\"\"\n style={style}\n >\n {model.segments.map((segment) => (\n <span\n key={segment.start}\n data-highlight-kind={segment.kind}\n style={\n segment.kind ? { color: highlightColors[segment.kind] } : undefined\n }\n >\n {model.text.slice(segment.start, segment.end)}\n </span>\n ))}\n {/* A zero-width sentinel gives a trailing newline the same final line as the textarea. */}\n <span data-texion-highlight-sentinel=\"\">{'\\u200b'}</span>\n </div>\n );\n});\n"],"mappings":";AAAA,SAAS,kBAAkB;AA8BvB,SAOI,KAPJ;AA1BG,IAAM,kBAAiD;AAAA,EAC5D,SAAS;AAAA,EACT,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AAAA,EACN,aAAa;AAAA,EACb,SAAS;AAAA,EACT,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,eAAe;AAAA,EACf,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,kBAAkB;AACpB;AAEO,IAAM,mBAAmB,WAG9B,SAASA,kBAAiB,EAAE,OAAO,MAAM,GAAG,KAAK;AACjD,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAU;AAAA,MACV,iCAA8B;AAAA,MAC9B;AAAA,MAEC;AAAA,cAAM,SAAS,IAAI,CAAC,YACnB;AAAA,UAAC;AAAA;AAAA,YAEC,uBAAqB,QAAQ;AAAA,YAC7B,OACE,QAAQ,OAAO,EAAE,OAAO,gBAAgB,QAAQ,IAAI,EAAE,IAAI;AAAA,YAG3D,gBAAM,KAAK,MAAM,QAAQ,OAAO,QAAQ,GAAG;AAAA;AAAA,UANvC,QAAQ;AAAA,QAOf,CACD;AAAA,QAED,oBAAC,UAAK,kCAA+B,IAAI,oBAAS;AAAA;AAAA;AAAA,EACpD;AAEJ,CAAC;","names":["HighlightOverlay"]}
@@ -0,0 +1,36 @@
1
+ // src/renderers/csv/index.tsx
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ function CsvRenderer({ preview }) {
4
+ const table = preview.nodes.find((node) => node.type === "csv-table");
5
+ if (!table) {
6
+ return /* @__PURE__ */ jsx("pre", { children: preview.nodes.map((node) => node.value ?? "").join("") });
7
+ }
8
+ const rows = table.children ?? [];
9
+ const columns = rows.reduce(
10
+ (maximum, row) => Math.max(maximum, row.children?.length ?? 0),
11
+ 0
12
+ );
13
+ return /* @__PURE__ */ jsx(
14
+ "div",
15
+ {
16
+ className: "texion-csv-viewer",
17
+ tabIndex: 0,
18
+ role: "region",
19
+ "aria-label": "Scrollable CSV table",
20
+ children: /* @__PURE__ */ jsxs("table", { children: [
21
+ /* @__PURE__ */ jsx("caption", { children: "CSV data" }),
22
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: Array.from({ length: columns }, (_, index) => /* @__PURE__ */ jsxs("th", { scope: "col", children: [
23
+ "Column ",
24
+ index + 1
25
+ ] }, index)) }) }),
26
+ /* @__PURE__ */ jsx("tbody", { children: rows.map((row, index) => /* @__PURE__ */ jsx("tr", { children: row.children?.map((cell, column) => /* @__PURE__ */ jsx("td", { children: cell.children?.map((child) => child.value ?? "").join("") ?? cell.value ?? "" }, column)) }, index)) })
27
+ ] })
28
+ }
29
+ );
30
+ }
31
+ var csv_default = CsvRenderer;
32
+ export {
33
+ CsvRenderer,
34
+ csv_default as default
35
+ };
36
+ //# sourceMappingURL=csv-COGONMFA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/renderers/csv/index.tsx"],"sourcesContent":["import type { PreviewRendererProps } from '../types';\n\nexport function CsvRenderer({ preview }: PreviewRendererProps) {\n const table = preview.nodes.find((node) => node.type === 'csv-table');\n if (!table) {\n return <pre>{preview.nodes.map((node) => node.value ?? '').join('')}</pre>;\n }\n const rows = table.children ?? [];\n const columns = rows.reduce(\n (maximum, row) => Math.max(maximum, row.children?.length ?? 0),\n 0,\n );\n return (\n <div\n className=\"texion-csv-viewer\"\n tabIndex={0}\n role=\"region\"\n aria-label=\"Scrollable CSV table\"\n >\n <table>\n <caption>CSV data</caption>\n <thead>\n <tr>\n {Array.from({ length: columns }, (_, index) => (\n <th scope=\"col\" key={index}>\n Column {index + 1}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.map((row, index) => (\n <tr key={index}>\n {row.children?.map((cell, column) => (\n <td key={column}>\n {cell.children?.map((child) => child.value ?? '').join('') ??\n cell.value ??\n ''}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n );\n}\nexport default CsvRenderer;\n"],"mappings":";AAKW,cAmBG,YAnBH;AAHJ,SAAS,YAAY,EAAE,QAAQ,GAAyB;AAC7D,QAAM,QAAQ,QAAQ,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,WAAW;AACpE,MAAI,CAAC,OAAO;AACV,WAAO,oBAAC,SAAK,kBAAQ,MAAM,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,EAAE,KAAK,EAAE,GAAE;AAAA,EACtE;AACA,QAAM,OAAO,MAAM,YAAY,CAAC;AAChC,QAAM,UAAU,KAAK;AAAA,IACnB,CAAC,SAAS,QAAQ,KAAK,IAAI,SAAS,IAAI,UAAU,UAAU,CAAC;AAAA,IAC7D;AAAA,EACF;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,UAAU;AAAA,MACV,MAAK;AAAA,MACL,cAAW;AAAA,MAEX,+BAAC,WACC;AAAA,4BAAC,aAAQ,sBAAQ;AAAA,QACjB,oBAAC,WACC,8BAAC,QACE,gBAAM,KAAK,EAAE,QAAQ,QAAQ,GAAG,CAAC,GAAG,UACnC,qBAAC,QAAG,OAAM,OAAkB;AAAA;AAAA,UAClB,QAAQ;AAAA,aADG,KAErB,CACD,GACH,GACF;AAAA,QACA,oBAAC,WACE,eAAK,IAAI,CAAC,KAAK,UACd,oBAAC,QACE,cAAI,UAAU,IAAI,CAAC,MAAM,WACxB,oBAAC,QACE,eAAK,UAAU,IAAI,CAAC,UAAU,MAAM,SAAS,EAAE,EAAE,KAAK,EAAE,KACvD,KAAK,SACL,MAHK,MAIT,CACD,KAPM,KAQT,CACD,GACH;AAAA,SACF;AAAA;AAAA,EACF;AAEJ;AACA,IAAO,cAAQ;","names":[]}
@@ -0,0 +1,61 @@
1
+ // src/renderers/image/index.tsx
2
+ import { useState as useState2 } from "react";
3
+
4
+ // src/renderers/image/useObjectUrl.ts
5
+ import { useEffect, useState } from "react";
6
+ function useObjectUrl(blob, mimeType) {
7
+ const [current, setCurrent] = useState();
8
+ useEffect(() => {
9
+ if (!blob || typeof URL.createObjectURL !== "function") {
10
+ return;
11
+ }
12
+ const typed = mimeType && blob.type !== mimeType ? blob.slice(0, blob.size, mimeType) : blob;
13
+ const url = URL.createObjectURL(typed);
14
+ setCurrent({ blob, url });
15
+ return () => URL.revokeObjectURL(url);
16
+ }, [blob, mimeType]);
17
+ return current?.blob === blob ? current?.url : void 0;
18
+ }
19
+
20
+ // src/renderers/image/index.tsx
21
+ import { jsx, jsxs } from "react/jsx-runtime";
22
+ function ImageRenderer({ document, preview }) {
23
+ const image = preview.image;
24
+ const url = useObjectUrl(image ? document?.blob : void 0, image?.mimeType);
25
+ const [failedUrl, setFailedUrl] = useState2();
26
+ if (!image) {
27
+ return /* @__PURE__ */ jsx("p", { role: "status", children: "Image preview is unavailable." });
28
+ }
29
+ if (!url) {
30
+ return /* @__PURE__ */ jsx("p", { role: "status", children: "Preparing local image preview\u2026" });
31
+ }
32
+ if (failedUrl === url) {
33
+ return /* @__PURE__ */ jsx("p", { role: "alert", children: "This image could not be decoded. The original attachment is retained." });
34
+ }
35
+ return /* @__PURE__ */ jsxs("figure", { className: "texion-image-viewer", children: [
36
+ /* @__PURE__ */ jsx(
37
+ "img",
38
+ {
39
+ src: url,
40
+ alt: document?.name ?? "Uploaded image",
41
+ width: image.width,
42
+ height: image.height,
43
+ decoding: "async",
44
+ onError: () => setFailedUrl(url)
45
+ }
46
+ ),
47
+ /* @__PURE__ */ jsxs("figcaption", { children: [
48
+ image.width,
49
+ " \xD7 ",
50
+ image.height,
51
+ " \xB7 ",
52
+ image.mimeType
53
+ ] })
54
+ ] });
55
+ }
56
+ var image_default = ImageRenderer;
57
+ export {
58
+ ImageRenderer,
59
+ image_default as default
60
+ };
61
+ //# sourceMappingURL=image-TKOV52M6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/renderers/image/index.tsx","../src/renderers/image/useObjectUrl.ts"],"sourcesContent":["import { useState } from 'react';\nimport type { PreviewRendererProps } from '../types';\nimport { useObjectUrl } from './useObjectUrl';\n\nexport function ImageRenderer({ document, preview }: PreviewRendererProps) {\n const image = preview.image;\n const url = useObjectUrl(image ? document?.blob : undefined, image?.mimeType);\n const [failedUrl, setFailedUrl] = useState<string>();\n if (!image) {\n return <p role=\"status\">Image preview is unavailable.</p>;\n }\n if (!url) {\n return <p role=\"status\">Preparing local image preview…</p>;\n }\n if (failedUrl === url) {\n return (\n <p role=\"alert\">\n This image could not be decoded. The original attachment is retained.\n </p>\n );\n }\n return (\n <figure className=\"texion-image-viewer\">\n <img\n src={url}\n alt={document?.name ?? 'Uploaded image'}\n width={image.width}\n height={image.height}\n decoding=\"async\"\n onError={() => setFailedUrl(url)}\n />\n <figcaption>\n {image.width} × {image.height} · {image.mimeType}\n </figcaption>\n </figure>\n );\n}\nexport default ImageRenderer;\n","import { useEffect, useState } from 'react';\n\nexport function useObjectUrl(\n blob?: Blob,\n mimeType?: string,\n): string | undefined {\n const [current, setCurrent] = useState<{ blob: Blob; url: string }>();\n useEffect(() => {\n if (!blob || typeof URL.createObjectURL !== 'function') {\n return;\n }\n const typed =\n mimeType && blob.type !== mimeType\n ? blob.slice(0, blob.size, mimeType)\n : blob;\n const url = URL.createObjectURL(typed);\n setCurrent({ blob, url });\n return () => URL.revokeObjectURL(url);\n }, [blob, mimeType]);\n return current?.blob === blob ? current?.url : undefined;\n}\n"],"mappings":";AAAA,SAAS,YAAAA,iBAAgB;;;ACAzB,SAAS,WAAW,gBAAgB;AAE7B,SAAS,aACd,MACA,UACoB;AACpB,QAAM,CAAC,SAAS,UAAU,IAAI,SAAsC;AACpE,YAAU,MAAM;AACd,QAAI,CAAC,QAAQ,OAAO,IAAI,oBAAoB,YAAY;AACtD;AAAA,IACF;AACA,UAAM,QACJ,YAAY,KAAK,SAAS,WACtB,KAAK,MAAM,GAAG,KAAK,MAAM,QAAQ,IACjC;AACN,UAAM,MAAM,IAAI,gBAAgB,KAAK;AACrC,eAAW,EAAE,MAAM,IAAI,CAAC;AACxB,WAAO,MAAM,IAAI,gBAAgB,GAAG;AAAA,EACtC,GAAG,CAAC,MAAM,QAAQ,CAAC;AACnB,SAAO,SAAS,SAAS,OAAO,SAAS,MAAM;AACjD;;;ADXW,cAsBL,YAtBK;AALJ,SAAS,cAAc,EAAE,UAAU,QAAQ,GAAyB;AACzE,QAAM,QAAQ,QAAQ;AACtB,QAAM,MAAM,aAAa,QAAQ,UAAU,OAAO,QAAW,OAAO,QAAQ;AAC5E,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAiB;AACnD,MAAI,CAAC,OAAO;AACV,WAAO,oBAAC,OAAE,MAAK,UAAS,2CAA6B;AAAA,EACvD;AACA,MAAI,CAAC,KAAK;AACR,WAAO,oBAAC,OAAE,MAAK,UAAS,iDAA8B;AAAA,EACxD;AACA,MAAI,cAAc,KAAK;AACrB,WACE,oBAAC,OAAE,MAAK,SAAQ,mFAEhB;AAAA,EAEJ;AACA,SACE,qBAAC,YAAO,WAAU,uBAChB;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,KAAK,UAAU,QAAQ;AAAA,QACvB,OAAO,MAAM;AAAA,QACb,QAAQ,MAAM;AAAA,QACd,UAAS;AAAA,QACT,SAAS,MAAM,aAAa,GAAG;AAAA;AAAA,IACjC;AAAA,IACA,qBAAC,gBACE;AAAA,YAAM;AAAA,MAAM;AAAA,MAAI,MAAM;AAAA,MAAO;AAAA,MAAI,MAAM;AAAA,OAC1C;AAAA,KACF;AAEJ;AACA,IAAO,gBAAQ;","names":["useState","useState"]}