1 line
231 KiB
Plaintext
1 line
231 KiB
Plaintext
{"version":3,"mappings":"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","names":["Combobox","input","list","tabInsertsSuggestions","defaultFirstOption","event","keyboardBindings","trackComposition","commitWithElement","_a","visible","indexDiff","focusEl","els","focusIndex","indexOfItem","newIndex","target","el","scrollTo","combobox","commit","fireCommitEvent","container","inViewport","element","scrollTop","containerBottom","top","bottom","boundary","query","text","key","cursor","multiWord","lookBackIndex","lastMatchPosition","keyIndex","pre","CustomHTMLElement","InputStyleCloneUpdateEvent","CloneRegistry","_InputStyleCloneElement","__privateAdd","_InputStyleCloneElement_instances","_styleObserver","__privateMethod","updateStyles_fn","_resizeObserver","requestUpdateLayout_fn","_inputRef","_container","_xOffset","_yOffset","_isLayoutUpdating","_onInput","updateText_fn","_onDocumentScrollOrResize","usingInput_fn","clone","__privateSet","__privateGet","input_get","fn","updateLayout_fn","inputStyle","inputRect","cloneRect","prop","propertiesToCopy","InputStyleCloneElement","e","_InputRange","startOffset","endOffset","_InputRange_instances","_inputElement","_startOffset","_endOffset","selectionStart","selectionEnd","offset","clampOffset_fn","toStart","createCloneRange_fn","styleClone_get","cloneElement_get","range","textNode","InputRange","states","TextExpander","expander","match","menu","_b","position","caretRect","targetPosition","currentPosition","delta","currentStyle","item","beginning","remaining","detail","suffix","value","found","providers","provide","result","changeEvent","x","TextExpanderElement","keysAttr","keys","multiWordAttr","globalMultiWord","state","ansiRegex","onlyFirst","pattern","regex","stripAnsi","string","segmenter","stringLength","countAnsiEscapeCodes","length","_","poweredByGiphyURL","PHANPY_IMG_ALT_API_URL","IMG_ALT_API_URL","PHANPY_GIPHY_API_KEY","GIPHY_API_KEY","import","supportedLanguagesMap","supportedLanguages","reduce","acc","l","code","common","native","expiryOptions","i18nDuration","expirySeconds","Object","oneDay","expiresInFromExpiresAt","expiresAt","Date","getTime","now","find","s","document","createElement","role","className","windowMargin","observer","IntersectionObserver","entries","forEach","entry","isIntersecting","left","width","boundingClientRect","innerWidth","window","insetInlineStart","isRTL","style","observe","DEFAULT_LANG","localeMatch","Intl","DateTimeFormat","resolvedOptions","locale","navigator","languages","map","urlRegexObj","RegExp","urlRegex","source","flags","usernameRegex","urlPlaceholder","countableText","inputText","replace","USERNAME_RE","MENTION_RE","HASHTAG_RE","SHORTCODE_RE_FRAGMENT","SCAN_RE","Segmenter","escapeHTML","highlightText","maxCharacters","Infinity","composerCharacterCount","withinLimitHTML","exceedLimitHTML","htmlSegments","segment","index","RTF","mem","RelativeTimeFormat","undefined","LF","ListFormat","CUSTOM_EMOJIS_COUNT","ADD_LABELS","camera","id","media","customEmoji","gif","poll","scheduledPost","Compose","onClose","replyToStatus","editStatus","draftStatus","standalone","hasOpener","i18n","t","_useLingui","rtf","lf","console","masto","instance","uiState","setUIState","useState","UID","uid","log","currentAccount","currentAccountInfo","maxMediaAttachments","charactersReservedPerUrl","imageMatrixLimit","supportedMimeTypes","imageSizeLimit","videoSizeLimit","videoMatrixLimit","videoFrameRateLimit","maxExpiration","maxOptions","maxCharactersPerOption","minExpiration","textareaRef","useRef","supportedImagesVideosTypes","spoilerTextRef","store","prevLanguage","language","sensitive","setMediaAttachments","setLanguage","prefs","oninputTextarea","scheduledAt","account","focusTextarea","dispatchEvent","setTimeout","spoilerText","useEffect","visibility2","language2","sensitive2","visibility","current","m","allMentions","Set","setSensitive","poll2","mediaAttachments","options","expiresIn","statusSource","dataset","mediaAttachments2","setVisibility","composablePoll","scheduledAt2","status","o","canClose","_t","hasValue","hasMediaAttachments","isSelf","hasOnlyAcct","confirmClose","hasIDMediaAttachments","beforeUnloadCopy","handleBeforeUnload","sameWithSource","getCharCount","updateCharCount","supportsCloseWatcher","useHotkeys","yes","addEventListener","capture","modals","hasModal","hasOnlyComposer","prevBackgroundDraft","count","escDownRef","useCloseWatcher","db","ns","backgroundDraft","useInterval","saveUnsavedDraft","draftKey","username","acct","unsupportedFiles","i2","items","_i18n","drafts","set","updatedAt","f","debug","error","files","clipboardData","max","file","alert","mediaFiles","allowedFiles","1","2","handleDragover","handleItems","setShowMentionPicker","showEmoji2Picker","showGIFPicker","useMemo","contentTranslationHideLanguages","autoDetectedLanguages","topLanguages","restLanguages","commonB","type","size","url","codeA","commonA","codeB","onMinimize","gifPickerDisabled","onPollButtonClick","setPoll","removeEventListener","addSubToolbarRef","setShowAddButton","useResizeObserver","showMentionPicker","scrollWidth","settings","scheduledAtButtonDisabled","onScheduledAtClick","sort","MIN_SCHEDULED_AT","replyToStatusMonthsAgo","_jsx","children","class","confirmText","passData","opener","composerState","Icon","_jsxs","showAddButton","openCompose","avatarStatic","onClick","Status","_Trans","__STATES__","formRef","formData","components","option","description","params2","res","attachment","results","mediaPromises","hasNoDescriptions","params","removeNullUndefined","allSettled","newStatus","i","supports","media_attributes","in_reply_to_id","saveStatus","visibilityIconsMap","opacity","pointerEvents","checked","disabled","onChange","icon","title","limit","action","setShowEmoji2Picker","setAutoDetectedLanguages","Textarea","ref","fileID","newAttachments","attachments","_2","j","q","v1","resolve","v2","fetch","onTrigger","defaultSearchTerm","Poll","newPoll","onDescriptionChange","setScheduledAt","onRemove","ScheduledAtField","getLocalTimezoneName","Menu2","onInput","supportsCameraCapture","MenuItem","CameraCaptureInput","0","body","open","showPollButton","pollButtonDisabled","showScheduledAt","FilePickerInput","composerGIFPicker","setShowGIFPicker","_Fragment","alt","Loader","topSupportedLanguages","commonText","localeCode2Text","MentionModal","socialAddress","textarea","textBeforeMention","spaceBeforeMention","textAfterMention","spaceAfterMention","newText","CustomEmojisModal","textBeforeEmoji","spaceBeforeEmoji","textAfterEmoji","spaceAfterEmoji","emojiShortcode","onSelect","blob","alt_text","showToast","hidden","theToast","mediaFile","newMediaAttachments","accept","Array","offsetHeight","scrollHeight","clientHeight","height","visibleEmojis","createObjectURL","langs2","lang","detectAll","langs","forwardRef","props","_t2","setText","performSearch","r","searcherRef","textExpanderRef","_getCustomEmojis","emojis","searcher","Fuse","handleCommited","handleActivate","handleDeactivate","handleChange","getCustomEmojis","textExpanderTextRef","text2","cacheKeyArg","detectLangs","langDetector","html","shortcode","emoji","encodeHTML","textareaProps","hasTextExpanderRef","history","displayNameWithEmoji","emojifyText","displayName","search","total","cur","name","shortenNumber","Promise","then","v","more","handleValue","matched","slowHighlightPerf","composeHighlightRef","useThrottledCallback","throttleHighlightText","start","end","useDebouncedCallback","dom","Event","resizeObserver","hasTextExpander","lastLine","bullet","postSpaces","anything","number","preSpaces","pos","debouncedAutoDetectLanguage","cloneNode","mark","autoResizeTextarea","rows","cols","onKeyDown","charCount","leftChars","setRangeText","setSelectionRange","scaleDimension","matrix","matrixLimit","scalingFactor","newHeight","newWidth","MediaAttachment","supportsEdit","onScroll","checkMaxError","configuration","getCurrentInstanceConfiguration","maxError","setMaxError","snapStates","imageMatrix","setImageMatrix","Math","videoMatrix","setVideoMatrix","debouncedOnDescriptionChange","timer","details","_t3","toastRef","setDescription","showModal","imageSizeLimit2","descTextarea","prettyBytes","videoSize","videoSizeLimit2","videoMatrixLimit2","videoMatrix2","maxErrorToast","maxErrorText","err","imageSize","suffixType","naturalWidth","naturalHeight","3","4","5","videoWidth","videoHeight","6","7","values","9","10","setShowModal","src","onLoad","Modal","onLoadedMetadata","subtype","response","zIndex","menuButton","append","_t4","multiple","required","label","splice","str","char","obj","push","api","accounts","setAccounts","setRelationshipsMap","selectedIndex","setSelectedIndex","loadRelationships","accounts2","term","debouncedLoadAccounts","loadAccounts","inputRef","filterShortcodes","searchTerm","aLower","a","bLower","b","aContains","bContains","bothStartWith","slice","selectAccount","selectedAccount","listRef","selectedItem","relationshipsMap","relationships","_t5","enableOnFormTags","relationship","AccountBlock","onSubmit","_t6","customEmojisList","customEmojis","setCustomEmojis","recentlyUsedCustomEmojis","emojisCat","othersCat","scrollableRef","matches","setMatches","onFind","_c","onSelectEmoji","useCallback","recentlyUsedCustomEmojis2","recentlyUsedEmojiIndex","emoji2","customEmojisCatList","category","queueMicrotask","CustomEmojisList","memo","setMax","CustomEmojiButton","showMore","showCode","parent","selfRect","rect","targetClassList","addEdges","GIFS_PER_PAGE","GIFPickerModal","_t7","setResults","fetchGIFs","qRef","closest","currentTarget","remove","debouncedOnInput","onPointerEnter","onFocus","staticUrl","currentOffset","images","fixed_height_small","fixed_height_downsampled","fixed_height","theImage","webp","urlObj","strippedURL","strippedWebP","preventDefault","original","theURL","mp4","url2","strippedURL2","webpObj","parse"],"ignoreList":[0,1,2,3,4],"sources":["../../node_modules/@github/combobox-nav/dist/index.js","../../node_modules/@github/text-expander-element/dist/index.js","../../node_modules/ansi-regex/index.js","../../node_modules/strip-ansi/index.js","../../node_modules/string-length/index.js","../../src/assets/powered-by-giphy.svg","../../src/components/compose.jsx"],"sourcesContent":["export default class Combobox {\n constructor(input, list, { tabInsertsSuggestions, defaultFirstOption } = {}) {\n this.input = input;\n this.list = list;\n this.tabInsertsSuggestions = tabInsertsSuggestions !== null && tabInsertsSuggestions !== void 0 ? tabInsertsSuggestions : true;\n this.defaultFirstOption = defaultFirstOption !== null && defaultFirstOption !== void 0 ? defaultFirstOption : false;\n this.isComposing = false;\n if (!list.id) {\n list.id = `combobox-${Math.random().toString().slice(2, 6)}`;\n }\n this.ctrlBindings = !!navigator.userAgent.match(/Macintosh/);\n this.keyboardEventHandler = event => keyboardBindings(event, this);\n this.compositionEventHandler = event => trackComposition(event, this);\n this.inputHandler = this.clearSelection.bind(this);\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-controls', list.id);\n input.setAttribute('aria-expanded', 'false');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-haspopup', 'listbox');\n }\n destroy() {\n this.clearSelection();\n this.stop();\n this.input.removeAttribute('role');\n this.input.removeAttribute('aria-controls');\n this.input.removeAttribute('aria-expanded');\n this.input.removeAttribute('aria-autocomplete');\n this.input.removeAttribute('aria-haspopup');\n }\n start() {\n this.input.setAttribute('aria-expanded', 'true');\n this.input.addEventListener('compositionstart', this.compositionEventHandler);\n this.input.addEventListener('compositionend', this.compositionEventHandler);\n this.input.addEventListener('input', this.inputHandler);\n this.input.addEventListener('keydown', this.keyboardEventHandler);\n this.list.addEventListener('click', commitWithElement);\n this.indicateDefaultOption();\n }\n stop() {\n this.clearSelection();\n this.input.setAttribute('aria-expanded', 'false');\n this.input.removeEventListener('compositionstart', this.compositionEventHandler);\n this.input.removeEventListener('compositionend', this.compositionEventHandler);\n this.input.removeEventListener('input', this.inputHandler);\n this.input.removeEventListener('keydown', this.keyboardEventHandler);\n this.list.removeEventListener('click', commitWithElement);\n }\n indicateDefaultOption() {\n var _a;\n if (this.defaultFirstOption) {\n (_a = Array.from(this.list.querySelectorAll('[role=\"option\"]:not([aria-disabled=\"true\"])'))\n .filter(visible)[0]) === null || _a === void 0 ? void 0 : _a.setAttribute('data-combobox-option-default', 'true');\n }\n }\n navigate(indexDiff = 1) {\n const focusEl = Array.from(this.list.querySelectorAll('[aria-selected=\"true\"]')).filter(visible)[0];\n const els = Array.from(this.list.querySelectorAll('[role=\"option\"]')).filter(visible);\n const focusIndex = els.indexOf(focusEl);\n if ((focusIndex === els.length - 1 && indexDiff === 1) || (focusIndex === 0 && indexDiff === -1)) {\n this.clearSelection();\n this.input.focus();\n return;\n }\n let indexOfItem = indexDiff === 1 ? 0 : els.length - 1;\n if (focusEl && focusIndex >= 0) {\n const newIndex = focusIndex + indexDiff;\n if (newIndex >= 0 && newIndex < els.length)\n indexOfItem = newIndex;\n }\n const target = els[indexOfItem];\n if (!target)\n return;\n for (const el of els) {\n el.removeAttribute('data-combobox-option-default');\n if (target === el) {\n this.input.setAttribute('aria-activedescendant', target.id);\n target.setAttribute('aria-selected', 'true');\n scrollTo(this.list, target);\n }\n else {\n el.removeAttribute('aria-selected');\n }\n }\n }\n clearSelection() {\n this.input.removeAttribute('aria-activedescendant');\n for (const el of this.list.querySelectorAll('[aria-selected=\"true\"]')) {\n el.removeAttribute('aria-selected');\n }\n this.indicateDefaultOption();\n }\n}\nfunction keyboardBindings(event, combobox) {\n if (event.shiftKey || event.metaKey || event.altKey)\n return;\n if (!combobox.ctrlBindings && event.ctrlKey)\n return;\n if (combobox.isComposing)\n return;\n switch (event.key) {\n case 'Enter':\n if (commit(combobox.input, combobox.list)) {\n event.preventDefault();\n }\n break;\n case 'Tab':\n if (combobox.tabInsertsSuggestions && commit(combobox.input, combobox.list)) {\n event.preventDefault();\n }\n break;\n case 'Escape':\n combobox.clearSelection();\n break;\n case 'ArrowDown':\n combobox.navigate(1);\n event.preventDefault();\n break;\n case 'ArrowUp':\n combobox.navigate(-1);\n event.preventDefault();\n break;\n case 'n':\n if (combobox.ctrlBindings && event.ctrlKey) {\n combobox.navigate(1);\n event.preventDefault();\n }\n break;\n case 'p':\n if (combobox.ctrlBindings && event.ctrlKey) {\n combobox.navigate(-1);\n event.preventDefault();\n }\n break;\n default:\n if (event.ctrlKey)\n break;\n combobox.clearSelection();\n }\n}\nfunction commitWithElement(event) {\n if (!(event.target instanceof Element))\n return;\n const target = event.target.closest('[role=\"option\"]');\n if (!target)\n return;\n if (target.getAttribute('aria-disabled') === 'true')\n return;\n fireCommitEvent(target);\n}\nfunction commit(input, list) {\n const target = list.querySelector('[aria-selected=\"true\"], [data-combobox-option-default=\"true\"]');\n if (!target)\n return false;\n if (target.getAttribute('aria-disabled') === 'true')\n return true;\n target.click();\n return true;\n}\nfunction fireCommitEvent(target) {\n target.dispatchEvent(new CustomEvent('combobox-commit', { bubbles: true }));\n}\nfunction visible(el) {\n return (!el.hidden &&\n !(el instanceof HTMLInputElement && el.type === 'hidden') &&\n (el.offsetWidth > 0 || el.offsetHeight > 0));\n}\nfunction trackComposition(event, combobox) {\n combobox.isComposing = event.type === 'compositionstart';\n const list = document.getElementById(combobox.input.getAttribute('aria-controls') || '');\n if (!list)\n return;\n combobox.clearSelection();\n}\nfunction scrollTo(container, target) {\n if (!inViewport(container, target)) {\n container.scrollTop = target.offsetTop;\n }\n}\nfunction inViewport(container, element) {\n const scrollTop = container.scrollTop;\n const containerBottom = scrollTop + container.clientHeight;\n const top = element.offsetTop;\n const bottom = top + element.clientHeight;\n return top >= scrollTop && bottom <= containerBottom;\n}\n","import Combobox from '@github/combobox-nav';\n\nconst boundary = /\\s|\\(|\\[/;\nfunction query(text, key, cursor, { multiWord, lookBackIndex, lastMatchPosition } = {\n multiWord: false,\n lookBackIndex: 0,\n lastMatchPosition: null\n}) {\n let keyIndex = text.lastIndexOf(key, cursor - 1);\n if (keyIndex === -1)\n return;\n if (keyIndex < lookBackIndex)\n return;\n if (multiWord) {\n if (lastMatchPosition != null) {\n if (lastMatchPosition === keyIndex)\n return;\n keyIndex = lastMatchPosition - key.length;\n }\n const charAfterKey = text[keyIndex + 1];\n if (charAfterKey === ' ' && cursor >= keyIndex + key.length + 1)\n return;\n const newLineIndex = text.lastIndexOf('\\n', cursor - 1);\n if (newLineIndex > keyIndex)\n return;\n const dotIndex = text.lastIndexOf('.', cursor - 1);\n if (dotIndex > keyIndex)\n return;\n }\n else {\n const spaceIndex = text.lastIndexOf(' ', cursor - 1);\n if (spaceIndex > keyIndex)\n return;\n }\n const pre = text[keyIndex - 1];\n if (pre && !boundary.test(pre))\n return;\n const queryString = text.substring(keyIndex + key.length, cursor);\n return {\n text: queryString,\n position: keyIndex + key.length\n };\n}\n\n/**\n * A custom element is implemented as a class which extends HTMLElement (in the\n * case of autonomous elements) or the interface you want to customize (in the\n * case of customized built-in elements).\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#custom_element_lifecycle_callbacks\n */\nclass CustomHTMLElement extends HTMLElement {\n}\n\nclass InputStyleCloneUpdateEvent extends Event {\n constructor() {\n super(\"update\");\n }\n}\nconst CloneRegistry = new WeakMap();\n/**\n * Create an element that exactly matches an input pixel-for-pixel and automatically stays in sync with it. This\n * is a non-interactive overlay on to the input and can be used to affect the visual appearance of the input\n * without modifying its behavior. The clone element is hidden by default.\n *\n * This lower level API powers the `InputRange` but provides more advanced functionality including event updates.\n *\n * Emits `update` events whenever anything is recalculated: when the layout changes, when the user scrolls, when the\n * input is updated, etc. This event may be emitted more than once per change.\n *\n * @note There may be cases in which the clone cannot observe changes to the input and fails to automatically update.\n * For example, if the `value` property on the input is written to directly, no `input` event is emitted by the input\n * and the clone does not automatically update. In these cases, `forceUpdate` can be used to manually trigger an update.\n */\n// PRIOR ART: This approach was adapted from the following MIT-licensed sources:\n// - primer/react (Copyright (c) 2018 GitHub, Inc.): https://github.com/primer/react/blob/a0db832302702b869aa22b0c4049ad9305ef631f/src/drafts/utils/character-coordinates.ts\n// - component/textarea-caret-position (Copyright (c) 2015 Jonathan Ong me@jongleberry.com): https://github.com/component/textarea-caret-position/blob/b5db7a7e47dd149c2a66276183c69234e4dabe30/index.js\n// - koddsson/textarea-caret-position (Copyright (c) 2015 Jonathan Ong me@jongleberry.com): https://github.com/koddsson/textarea-caret-position/blob/eba40ec8488eed4d77815f109af22e1d9c0751d3/index.js\nclass InputStyleCloneElement extends CustomHTMLElement {\n #styleObserver = new MutationObserver(() => this.#updateStyles());\n #resizeObserver = new ResizeObserver(() => this.#requestUpdateLayout());\n // This class is unique in that it will prevent itself from getting garbage collected because of the subscribed\n // observers (if never detached). Because of this, we want to avoid preventing the existence of this class from also\n // preventing the garbage collection of the associated input. This also allows us to automatically detach if the\n // input gets collected.\n #inputRef;\n #container;\n /**\n * Get the clone for an input, reusing an existing one if available. This avoids creating unecessary clones, which\n * have a performance cost due to their high-frequency event-based updates. Because these elements are shared, they\n * should be mutated with caution.\n *\n * Upon initial creation the clone element will automatically be inserted into the DOM and begin observing the\n * linked input. Only one clone per input can ever exist at a time.\n * @param input The target input to clone.\n */\n static for(input) {\n let clone = CloneRegistry.get(input);\n if (!clone) {\n clone = new InputStyleCloneElement();\n clone.connect(input);\n CloneRegistry.set(input, clone);\n }\n return clone;\n }\n /**\n * Connect this instance to a target input element and insert this instance into the DOM in the correct location.\n *\n * NOTE: calling the static `for` method is nearly always preferable as it will reuse an existing clone if available.\n * However, if reusing clones is problematic (ie, if the clone needs to be mutated), a clone can be constructed\n * directly with `new InputStyleCloneElement()` and then bound to an input and inserted into the DOM with\n * `clone.connect(target)`.\n */\n connect(input) {\n this.#inputRef = new WeakRef(input);\n // We want position:absolute so it doesn't take space in the layout, but that doesn't work with display:table-cell\n // used in the HTMLInputElement approach. So we need a wrapper.\n this.#container = document.createElement(\"div\");\n this.#container.style.position = \"absolute\";\n this.#container.style.pointerEvents = \"none\";\n input.after(this.#container);\n this.#container.appendChild(this);\n }\n /**\n * Force a recalculation. Will emit an `update` event. This is typically not needed unless the input has changed in\n * an unobservable way, eg by directly writing to the `value` property.\n */\n forceUpdate() {\n this.#updateStyles();\n this.#updateText();\n }\n /** @private */\n connectedCallback() {\n this.#usingInput((input) => {\n this.style.pointerEvents = \"none\";\n this.style.userSelect = \"none\";\n this.style.overflow = \"hidden\";\n this.style.display = \"block\";\n // Important not to use display:none which would not render the content at all\n this.style.visibility = \"hidden\";\n if (input instanceof HTMLTextAreaElement) {\n this.style.whiteSpace = \"pre-wrap\";\n this.style.wordWrap = \"break-word\";\n }\n else {\n this.style.whiteSpace = \"nowrap\";\n // text in single-line inputs is vertically centered\n this.style.display = \"table-cell\";\n this.style.verticalAlign = \"middle\";\n }\n this.setAttribute(\"aria-hidden\", \"true\");\n this.#updateStyles();\n this.#updateText();\n this.#styleObserver.observe(input, {\n attributeFilter: [\n \"style\",\n \"dir\", // users can right-click in some browsers to change the text direction dynamically\n ],\n });\n this.#resizeObserver.observe(input);\n document.addEventListener(\"scroll\", this.#onDocumentScrollOrResize, { capture: true });\n window.addEventListener(\"resize\", this.#onDocumentScrollOrResize, { capture: true });\n // capture so this happens first, so other things can respond to `input` events after this data updates\n input.addEventListener(\"input\", this.#onInput, { capture: true });\n });\n }\n /** @private */\n disconnectedCallback() {\n this.#container?.remove();\n this.#styleObserver.disconnect();\n this.#resizeObserver.disconnect();\n document.removeEventListener(\"scroll\", this.#onDocumentScrollOrResize, { capture: true });\n window.removeEventListener(\"resize\", this.#onDocumentScrollOrResize, { capture: true });\n // Can't use `usingInput` here since that could infinitely recurse\n const input = this.#input;\n if (input) {\n input.removeEventListener(\"input\", this.#onInput, { capture: true });\n CloneRegistry.delete(input);\n }\n }\n // --- private ---\n get #input() {\n return this.#inputRef?.deref();\n }\n /** Perform `fn` using the `input` if it is still available. If not, clean up the clone instead. */\n #usingInput(fn) {\n const input = this.#input;\n if (!input)\n return this.remove();\n return fn(input);\n }\n /** Current relative x-adjustment in pixels, executed via CSS transform. */\n #xOffset = 0;\n /** Current relative y-adjustment in pixels, executed via CSS transform. */\n #yOffset = 0;\n /**\n * Update only geometric properties without recalculating styles. Typically call `#requestUpdateLayout` instead to\n * only update once per animation frame.\n */\n #updateLayout() {\n // This runs often, so keep it as fast as possible! Avoid all unecessary updates.\n this.#usingInput((input) => {\n const inputStyle = window.getComputedStyle(input);\n this.style.height = inputStyle.height;\n this.style.width = inputStyle.width;\n // Immediately re-adjust for browser inconsistencies in scrollbar handling, if necessary\n if (input.clientHeight !== this.clientHeight)\n this.style.height = `calc(${inputStyle.height} + ${input.clientHeight - this.clientHeight}px)`;\n if (input.clientWidth !== this.clientWidth)\n this.style.width = `calc(${inputStyle.width} + ${input.clientWidth - this.clientWidth}px)`;\n // Position on top of the input\n const inputRect = input.getBoundingClientRect();\n const cloneRect = this.getBoundingClientRect();\n this.#xOffset = this.#xOffset + inputRect.left - cloneRect.left;\n this.#yOffset = this.#yOffset + inputRect.top - cloneRect.top;\n this.style.transform = `translate(${this.#xOffset}px, ${this.#yOffset}px)`;\n this.scrollTop = input.scrollTop;\n this.scrollLeft = input.scrollLeft;\n this.dispatchEvent(new InputStyleCloneUpdateEvent());\n });\n }\n #isLayoutUpdating = false;\n /** Request a layout update. Will only happen once per animation frame, to avoid unecessary updates. */\n #requestUpdateLayout() {\n if (this.#isLayoutUpdating)\n return;\n this.#isLayoutUpdating = true;\n requestAnimationFrame(() => {\n this.#updateLayout();\n this.#isLayoutUpdating = false;\n });\n }\n /** Update the styles of the clone based on the styles of the input, then request a layout update. */\n #updateStyles() {\n this.#usingInput((input) => {\n const inputStyle = window.getComputedStyle(input);\n for (const prop of propertiesToCopy)\n this.style[prop] = inputStyle[prop];\n this.#requestUpdateLayout();\n });\n }\n /**\n * Update the text content of the clone based on the text content of the input. Triggers a layout update in case the\n * text update caused scrolling.\n */\n #updateText() {\n this.#usingInput((input) => {\n this.textContent = input.value;\n // This is often unecessary on a pure text update, but text updates could potentially cause layout updates like\n // scrolling or resizing. And we run the update on _every frame_ when scrolling, so this isn't that expensive.\n // We don't requestUpdateLayout here because this one should happen synchronously, so that clients can react\n // within their own `input` event handlers.\n this.#updateLayout();\n });\n }\n #onInput = () => this.#updateText();\n #onDocumentScrollOrResize = (event) => {\n this.#usingInput((input) => {\n if (event.target === document ||\n event.target === window ||\n (event.target instanceof Node && event.target.contains(input)))\n this.#requestUpdateLayout();\n });\n };\n}\n// Note that some browsers, such as Firefox, do not concatenate properties\n// into their shorthand (e.g. padding-top, padding-bottom etc. -> padding),\n// so we have to list every single property explicitly.\nconst propertiesToCopy = [\n // RTL / vertical writing modes support:\n \"direction\",\n \"writingMode\",\n \"unicodeBidi\",\n \"textOrientation\",\n \"boxSizing\",\n \"borderTopWidth\",\n \"borderRightWidth\",\n \"borderBottomWidth\",\n \"borderLeftWidth\",\n \"borderStyle\",\n \"paddingTop\",\n \"paddingRight\",\n \"paddingBottom\",\n \"paddingLeft\",\n // https://developer.mozilla.org/en-US/docs/Web/CSS/font\n \"fontStyle\",\n \"fontVariant\",\n \"fontWeight\",\n \"fontStretch\",\n \"fontSize\",\n \"fontSizeAdjust\",\n \"lineHeight\",\n \"fontFamily\",\n \"textAlign\",\n \"textTransform\",\n \"textIndent\",\n \"textDecoration\",\n \"letterSpacing\",\n \"wordSpacing\",\n \"tabSize\",\n \"MozTabSize\",\n];\n// Inspired by https://github.com/github/catalyst/blob/dc284dcf4f82329a9cac5c867462a8fa529b6c40/src/register.ts\ntry {\n customElements.define(\"input-style-clone\", InputStyleCloneElement);\n}\ncatch (e) {\n // Throws DOMException with NotSupportedError if already defined\n if (!(e instanceof DOMException && e.name === \"NotSupportedError\"))\n throw e;\n}\n\nclass InputRange {\n #inputElement;\n #startOffset;\n #endOffset;\n /**\n * Construct a new `InputRange`.\n * @param element The target input element that contains the content for the range.\n * @param startOffset The inclusive 0-based start index for the range. Will be adjusted to fit in the input contents.\n * @param endOffset The exclusive 0-based end index for the range. Will be adjusted to fit in the input contents.\n */\n constructor(element, startOffset = 0, endOffset = startOffset) {\n this.#inputElement = element;\n this.#startOffset = startOffset;\n this.#endOffset = endOffset;\n }\n /**\n * Create a new range from the current user selection. If the input is not focused, the range will just be the start\n * of the input (offsets `0` to `0`).\n *\n * This can be used to get the caret coordinates: if the resulting range is `collapsed`, the location of the\n * `getBoundingClientRect` will be the location of the caret caret (note, however, that the width will be `0` in\n * this case).\n */\n static fromSelection(input) {\n const { selectionStart, selectionEnd } = input;\n return new InputRange(input, selectionStart ?? undefined, selectionEnd ?? undefined);\n }\n /** Returns true if the start is equal to the end of this range. */\n get collapsed() {\n return this.startOffset === this.endOffset;\n }\n /** Always returns the containing input element. */\n get commonAncestorContainer() {\n return this.#inputElement;\n }\n /** Always returns the containing input element. */\n get endContainer() {\n return this.#inputElement;\n }\n /** Always returns the containing input element. */\n get startContainer() {\n return this.#inputElement;\n }\n get startOffset() {\n return this.#startOffset;\n }\n get endOffset() {\n return this.#endOffset;\n }\n /** Update the inclusive start offset. Will be adjusted to fit within the content size. */\n setStartOffset(offset) {\n this.#startOffset = this.#clampOffset(offset);\n }\n /** Update the exclusive end offset. Will be adjusted to fit within the content size. */\n setEndOffset(offset) {\n this.#endOffset = this.#clampOffset(offset);\n }\n /**\n * Collapse this range to one side.\n * @param toStart If `true`, will collapse to the start side. Otherwise, will collapse to the end.\n */\n collapse(toStart = false) {\n if (toStart)\n this.setEndOffset(this.startOffset);\n else\n this.setStartOffset(this.endOffset);\n }\n /** Returns a `DocumentFragment` containing a new `Text` node containing the content in the range. */\n cloneContents() {\n return this.#createCloneRange().cloneContents();\n }\n /** Create a copy of this range. */\n cloneRange() {\n return new InputRange(this.#inputElement, this.startOffset, this.endOffset);\n }\n /**\n * Obtain one rect that contains the entire contents of the range. If the range spans multiple lines, this box will\n * contain all pieces of the range but may also contain some space outside the range.\n * @see https://iansan5653.github.io/dom-input-range/demos/playground/\n */\n getBoundingClientRect() {\n return this.#createCloneRange().getBoundingClientRect();\n }\n /**\n * Obtain the rects that contain contents of this range. If the range spans multiple lines, there will be multiple\n * bounding boxes. These boxes can be used, for example, to draw a highlight over the range.\n * @see https://iansan5653.github.io/dom-input-range/demos/playground/\n */\n getClientRects() {\n return this.#createCloneRange().getClientRects();\n }\n /** Get the contents of the range as a string. */\n toString() {\n return this.#createCloneRange().toString();\n }\n /**\n * Get the underlying `InputStyleClone` instance powering these calculations. This can be used to listen for\n * updates to trigger layout recalculation.\n */\n getStyleClone() {\n return this.#styleClone;\n }\n // --- private ---\n get #styleClone() {\n return InputStyleCloneElement.for(this.#inputElement);\n }\n get #cloneElement() {\n return this.#styleClone;\n }\n #clampOffset(offset) {\n return Math.max(0, Math.min(offset, this.#inputElement.value.length));\n }\n #createCloneRange() {\n // It's tempting to create a single Range and reuse it across the lifetime of the class. However, this wouldn't be\n // accurate because the contents of the input can change and the contents of the range would become stale. So we\n // must create a new range every time we need it.\n const range = document.createRange();\n const textNode = this.#cloneElement.childNodes[0];\n if (textNode) {\n range.setStart(textNode, this.startOffset);\n range.setEnd(textNode, this.endOffset);\n }\n return range;\n }\n}\n\nconst states = new WeakMap();\nclass TextExpander {\n constructor(expander, input) {\n this.expander = expander;\n this.input = input;\n this.combobox = null;\n this.menu = null;\n this.match = null;\n this.justPasted = false;\n this.lookBackIndex = 0;\n this.oninput = this.onInput.bind(this);\n this.onpaste = this.onPaste.bind(this);\n this.onkeydown = this.onKeydown.bind(this);\n this.oncommit = this.onCommit.bind(this);\n this.onmousedown = this.onMousedown.bind(this);\n this.onblur = this.onBlur.bind(this);\n this.interactingWithList = false;\n input.addEventListener('paste', this.onpaste);\n input.addEventListener('input', this.oninput);\n input.addEventListener('keydown', this.onkeydown);\n input.addEventListener('blur', this.onblur);\n }\n destroy() {\n this.input.removeEventListener('paste', this.onpaste);\n this.input.removeEventListener('input', this.oninput);\n this.input.removeEventListener('keydown', this.onkeydown);\n this.input.removeEventListener('blur', this.onblur);\n }\n dismissMenu() {\n if (this.deactivate()) {\n this.lookBackIndex = this.input.selectionEnd || this.lookBackIndex;\n }\n }\n activate(match, menu) {\n var _a, _b;\n if (this.input !== document.activeElement && this.input !== ((_b = (_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.activeElement)) {\n return;\n }\n this.deactivate();\n this.menu = menu;\n if (!menu.id)\n menu.id = `text-expander-${Math.floor(Math.random() * 100000).toString()}`;\n this.expander.append(menu);\n this.combobox = new Combobox(this.input, menu);\n this.expander.dispatchEvent(new Event('text-expander-activate'));\n this.positionMenu(menu, match.position);\n this.combobox.start();\n menu.addEventListener('combobox-commit', this.oncommit);\n menu.addEventListener('mousedown', this.onmousedown);\n this.combobox.navigate(1);\n }\n positionMenu(menu, position) {\n const caretRect = new InputRange(this.input, position).getBoundingClientRect();\n const targetPosition = { left: caretRect.left, top: caretRect.top + caretRect.height };\n const currentPosition = menu.getBoundingClientRect();\n const delta = {\n left: targetPosition.left - currentPosition.left,\n top: targetPosition.top - currentPosition.top\n };\n if (delta.left !== 0 || delta.top !== 0) {\n const currentStyle = getComputedStyle(menu);\n menu.style.left = currentStyle.left ? `calc(${currentStyle.left} + ${delta.left}px)` : `${delta.left}px`;\n menu.style.top = currentStyle.top ? `calc(${currentStyle.top} + ${delta.top}px)` : `${delta.top}px`;\n }\n }\n deactivate() {\n const menu = this.menu;\n if (!menu || !this.combobox)\n return false;\n this.expander.dispatchEvent(new Event('text-expander-deactivate'));\n this.menu = null;\n menu.removeEventListener('combobox-commit', this.oncommit);\n menu.removeEventListener('mousedown', this.onmousedown);\n this.combobox.destroy();\n this.combobox = null;\n menu.remove();\n return true;\n }\n onCommit({ target }) {\n var _a;\n const item = target;\n if (!(item instanceof HTMLElement))\n return;\n if (!this.combobox)\n return;\n const match = this.match;\n if (!match)\n return;\n const beginning = this.input.value.substring(0, match.position - match.key.length);\n const remaining = this.input.value.substring(match.position + match.text.length);\n const detail = { item, key: match.key, value: null, continue: false };\n const canceled = !this.expander.dispatchEvent(new CustomEvent('text-expander-value', { cancelable: true, detail }));\n if (canceled)\n return;\n if (!detail.value)\n return;\n let suffix = (_a = this.expander.getAttribute('suffix')) !== null && _a !== void 0 ? _a : ' ';\n if (detail.continue) {\n suffix = '';\n }\n const value = `${detail.value}${suffix}`;\n this.input.value = beginning + value + remaining;\n const cursor = beginning.length + value.length;\n this.deactivate();\n this.input.focus({\n preventScroll: true\n });\n this.input.selectionStart = cursor;\n this.input.selectionEnd = cursor;\n if (!detail.continue) {\n this.lookBackIndex = cursor;\n this.match = null;\n }\n this.expander.dispatchEvent(new CustomEvent('text-expander-committed', { cancelable: false, detail: { input: this.input } }));\n }\n onBlur() {\n if (this.interactingWithList) {\n this.interactingWithList = false;\n return;\n }\n this.deactivate();\n }\n onPaste() {\n this.justPasted = true;\n }\n async onInput() {\n if (this.justPasted) {\n this.justPasted = false;\n return;\n }\n const match = this.findMatch();\n if (match) {\n this.match = match;\n const menu = await this.notifyProviders(match);\n if (!this.match)\n return;\n if (menu) {\n this.activate(match, menu);\n }\n else {\n this.deactivate();\n }\n }\n else {\n this.match = null;\n this.deactivate();\n }\n }\n findMatch() {\n const cursor = this.input.selectionEnd || 0;\n const text = this.input.value;\n if (cursor <= this.lookBackIndex) {\n this.lookBackIndex = cursor - 1;\n }\n for (const { key, multiWord } of this.expander.keys) {\n const found = query(text, key, cursor, {\n multiWord,\n lookBackIndex: this.lookBackIndex,\n lastMatchPosition: this.match ? this.match.position : null\n });\n if (found) {\n return { text: found.text, key, position: found.position };\n }\n }\n }\n async notifyProviders(match) {\n const providers = [];\n const provide = (result) => providers.push(result);\n const changeEvent = new CustomEvent('text-expander-change', {\n cancelable: true,\n detail: { provide, text: match.text, key: match.key }\n });\n const canceled = !this.expander.dispatchEvent(changeEvent);\n if (canceled)\n return;\n const all = await Promise.all(providers);\n const fragments = all.filter(x => x.matched).map(x => x.fragment);\n return fragments[0];\n }\n onMousedown() {\n this.interactingWithList = true;\n }\n onKeydown(event) {\n if (event.key === 'Escape') {\n this.match = null;\n if (this.deactivate()) {\n this.lookBackIndex = this.input.selectionEnd || this.lookBackIndex;\n event.stopImmediatePropagation();\n event.preventDefault();\n }\n }\n }\n}\nclass TextExpanderElement extends HTMLElement {\n get keys() {\n const keysAttr = this.getAttribute('keys');\n const keys = keysAttr ? keysAttr.split(' ') : [];\n const multiWordAttr = this.getAttribute('multiword');\n const multiWord = multiWordAttr ? multiWordAttr.split(' ') : [];\n const globalMultiWord = multiWord.length === 0 && this.hasAttribute('multiword');\n return keys.map(key => ({ key, multiWord: globalMultiWord || multiWord.includes(key) }));\n }\n set keys(value) {\n this.setAttribute('keys', value);\n }\n connectedCallback() {\n const input = this.querySelector('input[type=\"text\"], textarea');\n if (!(input instanceof HTMLInputElement || input instanceof HTMLTextAreaElement))\n return;\n const state = new TextExpander(this, input);\n states.set(this, state);\n }\n disconnectedCallback() {\n const state = states.get(this);\n if (!state)\n return;\n state.destroy();\n states.delete(this);\n }\n dismiss() {\n const state = states.get(this);\n if (!state)\n return;\n state.dismissMenu();\n }\n}\n\nif (!window.customElements.get('text-expander')) {\n window.TextExpanderElement = TextExpanderElement;\n window.customElements.define('text-expander', TextExpanderElement);\n}\n\nexport { TextExpanderElement as default };\n","export default function ansiRegex({onlyFirst = false} = {}) {\n\tconst pattern = [\n\t '[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]+)*|[a-zA-Z\\\\d]+(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)',\n\t\t'(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PR-TZcf-ntqry=><~]))'\n\t].join('|');\n\n\treturn new RegExp(pattern, onlyFirst ? undefined : 'g');\n}\n","import ansiRegex from 'ansi-regex';\n\nconst regex = ansiRegex();\n\nexport default function stripAnsi(string) {\n\tif (typeof string !== 'string') {\n\t\tthrow new TypeError(`Expected a \\`string\\`, got \\`${typeof string}\\``);\n\t}\n\n\t// Even though the regex is global, we don't need to reset the `.lastIndex`\n\t// because unlike `.exec()` and `.test()`, `.replace()` does it automatically\n\t// and doing it manually has a performance penalty.\n\treturn string.replace(regex, '');\n}\n","import stripAnsi from 'strip-ansi';\n\nconst segmenter = new Intl.Segmenter();\n\nexport default function stringLength(string, {countAnsiEscapeCodes = false} = {}) {\n\tif (string === '') {\n\t\treturn 0;\n\t}\n\n\tif (!countAnsiEscapeCodes) {\n\t\tstring = stripAnsi(string);\n\t}\n\n\tif (string === '') {\n\t\treturn 0;\n\t}\n\n\tlet length = 0;\n\n\tfor (const _ of segmenter.segment(string)) { // eslint-disable-line no-unused-vars\n\t\tlength++;\n\t}\n\n\treturn length;\n}\n","export default \"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20version='1.0'%20viewBox='0%200%20641%20223'%3e%3cpath%20fill='%23aaa'%20d='M86%20214c-9-1-17-4-24-8l-6-3-5-5-5-4-4-6-4-6-3-8-2-8v-27l2-9%203-9%204-6%204-6%205-5%205-5%207-3%206-4%207-2%207-2%2012-1h12l7%201%208%202%207%204%207%203%205%205%205%204-10%2010-10%209-4-3-10-5-5-1H88l-5%202-6%203-3%204-4%204-2%205-2%206v6l-1%207%201%207%202%207%203%205%202%204%204%203%204%203%205%202%206%202h9l10-1%205-2%206-3v-16H91v-27h59v54l-1%203-2%203-5%204-4%204-5%203-5%202-8%202-8%202-10%201H92l-6-1zm266-62V91h34v46h44V91h34v121h-34v-46h-44v46h-34v-61zm-182-1V90h34v121h-34v-60zm59-1V90h35l36%201%205%202c3%200%208%202%2010%204l5%202%204%205%205%204%203%207%203%207%201%2013v13l-4%206-3%207-4%204-5%205-5%202-5%203-6%202-5%201-18%201h-18v32h-34v-61zm67-2%203-2%202-4%202-5v-5l-2-4-2-4-3-2-3-3h-30v31h30l3-2zm226%2039v-24l-8-12-18-28a1751%201751%200%200%200-20-31v-2h39l7%2012%2012%2021%206%209%2013-21%2013-21h38v2l-41%2061-7%2010v48h-34v-24zM109%2066l-4-1-5-5-5-4-1-5-3-9v-5l1-5c2-7%203-10%208-15l4-4%207-2%207-2h7l6%201%205%202%205%202%203%204%204%203%202%206%202%205v13l-2%205-2%206-4%204-3%203-5%202-4%202-9%201h-9l-5-2zm22-11%204-2%203-4%202-5V34l-2-4-2-4-3-2-4-3-5-1h-6l-4%202-5%202-2%204-3%205-1%203v4l1%205%202%205%202%202%205%203%204%202h10l4-2zM37%2039V11h33l3%201%203%202%204%203%203%203%201%205%201%204v5l-1%204-3%204-3%205-4%201-3%202-11%201H49v16H37V39zm31%200%203-2%201-2%201-2v-4l-1-3-3-2-2-2H49v18h15l4-1zm107%2025a512%20512%200%200%200-19-53h14l4%2014%206%2019%201%204%201-1%207-19%205-17h9l6%2019%207%2018v-1l2-6%205-17%204-13h14v1l-4%2012-16%2041v2h-5l-5-1-6-15-6-15-1%201-3%207-6%2015-2%208h-11l-1-3zm74-25V11h42v11h-29v2l-1%205v4h29v11h-28v11h2l15%201h13v11h-43V39zm55%200V11h33l5%203%205%202%202%204%202%205v10l-2%203-1%204-5%203-5%203%205%205%208%2010%203%204h-14l-7-9-8-10h-9v19h-12V39zm33-3%202-3v-6l-3-3-2-3h-18v16h1v1h17l2-2zm26%203V11h42v11h-29l-1%206v5h29v11h-28v5l-1%205%201%201v1h30v11h-43V39zm54%200V11h17l18%201%204%202%205%203%202%204%203%204%202%206%201%206v5c-1%206-3%2012-6%2015l-3%204-5%203-5%202-17%201h-16V39zm33%2014%205-5%202-3v-6l-1-6-1-3-1-3-4-3-3-2h-5l-6-1-3%201h-3v34h9l8-1%203-2zm50-14V11h34l5%202%204%202%202%203%202%203v9l-2%202-3%204-1%201%203%203%203%204%201%203%201%204-1%204-1%204-3%203-3%203-5%201-5%201h-31V39zm34%2015%202-1v-6l-2-2-2-2h-20v13h20l2-2zm-3-22%204-2v-6l-2-1-2-2h-19v12h16l4-1zm42%2024V45l-6-9-11-17-5-8h15l4%208%207%2011%202%203%207-11%207-11h14l-11%2016-11%2017v23h-12V56z'/%3e%3c/svg%3e\"","import './compose.css';\nimport '@github/text-expander-element';\n\nimport { msg, plural } from '@lingui/core/macro';\nimport { Trans, useLingui } from '@lingui/react/macro';\nimport { MenuItem } from '@szhsin/react-menu';\nimport { deepEqual } from 'fast-equals';\nimport Fuse from 'fuse.js';\nimport { forwardRef, memo } from 'preact/compat';\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'preact/hooks';\nimport { useHotkeys } from 'react-hotkeys-hook';\nimport stringLength from 'string-length';\n// import { detectAll } from 'tinyld/light';\nimport { uid } from 'uid/single';\nimport { useDebouncedCallback, useThrottledCallback } from 'use-debounce';\nimport useResizeObserver from 'use-resize-observer';\nimport { useSnapshot } from 'valtio';\n\nimport poweredByGiphyURL from '../assets/powered-by-giphy.svg';\n\nimport Menu2 from '../components/menu2';\nimport supportedLanguages from '../data/status-supported-languages';\nimport urlRegex from '../data/url-regex';\nimport { api } from '../utils/api';\nimport { langDetector } from '../utils/browser-translator';\nimport db from '../utils/db';\nimport emojifyText from '../utils/emojify-text';\nimport i18nDuration from '../utils/i18n-duration';\nimport isRTL from '../utils/is-rtl';\nimport localeMatch from '../utils/locale-match';\nimport localeCode2Text from '../utils/localeCode2Text';\nimport mem from '../utils/mem';\nimport openCompose from '../utils/open-compose';\nimport pmem from '../utils/pmem';\nimport prettyBytes from '../utils/pretty-bytes';\nimport { fetchRelationships } from '../utils/relationships';\nimport shortenNumber from '../utils/shorten-number';\nimport showToast from '../utils/show-toast';\nimport states, { saveStatus } from '../utils/states';\nimport store from '../utils/store';\nimport {\n getCurrentAccount,\n getCurrentAccountNS,\n getCurrentInstance,\n getCurrentInstanceConfiguration,\n} from '../utils/store-utils';\nimport supports from '../utils/supports';\nimport useCloseWatcher from '../utils/useCloseWatcher';\nimport useInterval from '../utils/useInterval';\nimport visibilityIconsMap from '../utils/visibility-icons-map';\n\nimport AccountBlock from './account-block';\n// import Avatar from './avatar';\nimport Icon from './icon';\nimport Loader from './loader';\nimport Modal from './modal';\nimport ScheduledAtField, {\n getLocalTimezoneName,\n MIN_SCHEDULED_AT,\n} from './ScheduledAtField';\nimport Status from './status';\n\nconst {\n PHANPY_IMG_ALT_API_URL: IMG_ALT_API_URL,\n PHANPY_GIPHY_API_KEY: GIPHY_API_KEY,\n} = import.meta.env;\n\nconst supportedLanguagesMap = supportedLanguages.reduce((acc, l) => {\n const [code, common, native] = l;\n acc[code] = {\n common,\n native,\n };\n return acc;\n}, {});\n\n/* NOTES:\n - Max character limit includes BOTH status text and Content Warning text\n*/\n\nconst expiryOptions = {\n 300: i18nDuration(5, 'minute'),\n 1_800: i18nDuration(30, 'minute'),\n 3_600: i18nDuration(1, 'hour'),\n 21_600: i18nDuration(6, 'hour'),\n 86_400: i18nDuration(1, 'day'),\n 259_200: i18nDuration(3, 'day'),\n 604_800: i18nDuration(1, 'week'),\n};\nconst expirySeconds = Object.keys(expiryOptions);\nconst oneDay = 24 * 60 * 60;\n\nconst expiresInFromExpiresAt = (expiresAt) => {\n if (!expiresAt) return oneDay;\n const delta = (new Date(expiresAt).getTime() - Date.now()) / 1000;\n return expirySeconds.find((s) => s >= delta) || oneDay;\n};\n\nconst menu = document.createElement('ul');\nmenu.role = 'listbox';\nmenu.className = 'text-expander-menu';\n\n// Set IntersectionObserver on menu, reposition it because text-expander doesn't handle it\nconst windowMargin = 16;\nconst observer = new IntersectionObserver((entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n const { left, width } = entry.boundingClientRect;\n const { innerWidth } = window;\n if (left + width > innerWidth) {\n const insetInlineStart = isRTL() ? 'right' : 'left';\n menu.style[insetInlineStart] = innerWidth - width - windowMargin + 'px';\n }\n }\n });\n});\nobserver.observe(menu);\n\nconst DEFAULT_LANG = localeMatch(\n [new Intl.DateTimeFormat().resolvedOptions().locale, ...navigator.languages],\n supportedLanguages.map((l) => l[0]),\n 'en',\n);\n\n// https://github.com/mastodon/mastodon/blob/c4a429ed47e85a6bbf0d470a41cc2f64cf120c19/app/javascript/mastodon/features/compose/util/counter.js\nconst urlRegexObj = new RegExp(urlRegex.source, urlRegex.flags);\nconst usernameRegex = /(^|[^\\/\\w])@(([a-z0-9_]+)@[a-z0-9\\.\\-]+[a-z0-9]+)/gi;\nconst urlPlaceholder = '$2xxxxxxxxxxxxxxxxxxxxxxx';\nfunction countableText(inputText) {\n return inputText\n .replace(urlRegexObj, urlPlaceholder)\n .replace(usernameRegex, '$1@$3');\n}\n\n// https://github.com/mastodon/mastodon/blob/c03bd2a238741a012aa4b98dc4902d6cf948ab63/app/models/account.rb#L69\nconst USERNAME_RE = /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i;\nconst MENTION_RE = new RegExp(\n `(^|[^=\\\\/\\\\w])(@${USERNAME_RE.source}(?:@[\\\\p{L}\\\\w.-]+[\\\\w]+)?)`,\n 'uig',\n);\n\n// AI-generated, all other regexes are too complicated\nconst HASHTAG_RE = new RegExp(\n `(^|[^=\\\\/\\\\w])(#[\\\\p{L}\\\\p{N}_]+([\\\\p{L}\\\\p{N}_.]+[\\\\p{L}\\\\p{N}_]+)?)(?![\\\\/\\\\w])`,\n 'iug',\n);\n\n// https://github.com/mastodon/mastodon/blob/23e32a4b3031d1da8b911e0145d61b4dd47c4f96/app/models/custom_emoji.rb#L31\nconst SHORTCODE_RE_FRAGMENT = '[a-zA-Z0-9_]{2,}';\nconst SCAN_RE = new RegExp(\n `(^|[^=\\\\/\\\\w])(:${SHORTCODE_RE_FRAGMENT}:)(?=[^A-Za-z0-9_:]|$)`,\n 'g',\n);\n\nconst segmenter = new Intl.Segmenter();\nfunction escapeHTML(text) {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\nfunction highlightText(text, { maxCharacters = Infinity }) {\n // Exceeded characters limit\n const { composerCharacterCount } = states;\n if (composerCharacterCount > maxCharacters) {\n // Highlight exceeded characters\n let withinLimitHTML = '',\n exceedLimitHTML = '';\n const htmlSegments = segmenter.segment(text);\n for (const { segment, index } of htmlSegments) {\n if (index < maxCharacters) {\n withinLimitHTML += segment;\n } else {\n exceedLimitHTML += segment;\n }\n }\n if (exceedLimitHTML) {\n exceedLimitHTML =\n '<mark class=\"compose-highlight-exceeded\">' +\n escapeHTML(exceedLimitHTML) +\n '</mark>';\n }\n return escapeHTML(withinLimitHTML) + exceedLimitHTML;\n }\n\n return escapeHTML(text)\n .replace(urlRegexObj, '$2<mark class=\"compose-highlight-url\">$3</mark>') // URLs\n .replace(MENTION_RE, '$1<mark class=\"compose-highlight-mention\">$2</mark>') // Mentions\n .replace(HASHTAG_RE, '$1<mark class=\"compose-highlight-hashtag\">$2</mark>') // Hashtags\n .replace(\n SCAN_RE,\n '$1<mark class=\"compose-highlight-emoji-shortcode\">$2</mark>',\n ); // Emoji shortcodes\n}\n\n// const rtf = new Intl.RelativeTimeFormat();\nconst RTF = mem((locale) => new Intl.RelativeTimeFormat(locale || undefined));\nconst LF = mem((locale) => new Intl.ListFormat(locale || undefined));\n\nconst CUSTOM_EMOJIS_COUNT = 100;\n\nconst ADD_LABELS = {\n camera: msg`Take photo or video`,\n media: msg`Add media`,\n customEmoji: msg`Add custom emoji`,\n gif: msg`Add GIF`,\n poll: msg`Add poll`,\n scheduledPost: msg`Schedule post`,\n};\n\nfunction Compose({\n onClose,\n replyToStatus,\n editStatus,\n draftStatus,\n standalone,\n hasOpener,\n}) {\n const { i18n, _, t } = useLingui();\n const rtf = RTF(i18n.locale);\n const lf = LF(i18n.locale);\n\n console.warn('RENDER COMPOSER');\n const { masto, instance } = api();\n const [uiState, setUIState] = useState('default');\n const UID = useRef(draftStatus?.uid || uid());\n console.log('Compose UID', UID.current);\n\n const currentAccount = getCurrentAccount();\n const currentAccountInfo = currentAccount.info;\n\n const configuration = getCurrentInstanceConfiguration();\n console.log('⚙️ Configuration', configuration);\n\n const {\n statuses: {\n maxCharacters,\n maxMediaAttachments, // Beware: it can be undefined!\n charactersReservedPerUrl,\n } = {},\n mediaAttachments: {\n supportedMimeTypes,\n imageSizeLimit,\n imageMatrixLimit,\n videoSizeLimit,\n videoMatrixLimit,\n videoFrameRateLimit,\n } = {},\n polls: {\n maxOptions,\n maxCharactersPerOption,\n maxExpiration,\n minExpiration,\n } = {},\n } = configuration || {};\n const supportedImagesVideosTypes = supportedMimeTypes?.filter((mimeType) =>\n /^(image|video)/i.test(mimeType),\n );\n\n const textareaRef = useRef();\n const spoilerTextRef = useRef();\n const [visibility, setVisibility] = useState('public');\n const [sensitive, setSensitive] = useState(false);\n const [language, setLanguage] = useState(\n store.session.get('currentLanguage') || DEFAULT_LANG,\n );\n const prevLanguage = useRef(language);\n const [mediaAttachments, setMediaAttachments] = useState([]);\n const [poll, setPoll] = useState(null);\n const [scheduledAt, setScheduledAt] = useState(null);\n\n const prefs = store.account.get('preferences') || {};\n\n const oninputTextarea = () => {\n if (!textareaRef.current) return;\n textareaRef.current.dispatchEvent(new Event('input'));\n };\n const focusTextarea = () => {\n setTimeout(() => {\n if (!textareaRef.current) return;\n // status starts with newline, focus on first position\n if (draftStatus?.status?.startsWith?.('\\n')) {\n textareaRef.current.selectionStart = 0;\n textareaRef.current.selectionEnd = 0;\n }\n console.debug('FOCUS textarea');\n textareaRef.current?.focus();\n }, 300);\n };\n\n useEffect(() => {\n if (replyToStatus) {\n const { spoilerText, visibility, language, sensitive } = replyToStatus;\n if (spoilerText && spoilerTextRef.current) {\n spoilerTextRef.current.value = spoilerText;\n }\n const mentions = new Set([\n replyToStatus.account.acct,\n ...replyToStatus.mentions.map((m) => m.acct),\n ]);\n const allMentions = [...mentions].filter(\n (m) => m !== currentAccountInfo.acct,\n );\n if (allMentions.length > 0) {\n textareaRef.current.value = `${allMentions\n .map((m) => `@${m}`)\n .join(' ')} `;\n oninputTextarea();\n }\n focusTextarea();\n setVisibility(\n visibility === 'public' && prefs['posting:default:visibility']\n ? prefs['posting:default:visibility'].toLowerCase()\n : visibility,\n );\n setLanguage(\n language ||\n prefs['posting:default:language']?.toLowerCase() ||\n DEFAULT_LANG,\n );\n setSensitive(sensitive && !!spoilerText);\n } else if (editStatus) {\n const { visibility, language, sensitive, poll, mediaAttachments } =\n editStatus;\n const composablePoll = !!poll?.options && {\n ...poll,\n options: poll.options.map((o) => o?.title || o),\n expiresIn: poll?.expiresIn || expiresInFromExpiresAt(poll.expiresAt),\n };\n setUIState('loading');\n (async () => {\n try {\n const statusSource = await masto.v1.statuses\n .$select(editStatus.id)\n .source.fetch();\n console.log({ statusSource });\n const { text, spoilerText } = statusSource;\n textareaRef.current.value = text;\n textareaRef.current.dataset.source = text;\n oninputTextarea();\n focusTextarea();\n spoilerTextRef.current.value = spoilerText;\n setVisibility(visibility);\n setLanguage(\n language ||\n prefs['posting:default:language']?.toLowerCase() ||\n DEFAULT_LANG,\n );\n setSensitive(sensitive);\n if (composablePoll) setPoll(composablePoll);\n setMediaAttachments(mediaAttachments);\n setUIState('default');\n } catch (e) {\n console.error(e);\n alert(e?.reason || e);\n setUIState('error');\n }\n })();\n } else {\n focusTextarea();\n console.log('Apply prefs', prefs);\n if (prefs['posting:default:visibility']) {\n setVisibility(prefs['posting:default:visibility'].toLowerCase());\n }\n if (prefs['posting:default:language']) {\n setLanguage(prefs['posting:default:language'].toLowerCase());\n }\n if (prefs['posting:default:sensitive']) {\n setSensitive(!!prefs['posting:default:sensitive']);\n }\n }\n if (draftStatus) {\n const {\n status,\n spoilerText,\n visibility,\n language,\n sensitive,\n poll,\n mediaAttachments,\n scheduledAt,\n } = draftStatus;\n const composablePoll = !!poll?.options && {\n ...poll,\n options: poll.options.map((o) => o?.title || o),\n expiresIn: poll?.expiresIn || expiresInFromExpiresAt(poll.expiresAt),\n };\n textareaRef.current.value = status;\n oninputTextarea();\n focusTextarea();\n if (spoilerText) spoilerTextRef.current.value = spoilerText;\n if (visibility) setVisibility(visibility);\n setLanguage(\n language ||\n prefs['posting:default:language']?.toLowerCase() ||\n DEFAULT_LANG,\n );\n if (sensitive !== null) setSensitive(sensitive);\n if (composablePoll) setPoll(composablePoll);\n if (mediaAttachments) setMediaAttachments(mediaAttachments);\n if (scheduledAt) setScheduledAt(scheduledAt);\n }\n }, [draftStatus, editStatus, replyToStatus]);\n\n const formRef = useRef();\n\n const beforeUnloadCopy = t`You have unsaved changes. Discard this post?`;\n const canClose = () => {\n const { value, dataset } = textareaRef.current;\n\n // check if loading\n if (uiState === 'loading') {\n console.log('canClose', { uiState });\n return false;\n }\n\n // check for status and media attachments\n const hasValue = (value || '')\n .trim()\n .replace(/^\\p{White_Space}+|\\p{White_Space}+$/gu, '');\n const hasMediaAttachments = mediaAttachments.length > 0;\n if (!hasValue && !hasMediaAttachments) {\n console.log('canClose', { value, mediaAttachments });\n return true;\n }\n\n // check if all media attachments have IDs\n const hasIDMediaAttachments =\n mediaAttachments.length > 0 &&\n mediaAttachments.every((media) => media.id);\n if (hasIDMediaAttachments) {\n console.log('canClose', { hasIDMediaAttachments });\n return true;\n }\n\n // check if status contains only \"@acct\", if replying\n const isSelf = replyToStatus?.account.id === currentAccountInfo.id;\n const hasOnlyAcct =\n replyToStatus && value.trim() === `@${replyToStatus.account.acct}`;\n // TODO: check for mentions, or maybe just generic \"@username<space>\", including multiple mentions like \"@username1<space>@username2<space>\"\n if (!isSelf && hasOnlyAcct) {\n console.log('canClose', { isSelf, hasOnlyAcct });\n return true;\n }\n\n // check if status is same with source\n const sameWithSource = value === dataset?.source;\n if (sameWithSource) {\n console.log('canClose', { sameWithSource });\n return true;\n }\n\n console.log('canClose', {\n value,\n hasMediaAttachments,\n hasIDMediaAttachments,\n poll,\n isSelf,\n hasOnlyAcct,\n sameWithSource,\n uiState,\n });\n\n return false;\n };\n\n const confirmClose = () => {\n if (!canClose()) {\n const yes = confirm(beforeUnloadCopy);\n return yes;\n }\n return true;\n };\n\n useEffect(() => {\n // Show warning if user tries to close window with unsaved changes\n const handleBeforeUnload = (e) => {\n if (!canClose()) {\n e.preventDefault();\n e.returnValue = beforeUnloadCopy;\n }\n };\n window.addEventListener('beforeunload', handleBeforeUnload, {\n capture: true,\n });\n return () =>\n window.removeEventListener('beforeunload', handleBeforeUnload, {\n capture: true,\n });\n }, []);\n\n const getCharCount = () => {\n const { value } = textareaRef.current;\n const { value: spoilerText } = spoilerTextRef.current;\n return stringLength(countableText(value)) + stringLength(spoilerText);\n };\n const updateCharCount = () => {\n const count = getCharCount();\n states.composerCharacterCount = count;\n };\n useEffect(updateCharCount, []);\n\n const supportsCloseWatcher = window.CloseWatcher;\n const escDownRef = useRef(false);\n useHotkeys(\n 'esc',\n () => {\n escDownRef.current = true;\n // This won't be true if this event is already handled and not propagated 🤞\n },\n {\n enabled: !supportsCloseWatcher,\n enableOnFormTags: true,\n },\n );\n useHotkeys(\n 'esc',\n () => {\n if (!standalone && escDownRef.current && confirmClose()) {\n onClose();\n }\n escDownRef.current = false;\n },\n {\n enabled: !supportsCloseWatcher,\n enableOnFormTags: true,\n // Use keyup because Esc keydown will close the confirm dialog on Safari\n keyup: true,\n ignoreEventWhen: () => {\n const modals = document.querySelectorAll('#modal-container > *');\n const hasModal = !!modals;\n const hasOnlyComposer =\n modals.length === 1 && modals[0].querySelector('#compose-container');\n return hasModal && !hasOnlyComposer;\n },\n },\n );\n useCloseWatcher(() => {\n if (!standalone && confirmClose()) {\n onClose();\n }\n }, []);\n\n const prevBackgroundDraft = useRef({});\n const draftKey = () => {\n const ns = getCurrentAccountNS();\n return `${ns}#${UID.current}`;\n };\n const saveUnsavedDraft = () => {\n // Not enabling this for editing status\n // I don't think this warrant a draft mode for a status that's already posted\n // Maybe it could be a big edit change but it should be rare\n if (editStatus) return;\n if (states.composerState.minimized) return;\n const key = draftKey();\n const backgroundDraft = {\n key,\n replyTo: replyToStatus\n ? {\n /* Smaller payload of replyToStatus. Reasons:\n - No point storing whole thing\n - Could have media attachments\n - Could be deleted/edited later\n */\n id: replyToStatus.id,\n account: {\n id: replyToStatus.account.id,\n username: replyToStatus.account.username,\n acct: replyToStatus.account.acct,\n },\n }\n : null,\n draftStatus: {\n uid: UID.current,\n status: textareaRef.current.value,\n spoilerText: spoilerTextRef.current.value,\n visibility,\n language,\n sensitive,\n poll,\n mediaAttachments,\n scheduledAt,\n },\n };\n if (\n !deepEqual(backgroundDraft, prevBackgroundDraft.current) &&\n !canClose()\n ) {\n console.debug('not equal', backgroundDraft, prevBackgroundDraft.current);\n db.drafts\n .set(key, {\n ...backgroundDraft,\n state: 'unsaved',\n updatedAt: Date.now(),\n })\n .then(() => {\n console.debug('DRAFT saved', key, backgroundDraft);\n })\n .catch((e) => {\n console.error('DRAFT failed', key, e);\n });\n prevBackgroundDraft.current = structuredClone(backgroundDraft);\n }\n };\n useInterval(saveUnsavedDraft, 5000); // background save every 5s\n useEffect(() => {\n saveUnsavedDraft();\n // If unmounted, means user discarded the draft\n // Also means pop-out 🙈, but it's okay because the pop-out will persist the ID and re-create the draft\n return () => {\n db.drafts.del(draftKey());\n };\n }, []);\n\n useEffect(() => {\n const handleItems = (e) => {\n const { items } = e.clipboardData || e.dataTransfer;\n const files = [];\n const unsupportedFiles = [];\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (item.kind === 'file') {\n const file = item.getAsFile();\n if (\n supportedMimeTypes !== undefined &&\n !supportedMimeTypes.includes(file.type)\n ) {\n unsupportedFiles.push(file);\n } else {\n files.push(file);\n }\n }\n }\n if (unsupportedFiles.length > 0) {\n alert(\n plural(unsupportedFiles.length, {\n one: `File ${unsupportedFiles[0].name} is not supported.`,\n other: `Files ${lf.format(\n unsupportedFiles.map((f) => f.name),\n )} are not supported.`,\n }),\n );\n }\n if (files.length > 0 && mediaAttachments.length >= maxMediaAttachments) {\n alert(\n plural(maxMediaAttachments, {\n one: 'You can only attach up to 1 file.',\n other: 'You can only attach up to # files.',\n }),\n );\n return;\n }\n console.log({ files });\n if (files.length > 0) {\n e.preventDefault();\n e.stopPropagation();\n // Auto-cut-off files to avoid exceeding maxMediaAttachments\n let allowedFiles = files;\n if (maxMediaAttachments !== undefined) {\n const max = maxMediaAttachments - mediaAttachments.length;\n allowedFiles = allowedFiles.slice(0, max);\n if (allowedFiles.length <= 0) {\n alert(\n plural(maxMediaAttachments, {\n one: 'You can only attach up to 1 file.',\n other: 'You can only attach up to # files.',\n }),\n );\n return;\n }\n }\n const mediaFiles = allowedFiles.map((file) => ({\n file,\n type: file.type,\n size: file.size,\n url: URL.createObjectURL(file),\n id: null,\n description: null,\n }));\n setMediaAttachments([...mediaAttachments, ...mediaFiles]);\n }\n };\n window.addEventListener('paste', handleItems);\n const handleDragover = (e) => {\n // Prevent default if there's files\n if (e.dataTransfer.items.length > 0) {\n e.preventDefault();\n e.stopPropagation();\n }\n };\n window.addEventListener('dragover', handleDragover);\n window.addEventListener('drop', handleItems);\n return () => {\n window.removeEventListener('paste', handleItems);\n window.removeEventListener('dragover', handleDragover);\n window.removeEventListener('drop', handleItems);\n };\n }, [mediaAttachments]);\n\n const [showMentionPicker, setShowMentionPicker] = useState(false);\n const [showEmoji2Picker, setShowEmoji2Picker] = useState(false);\n const [showGIFPicker, setShowGIFPicker] = useState(false);\n\n const [autoDetectedLanguages, setAutoDetectedLanguages] = useState(null);\n const [topSupportedLanguages, restSupportedLanguages] = useMemo(() => {\n const topLanguages = [];\n const restLanguages = [];\n const { contentTranslationHideLanguages = [] } = states.settings;\n supportedLanguages.forEach((l) => {\n const [code] = l;\n if (\n code === language ||\n code === prevLanguage.current ||\n code === DEFAULT_LANG ||\n contentTranslationHideLanguages.includes(code) ||\n (autoDetectedLanguages?.length && autoDetectedLanguages.includes(code))\n ) {\n topLanguages.push(l);\n } else {\n restLanguages.push(l);\n }\n });\n topLanguages.sort(([codeA, commonA], [codeB, commonB]) => {\n if (codeA === language) return -1;\n if (codeB === language) return 1;\n return commonA.localeCompare(commonB);\n });\n restLanguages.sort(([codeA, commonA], [codeB, commonB]) =>\n commonA.localeCompare(commonB),\n );\n return [topLanguages, restLanguages];\n }, [language, autoDetectedLanguages]);\n\n const replyToStatusMonthsAgo = useMemo(\n () =>\n !!replyToStatus?.createdAt &&\n Math.floor(\n (Date.now() - new Date(replyToStatus.createdAt)) /\n (1000 * 60 * 60 * 24 * 30),\n ),\n [replyToStatus],\n );\n\n const onMinimize = () => {\n saveUnsavedDraft();\n states.composerState.minimized = true;\n };\n\n const gifPickerDisabled =\n uiState === 'loading' ||\n (maxMediaAttachments !== undefined &&\n mediaAttachments.length >= maxMediaAttachments) ||\n !!poll;\n\n // If maxOptions is not defined or defined and is greater than 1, show poll button\n const showPollButton = maxOptions == null || maxOptions > 1;\n const pollButtonDisabled =\n uiState === 'loading' || !!poll || !!mediaAttachments.length;\n const onPollButtonClick = () => {\n setPoll({\n options: ['', ''],\n expiresIn: 24 * 60 * 60, // 1 day\n multiple: false,\n });\n };\n\n const addSubToolbarRef = useRef();\n const [showAddButton, setShowAddButton] = useState(false);\n useResizeObserver({\n ref: addSubToolbarRef,\n box: 'border-box',\n onResize: ({ width }) => {\n // If scrollable, it's truncated\n const { scrollWidth } = addSubToolbarRef.current;\n const truncated = scrollWidth > width;\n const overTruncated = width < 84; // roughly two buttons width\n setShowAddButton(overTruncated || truncated);\n addSubToolbarRef.current.hidden = overTruncated;\n },\n });\n\n const showScheduledAt = !editStatus;\n const scheduledAtButtonDisabled = uiState === 'loading' || !!scheduledAt;\n const onScheduledAtClick = () => {\n const date = new Date(Date.now() + MIN_SCHEDULED_AT);\n setScheduledAt(date);\n };\n\n return (\n <div id=\"compose-container-outer\">\n <div id=\"compose-container\" class={standalone ? 'standalone' : ''}>\n <div class=\"compose-top\">\n {currentAccountInfo?.avatarStatic && (\n // <Avatar\n // url={currentAccountInfo.avatarStatic}\n // size=\"xl\"\n // alt={currentAccountInfo.username}\n // squircle={currentAccountInfo?.bot}\n // />\n <AccountBlock\n account={currentAccountInfo}\n accountInstance={currentAccount.instanceURL}\n hideDisplayName\n useAvatarStatic\n />\n )}\n {!standalone ? (\n <span class=\"compose-controls\">\n <button\n type=\"button\"\n class=\"plain4 pop-button\"\n disabled={uiState === 'loading'}\n onClick={() => {\n // If there are non-ID media attachments (not yet uploaded), show confirmation dialog because they are not going to be passed to the new window\n // const containNonIDMediaAttachments =\n // mediaAttachments.length > 0 &&\n // mediaAttachments.some((media) => !media.id);\n // if (containNonIDMediaAttachments) {\n // const yes = confirm(\n // 'You have media attachments that are not yet uploaded. Opening a new window will discard them and you will need to re-attach them. Are you sure you want to continue?',\n // );\n // if (!yes) {\n // return;\n // }\n // }\n\n // const mediaAttachmentsWithIDs = mediaAttachments.filter(\n // (media) => media.id,\n // );\n\n const newWin = openCompose({\n editStatus,\n replyToStatus,\n draftStatus: {\n uid: UID.current,\n status: textareaRef.current.value,\n spoilerText: spoilerTextRef.current.value,\n visibility,\n language,\n sensitive,\n poll,\n mediaAttachments,\n scheduledAt,\n },\n });\n\n if (!newWin) {\n return;\n }\n\n onClose();\n }}\n >\n <Icon icon=\"popout\" alt={t`Pop out`} />\n </button>\n <button\n type=\"button\"\n class=\"plain4 min-button\"\n onClick={onMinimize}\n >\n <Icon icon=\"minimize\" alt={t`Minimize`} />\n </button>{' '}\n <button\n type=\"button\"\n class=\"light close-button\"\n disabled={uiState === 'loading'}\n onClick={() => {\n if (confirmClose()) {\n onClose();\n }\n }}\n >\n <Icon icon=\"x\" alt={t`Close`} />\n </button>\n </span>\n ) : (\n hasOpener && (\n <button\n type=\"button\"\n class=\"light pop-button\"\n disabled={uiState === 'loading'}\n onClick={() => {\n // If there are non-ID media attachments (not yet uploaded), show confirmation dialog because they are not going to be passed to the new window\n // const containNonIDMediaAttachments =\n // mediaAttachments.length > 0 &&\n // mediaAttachments.some((media) => !media.id);\n // if (containNonIDMediaAttachments) {\n // const yes = confirm(\n // 'You have media attachments that are not yet uploaded. Opening a new window will discard them and you will need to re-attach them. Are you sure you want to continue?',\n // );\n // if (!yes) {\n // return;\n // }\n // }\n\n if (!window.opener) {\n alert(t`Looks like you closed the parent window.`);\n return;\n }\n\n if (window.opener.__STATES__.showCompose) {\n if (window.opener.__STATES__.composerState?.publishing) {\n alert(\n t`Looks like you already have a compose field open in the parent window and currently publishing. Please wait for it to be done and try again later.`,\n );\n return;\n }\n\n let confirmText = t`Looks like you already have a compose field open in the parent window. Popping in this window will discard the changes you made in the parent window. Continue?`;\n const yes = confirm(confirmText);\n if (!yes) return;\n }\n\n // const mediaAttachmentsWithIDs = mediaAttachments.filter(\n // (media) => media.id,\n // );\n\n onClose({\n fn: () => {\n const passData = {\n editStatus,\n replyToStatus,\n draftStatus: {\n uid: UID.current,\n status: textareaRef.current.value,\n spoilerText: spoilerTextRef.current.value,\n visibility,\n language,\n sensitive,\n poll,\n mediaAttachments,\n scheduledAt,\n },\n };\n window.opener.__COMPOSE__ = passData; // Pass it here instead of `showCompose` due to some weird proxy issue again\n if (window.opener.__STATES__.showCompose) {\n window.opener.__STATES__.showCompose = false;\n setTimeout(() => {\n window.opener.__STATES__.showCompose = true;\n }, 10);\n } else {\n window.opener.__STATES__.showCompose = true;\n }\n if (window.opener.__STATES__.composerState.minimized) {\n // Maximize it\n window.opener.__STATES__.composerState.minimized = false;\n }\n },\n });\n }}\n >\n <Icon icon=\"popin\" alt={t`Pop in`} />\n </button>\n )\n )}\n </div>\n {!!replyToStatus && (\n <div class=\"status-preview\">\n <Status status={replyToStatus} size=\"s\" previewMode />\n <div class=\"status-preview-legend reply-to\">\n {replyToStatusMonthsAgo > 0 ? (\n <Trans>\n Replying to @\n {replyToStatus.account.acct || replyToStatus.account.username}\n ’s post (\n <strong>\n {rtf.format(-replyToStatusMonthsAgo, 'month')}\n </strong>\n )\n </Trans>\n ) : (\n <Trans>\n Replying to @\n {replyToStatus.account.acct || replyToStatus.account.username}\n ’s post\n </Trans>\n )}\n </div>\n </div>\n )}\n {!!editStatus && (\n <div class=\"status-preview\">\n <Status status={editStatus} size=\"s\" previewMode />\n <div class=\"status-preview-legend\">\n <Trans>Editing source post</Trans>\n </div>\n </div>\n )}\n <form\n ref={formRef}\n class={`form-visibility-${visibility}`}\n style={{\n pointerEvents: uiState === 'loading' ? 'none' : 'auto',\n opacity: uiState === 'loading' ? 0.5 : 1,\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {\n formRef.current.dispatchEvent(\n new Event('submit', { cancelable: true }),\n );\n }\n }}\n onSubmit={(e) => {\n e.preventDefault();\n\n const formData = new FormData(e.target);\n const entries = Object.fromEntries(formData.entries());\n console.log('ENTRIES', entries);\n let { status, visibility, sensitive, spoilerText, scheduledAt } =\n entries;\n\n // Pre-cleanup\n sensitive = sensitive === 'on'; // checkboxes return \"on\" if checked\n\n // Convert datetime-local input value to RFC3339 Date string value\n scheduledAt = scheduledAt\n ? new Date(scheduledAt).toISOString()\n : undefined;\n\n // Validation\n /* Let the backend validate this\n if (stringLength(status) > maxCharacters) {\n alert(`Status is too long! Max characters: ${maxCharacters}`);\n return;\n }\n if (\n sensitive &&\n stringLength(status) + stringLength(spoilerText) > maxCharacters\n ) {\n alert(\n `Status and content warning is too long! Max characters: ${maxCharacters}`,\n );\n return;\n }\n */\n if (poll) {\n if (poll.options.length < 2) {\n alert(t`Poll must have at least 2 options`);\n return;\n }\n if (poll.options.some((option) => option === '')) {\n alert(t`Some poll choices are empty`);\n return;\n }\n }\n // TODO: check for URLs and use `charactersReservedPerUrl` to calculate max characters\n\n if (mediaAttachments.length > 0) {\n // If there are media attachments, check if they have no descriptions\n const hasNoDescriptions = mediaAttachments.some(\n (media) => !media.description?.trim?.(),\n );\n if (hasNoDescriptions) {\n const yes = confirm(\n t`Some media have no descriptions. Continue?`,\n );\n if (!yes) return;\n }\n }\n\n // Post-cleanup\n spoilerText = (sensitive && spoilerText) || undefined;\n status = status === '' ? undefined : status;\n\n // states.composerState.minimized = true;\n states.composerState.publishing = true;\n setUIState('loading');\n (async () => {\n try {\n console.log('MEDIA ATTACHMENTS', mediaAttachments);\n if (mediaAttachments.length > 0) {\n // Upload media attachments first\n const mediaPromises = mediaAttachments.map((attachment) => {\n const { file, description, id } = attachment;\n console.log('UPLOADING', attachment);\n if (id) {\n // If already uploaded\n return attachment;\n } else {\n const params = removeNullUndefined({\n file,\n description,\n });\n return masto.v2.media.create(params).then((res) => {\n if (res.id) {\n attachment.id = res.id;\n }\n return res;\n });\n }\n });\n const results = await Promise.allSettled(mediaPromises);\n\n // If any failed, return\n if (\n results.some((result) => {\n return result.status === 'rejected' || !result.value?.id;\n })\n ) {\n states.composerState.publishing = false;\n states.composerState.publishingError = true;\n setUIState('error');\n // Alert all the reasons\n results.forEach((result) => {\n if (result.status === 'rejected') {\n console.error(result);\n alert(result.reason || t`Attachment #${i} failed`);\n }\n });\n return;\n }\n\n console.log({ results, mediaAttachments });\n }\n\n /* NOTE:\n Using snakecase here because masto.js's `isObject` returns false for `params`, ONLY happens when opening in pop-out window. This is maybe due to `window.masto` variable being passed from the parent window. The check that failed is `x.constructor === Object`, so maybe the `Object` in new window is different than parent window's?\n Code: https://github.com/neet/masto.js/blob/dd0d649067b6a2b6e60fbb0a96597c373a255b00/src/serializers/is-object.ts#L2\n\n // TODO: Note above is no longer true in Masto.js v6. Revisit this.\n */\n let params = {\n status,\n // spoilerText,\n spoiler_text: spoilerText,\n language,\n sensitive,\n poll,\n // mediaIds: mediaAttachments.map((attachment) => attachment.id),\n media_ids: mediaAttachments.map(\n (attachment) => attachment.id,\n ),\n };\n if (editStatus && supports('@mastodon/edit-media-attributes')) {\n params.media_attributes = mediaAttachments.map(\n (attachment) => {\n return {\n id: attachment.id,\n description: attachment.description,\n // focus\n // thumbnail\n };\n },\n );\n } else if (!editStatus) {\n params.visibility = visibility;\n // params.inReplyToId = replyToStatus?.id || undefined;\n params.in_reply_to_id = replyToStatus?.id || undefined;\n params.scheduled_at = scheduledAt;\n }\n params = removeNullUndefined(params);\n console.log('POST', params);\n\n let newStatus;\n if (editStatus) {\n newStatus = await masto.v1.statuses\n .$select(editStatus.id)\n .update(params);\n saveStatus(newStatus, instance, {\n skipThreading: true,\n });\n } else {\n try {\n newStatus = await masto.v1.statuses.create(params, {\n requestInit: {\n headers: {\n 'Idempotency-Key': UID.current,\n },\n },\n });\n } catch (_) {\n // If idempotency key fails, try again without it\n newStatus = await masto.v1.statuses.create(params);\n }\n }\n states.composerState.minimized = false;\n states.composerState.publishing = false;\n setUIState('default');\n\n // Close\n onClose({\n // type: post, reply, edit\n type: editStatus ? 'edit' : replyToStatus ? 'reply' : 'post',\n newStatus,\n instance,\n scheduledAt,\n });\n } catch (e) {\n states.composerState.publishing = false;\n states.composerState.publishingError = true;\n console.error(e);\n alert(e?.reason || e);\n setUIState('error');\n }\n })();\n }}\n >\n <div class=\"toolbar stretch\">\n <input\n ref={spoilerTextRef}\n type=\"text\"\n name=\"spoilerText\"\n placeholder={t`Content warning`}\n disabled={uiState === 'loading'}\n class=\"spoiler-text-field\"\n lang={language}\n spellCheck=\"true\"\n dir=\"auto\"\n style={{\n opacity: sensitive ? 1 : 0,\n pointerEvents: sensitive ? 'auto' : 'none',\n }}\n onInput={() => {\n updateCharCount();\n }}\n />\n <label\n class={`toolbar-button ${sensitive ? 'highlight' : ''}`}\n title={t`Content warning or sensitive media`}\n >\n <input\n name=\"sensitive\"\n type=\"checkbox\"\n checked={sensitive}\n disabled={uiState === 'loading'}\n onChange={(e) => {\n const sensitive = e.target.checked;\n setSensitive(sensitive);\n if (sensitive) {\n spoilerTextRef.current?.focus();\n } else {\n textareaRef.current?.focus();\n }\n }}\n />\n <Icon icon={`eye-${sensitive ? 'close' : 'open'}`} />\n </label>{' '}\n <label\n class={`toolbar-button ${\n visibility !== 'public' && !sensitive ? 'show-field' : ''\n } ${visibility !== 'public' ? 'highlight' : ''}`}\n title={visibility}\n >\n <Icon icon={visibilityIconsMap[visibility]} alt={visibility} />\n <select\n name=\"visibility\"\n value={visibility}\n onChange={(e) => {\n setVisibility(e.target.value);\n }}\n disabled={uiState === 'loading' || !!editStatus}\n dir=\"auto\"\n >\n <option value=\"public\">\n <Trans>Public</Trans>\n </option>\n {(supports('@pleroma/local-visibility-post') ||\n supports('@akkoma/local-visibility-post')) && (\n <option value=\"local\">\n <Trans>Local</Trans>\n </option>\n )}\n <option value=\"unlisted\">\n <Trans>Unlisted</Trans>\n </option>\n <option value=\"private\">\n <Trans>Followers only</Trans>\n </option>\n <option value=\"direct\">\n <Trans>Private mention</Trans>\n </option>\n </select>\n </label>{' '}\n </div>\n <Textarea\n ref={textareaRef}\n placeholder={\n replyToStatus\n ? t`Post your reply`\n : editStatus\n ? t`Edit your post`\n : t`What are you doing?`\n }\n required={mediaAttachments?.length === 0}\n disabled={uiState === 'loading'}\n lang={language}\n onInput={() => {\n updateCharCount();\n }}\n maxCharacters={maxCharacters}\n performSearch={(params) => {\n const { type, q, limit } = params;\n if (type === 'accounts') {\n return masto.v1.accounts.search.list({\n q,\n limit,\n resolve: false,\n });\n }\n return masto.v2.search.fetch(params);\n }}\n onTrigger={(action) => {\n if (action?.name === 'custom-emojis') {\n setShowEmoji2Picker({\n defaultSearchTerm: action?.defaultSearchTerm || null,\n });\n } else if (action?.name === 'mention') {\n setShowMentionPicker({\n defaultSearchTerm: action?.defaultSearchTerm || null,\n });\n } else if (\n action?.name === 'auto-detect-language' &&\n action?.languages\n ) {\n setAutoDetectedLanguages(action.languages);\n }\n }}\n />\n {mediaAttachments?.length > 0 && (\n <div class=\"media-attachments\">\n {mediaAttachments.map((attachment, i) => {\n const { id, file } = attachment;\n const fileID = file?.size + file?.type + file?.name;\n return (\n <MediaAttachment\n key={id || fileID || i}\n attachment={attachment}\n disabled={uiState === 'loading'}\n lang={language}\n onDescriptionChange={(value) => {\n setMediaAttachments((attachments) => {\n const newAttachments = [...attachments];\n newAttachments[i] = {\n ...newAttachments[i],\n description: value,\n };\n return newAttachments;\n });\n }}\n onRemove={() => {\n setMediaAttachments((attachments) => {\n return attachments.filter((_, j) => j !== i);\n });\n }}\n />\n );\n })}\n <label class=\"media-sensitive\">\n <input\n name=\"sensitive\"\n type=\"checkbox\"\n checked={sensitive}\n disabled={uiState === 'loading'}\n onChange={(e) => {\n const sensitive = e.target.checked;\n setSensitive(sensitive);\n }}\n />{' '}\n <span>\n <Trans>Mark media as sensitive</Trans>\n </span>{' '}\n <Icon icon={`eye-${sensitive ? 'close' : 'open'}`} />\n </label>\n </div>\n )}\n {!!poll && (\n <Poll\n lang={language}\n maxOptions={maxOptions}\n maxExpiration={maxExpiration}\n minExpiration={minExpiration}\n maxCharactersPerOption={maxCharactersPerOption}\n poll={poll}\n disabled={uiState === 'loading'}\n onInput={(poll) => {\n if (poll) {\n const newPoll = { ...poll };\n setPoll(newPoll);\n } else {\n setPoll(null);\n }\n }}\n />\n )}\n {scheduledAt && (\n <div class=\"toolbar scheduled-at\">\n <button\n type=\"button\"\n class=\"plain4 small\"\n onClick={() => {\n setScheduledAt(null);\n }}\n >\n <Icon icon=\"x\" />\n </button>\n <label>\n <Trans>\n Posting on{' '}\n <ScheduledAtField\n scheduledAt={scheduledAt}\n setScheduledAt={setScheduledAt}\n />\n </Trans>\n <br />\n <small>{getLocalTimezoneName()}</small>\n </label>\n </div>\n )}\n <div class=\"toolbar compose-footer\">\n <span class=\"add-toolbar-button-group spacer\">\n {showAddButton && (\n <Menu2\n portal={{\n target: document.body,\n }}\n containerProps={{\n style: {\n zIndex: 1001,\n },\n }}\n menuButton={({ open }) => (\n <button\n type=\"button\"\n class={`toolbar-button add-button ${\n open ? 'active' : ''\n }`}\n >\n <Icon icon=\"plus\" title={t`Add`} />\n </button>\n )}\n >\n {supportsCameraCapture && (\n <MenuItem className=\"compose-menu-add-media\">\n <label class=\"compose-menu-add-media-field\">\n <CameraCaptureInput\n hidden\n supportedMimeTypes={supportedImagesVideosTypes}\n disabled={\n uiState === 'loading' ||\n mediaAttachments.length >= maxMediaAttachments ||\n !!poll\n }\n setMediaAttachments={setMediaAttachments}\n />\n </label>\n <Icon icon=\"camera\" /> <span>{_(ADD_LABELS.camera)}</span>\n </MenuItem>\n )}\n <MenuItem className=\"compose-menu-add-media\">\n <label class=\"compose-menu-add-media-field\">\n <FilePickerInput\n hidden\n supportedMimeTypes={supportedMimeTypes}\n maxMediaAttachments={maxMediaAttachments}\n mediaAttachments={mediaAttachments}\n disabled={\n uiState === 'loading' ||\n mediaAttachments.length >= maxMediaAttachments ||\n !!poll\n }\n setMediaAttachments={setMediaAttachments}\n />\n </label>\n <Icon icon=\"media\" /> <span>{_(ADD_LABELS.media)}</span>\n </MenuItem>\n <MenuItem\n onClick={() => {\n setShowEmoji2Picker(true);\n }}\n >\n <Icon icon=\"emoji2\" />{' '}\n <span>{_(ADD_LABELS.customEmoji)}</span>\n </MenuItem>\n {!!states.settings.composerGIFPicker && (\n <MenuItem\n disabled={gifPickerDisabled}\n onClick={() => {\n setShowGIFPicker(true);\n }}\n >\n <span class=\"icon icon-gif\" role=\"img\" />\n <span>{_(ADD_LABELS.gif)}</span>\n </MenuItem>\n )}\n {showPollButton && (\n <MenuItem\n disabled={pollButtonDisabled}\n onClick={onPollButtonClick}\n >\n <Icon icon=\"poll\" /> <span>{_(ADD_LABELS.poll)}</span>\n </MenuItem>\n )}\n {showScheduledAt && (\n <MenuItem\n disabled={scheduledAtButtonDisabled}\n onClick={onScheduledAtClick}\n >\n <Icon icon=\"schedule\" />{' '}\n <span>{_(ADD_LABELS.scheduledPost)}</span>\n </MenuItem>\n )}\n </Menu2>\n )}\n <span class=\"add-sub-toolbar-button-group\" ref={addSubToolbarRef}>\n {supportsCameraCapture && (\n <label class=\"toolbar-button\">\n <CameraCaptureInput\n supportedMimeTypes={supportedImagesVideosTypes}\n mediaAttachments={mediaAttachments}\n disabled={\n uiState === 'loading' ||\n mediaAttachments.length >= maxMediaAttachments ||\n !!poll\n }\n setMediaAttachments={setMediaAttachments}\n />\n <Icon icon=\"camera\" alt={_(ADD_LABELS.camera)} />\n </label>\n )}\n <label class=\"toolbar-button\">\n <FilePickerInput\n supportedMimeTypes={supportedMimeTypes}\n maxMediaAttachments={maxMediaAttachments}\n mediaAttachments={mediaAttachments}\n disabled={\n uiState === 'loading' ||\n mediaAttachments.length >= maxMediaAttachments ||\n !!poll\n }\n setMediaAttachments={setMediaAttachments}\n />\n <Icon icon=\"media\" alt={_(ADD_LABELS.media)} />\n </label>\n {/* <button\n type=\"button\"\n class=\"toolbar-button\"\n disabled={uiState === 'loading'}\n onClick={() => {\n setShowMentionPicker(true);\n }}\n >\n <Icon icon=\"at\" />\n </button> */}\n <button\n type=\"button\"\n class=\"toolbar-button\"\n disabled={uiState === 'loading'}\n onClick={() => {\n setShowEmoji2Picker(true);\n }}\n >\n <Icon icon=\"emoji2\" alt={_(ADD_LABELS.customEmoji)} />\n </button>\n {!!states.settings.composerGIFPicker && (\n <button\n type=\"button\"\n class=\"toolbar-button gif-picker-button\"\n disabled={gifPickerDisabled}\n onClick={() => {\n setShowGIFPicker(true);\n }}\n >\n <span\n class=\"icon icon-gif\"\n aria-label={_(ADD_LABELS.gif)}\n />\n </button>\n )}\n {showPollButton && (\n <>\n <button\n type=\"button\"\n class=\"toolbar-button\"\n disabled={pollButtonDisabled}\n onClick={onPollButtonClick}\n >\n <Icon icon=\"poll\" alt={_(ADD_LABELS.poll)} />\n </button>\n </>\n )}\n {showScheduledAt && (\n <button\n type=\"button\"\n class={`toolbar-button ${scheduledAt ? 'highlight' : ''}`}\n disabled={scheduledAtButtonDisabled}\n onClick={onScheduledAtClick}\n >\n <Icon icon=\"schedule\" alt={_(ADD_LABELS.scheduledPost)} />\n </button>\n )}\n </span>\n </span>\n {/* <div class=\"spacer\" /> */}\n {uiState === 'loading' ? (\n <Loader abrupt />\n ) : (\n <CharCountMeter\n maxCharacters={maxCharacters}\n hidden={uiState === 'loading'}\n />\n )}\n <label\n class={`toolbar-button ${\n language !== prevLanguage.current ||\n (autoDetectedLanguages?.length &&\n !autoDetectedLanguages.includes(language))\n ? 'highlight'\n : ''\n }`}\n >\n <span class=\"icon-text\">\n {supportedLanguagesMap[language]?.native}\n </span>\n <select\n name=\"language\"\n value={language}\n onChange={(e) => {\n const { value } = e.target;\n setLanguage(value || DEFAULT_LANG);\n store.session.set('currentLanguage', value || DEFAULT_LANG);\n }}\n disabled={uiState === 'loading'}\n dir=\"auto\"\n >\n {topSupportedLanguages.map(([code, common, native]) => {\n const commonText = localeCode2Text({\n code,\n fallback: common,\n });\n const showCommon = commonText !== native;\n return (\n <option value={code} key={code}>\n {showCommon ? `${native} - ${commonText}` : commonText}\n </option>\n );\n })}\n <hr />\n {restSupportedLanguages.map(([code, common, native]) => {\n const commonText = localeCode2Text({\n code,\n fallback: common,\n });\n const showCommon = commonText !== native;\n return (\n <option value={code} key={code}>\n {showCommon ? `${native} - ${commonText}` : commonText}\n </option>\n );\n })}\n </select>\n </label>{' '}\n <button type=\"submit\" disabled={uiState === 'loading'}>\n {scheduledAt\n ? t`Schedule`\n : replyToStatus\n ? t`Reply`\n : editStatus\n ? t`Update`\n : t({\n message: 'Post',\n context: 'Submit button in composer',\n })}\n </button>\n </div>\n </form>\n </div>\n {showMentionPicker && (\n <Modal\n onClose={() => {\n setShowMentionPicker(false);\n }}\n >\n <MentionModal\n masto={masto}\n instance={instance}\n onClose={() => {\n setShowMentionPicker(false);\n }}\n defaultSearchTerm={showMentionPicker?.defaultSearchTerm}\n onSelect={(socialAddress) => {\n const textarea = textareaRef.current;\n if (!textarea) return;\n const { selectionStart, selectionEnd } = textarea;\n const text = textarea.value;\n const textBeforeMention = text.slice(0, selectionStart);\n const spaceBeforeMention = textBeforeMention\n ? /[\\s\\t\\n\\r]$/.test(textBeforeMention)\n ? ''\n : ' '\n : '';\n const textAfterMention = text.slice(selectionEnd);\n const spaceAfterMention = /^[\\s\\t\\n\\r]/.test(textAfterMention)\n ? ''\n : ' ';\n const newText =\n textBeforeMention +\n spaceBeforeMention +\n '@' +\n socialAddress +\n spaceAfterMention +\n textAfterMention;\n textarea.value = newText;\n textarea.selectionStart = textarea.selectionEnd =\n selectionEnd +\n 1 +\n socialAddress.length +\n spaceAfterMention.length;\n textarea.focus();\n textarea.dispatchEvent(new Event('input'));\n }}\n />\n </Modal>\n )}\n {showEmoji2Picker && (\n <Modal\n onClose={() => {\n setShowEmoji2Picker(false);\n }}\n >\n <CustomEmojisModal\n masto={masto}\n instance={instance}\n onClose={() => {\n setShowEmoji2Picker(false);\n }}\n defaultSearchTerm={showEmoji2Picker?.defaultSearchTerm}\n onSelect={(emojiShortcode) => {\n const textarea = textareaRef.current;\n if (!textarea) return;\n const { selectionStart, selectionEnd } = textarea;\n const text = textarea.value;\n const textBeforeEmoji = text.slice(0, selectionStart);\n const spaceBeforeEmoji = textBeforeEmoji\n ? /[\\s\\t\\n\\r]$/.test(textBeforeEmoji)\n ? ''\n : ' '\n : '';\n const textAfterEmoji = text.slice(selectionEnd);\n const spaceAfterEmoji = /^[\\s\\t\\n\\r]/.test(textAfterEmoji)\n ? ''\n : ' ';\n const newText =\n textBeforeEmoji +\n spaceBeforeEmoji +\n emojiShortcode +\n spaceAfterEmoji +\n textAfterEmoji;\n textarea.value = newText;\n textarea.selectionStart = textarea.selectionEnd =\n selectionEnd + emojiShortcode.length + spaceAfterEmoji.length;\n textarea.focus();\n textarea.dispatchEvent(new Event('input'));\n }}\n />\n </Modal>\n )}\n {showGIFPicker && (\n <Modal\n onClose={() => {\n setShowGIFPicker(false);\n }}\n >\n <GIFPickerModal\n onClose={() => setShowGIFPicker(false)}\n onSelect={({ url, type, alt_text }) => {\n console.log('GIF URL', url);\n if (mediaAttachments.length >= maxMediaAttachments) {\n alert(\n plural(maxMediaAttachments, {\n one: 'You can only attach up to 1 file.',\n other: 'You can only attach up to # files.',\n }),\n );\n return;\n }\n // Download the GIF and insert it as media attachment\n (async () => {\n let theToast;\n try {\n theToast = showToast({\n text: t`Downloading GIF…`,\n duration: -1,\n });\n const blob = await fetch(url, {\n referrerPolicy: 'no-referrer',\n }).then((res) => res.blob());\n const file = new File(\n [blob],\n type === 'video/mp4' ? 'video.mp4' : 'image.gif',\n {\n type,\n },\n );\n const newMediaAttachments = [\n ...mediaAttachments,\n {\n file,\n type,\n size: file.size,\n id: null,\n description: alt_text || '',\n },\n ];\n setMediaAttachments(newMediaAttachments);\n theToast?.hideToast?.();\n } catch (err) {\n console.error(err);\n theToast?.hideToast?.();\n showToast(t`Failed to download GIF`);\n }\n })();\n }}\n />\n </Modal>\n )}\n </div>\n );\n}\n\nconst supportsCameraCapture = (() => {\n const input = document.createElement('input');\n return 'capture' in input;\n})();\nfunction CameraCaptureInput({\n hidden,\n disabled = false,\n supportedMimeTypes,\n setMediaAttachments,\n}) {\n return (\n <input\n type=\"file\"\n hidden={hidden}\n accept={supportedMimeTypes?.join(',')}\n capture=\"environment\"\n disabled={disabled}\n onChange={(e) => {\n const files = e.target.files;\n if (!files) return;\n const mediaFile = Array.from(files)[0];\n if (!mediaFile) return;\n setMediaAttachments((attachments) => [\n ...attachments,\n {\n file: mediaFile,\n type: mediaFile.type,\n size: mediaFile.size,\n url: URL.createObjectURL(mediaFile),\n id: null, // indicate uploaded state\n description: null,\n },\n ]);\n e.target.value = null;\n }}\n />\n );\n}\n\nfunction FilePickerInput({\n hidden,\n supportedMimeTypes,\n maxMediaAttachments,\n mediaAttachments,\n disabled = false,\n setMediaAttachments,\n}) {\n return (\n <input\n type=\"file\"\n hidden={hidden}\n accept={supportedMimeTypes?.join(',')}\n multiple={\n maxMediaAttachments === undefined ||\n maxMediaAttachments - mediaAttachments >= 2\n }\n disabled={disabled}\n onChange={(e) => {\n const files = e.target.files;\n if (!files) return;\n\n const mediaFiles = Array.from(files).map((file) => ({\n file,\n type: file.type,\n size: file.size,\n url: URL.createObjectURL(file),\n id: null, // indicate uploaded state\n description: null,\n }));\n console.log('MEDIA ATTACHMENTS', files, mediaFiles);\n\n // Validate max media attachments\n if (mediaAttachments.length + mediaFiles.length > maxMediaAttachments) {\n alert(\n plural(maxMediaAttachments, {\n one: 'You can only attach up to 1 file.',\n other: 'You can only attach up to # files.',\n }),\n );\n } else {\n setMediaAttachments((attachments) => {\n return attachments.concat(mediaFiles);\n });\n }\n // Reset\n e.target.value = '';\n }}\n />\n );\n}\n\nfunction autoResizeTextarea(textarea) {\n if (!textarea) return;\n const { value, offsetHeight, scrollHeight, clientHeight } = textarea;\n if (offsetHeight < window.innerHeight) {\n // NOTE: This check is needed because the offsetHeight return 50000 (really large number) on first render\n // No idea why it does that, will re-investigate in far future\n const offset = offsetHeight - clientHeight;\n const height = value ? scrollHeight + offset + 'px' : null;\n textarea.style.height = height;\n }\n}\n\nasync function _getCustomEmojis(instance, masto) {\n const emojis = await masto.v1.customEmojis.list();\n const visibleEmojis = emojis.filter((e) => e.visibleInPicker);\n const searcher = new Fuse(visibleEmojis, {\n keys: ['shortcode'],\n findAllMatches: true,\n });\n return [visibleEmojis, searcher];\n}\nconst getCustomEmojis = pmem(_getCustomEmojis, {\n // Limit by time to reduce memory usage\n // Cached by instance\n matchesArg: (cacheKeyArg, keyArg) => cacheKeyArg.instance === keyArg.instance,\n maxAge: 30 * 60 * 1000, // 30 minutes\n});\n\nconst detectLangs = async (text) => {\n if (langDetector) {\n const langs = await langDetector.detect(text);\n if (langs?.length) {\n return langs.slice(0, 2).map((lang) => lang.detectedLanguage);\n }\n }\n const { detectAll } = await import('tinyld/light');\n const langs = detectAll(text);\n if (langs?.length) {\n // return max 2\n return langs.slice(0, 2).map((lang) => lang.lang);\n }\n return null;\n};\n\nconst Textarea = forwardRef((props, ref) => {\n const { t } = useLingui();\n const { masto, instance } = api();\n const [text, setText] = useState(ref.current?.value || '');\n const {\n maxCharacters,\n performSearch = () => {},\n onTrigger = () => {},\n ...textareaProps\n } = props;\n // const snapStates = useSnapshot(states);\n // const charCount = snapStates.composerCharacterCount;\n\n // const customEmojis = useRef();\n const searcherRef = useRef();\n useEffect(() => {\n getCustomEmojis(instance, masto)\n .then((r) => {\n const [emojis, searcher] = r;\n searcherRef.current = searcher;\n })\n .catch((e) => {\n console.error(e);\n });\n }, []);\n\n const textExpanderRef = useRef();\n const textExpanderTextRef = useRef('');\n const hasTextExpanderRef = useRef(false);\n useEffect(() => {\n let handleChange,\n handleValue,\n handleCommited,\n handleActivate,\n handleDeactivate;\n if (textExpanderRef.current) {\n handleChange = (e) => {\n // console.log('text-expander-change', e);\n const { key, provide, text } = e.detail;\n textExpanderTextRef.current = text;\n\n if (text === '') {\n provide(\n Promise.resolve({\n matched: false,\n }),\n );\n return;\n }\n\n if (key === ':') {\n // const emojis = customEmojis.current.filter((emoji) =>\n // emoji.shortcode.startsWith(text),\n // );\n // const emojis = filterShortcodes(customEmojis.current, text);\n const results = searcherRef.current?.search(text, {\n limit: 5,\n });\n let html = '';\n results.forEach(({ item: emoji }) => {\n const { shortcode, url } = emoji;\n html += `\n <li role=\"option\" data-value=\"${encodeHTML(shortcode)}\">\n <img src=\"${encodeHTML(\n url,\n )}\" width=\"16\" height=\"16\" alt=\"\" loading=\"lazy\" /> \n ${encodeHTML(shortcode)}\n </li>`;\n });\n html += `<li role=\"option\" data-value=\"\" data-more=\"${text}\">${t`More…`}</li>`;\n // console.log({ emojis, html });\n menu.innerHTML = html;\n provide(\n Promise.resolve({\n matched: results.length > 0,\n fragment: menu,\n }),\n );\n return;\n }\n\n const type = {\n '@': 'accounts',\n '#': 'hashtags',\n }[key];\n provide(\n new Promise((resolve) => {\n const searchResults = performSearch({\n type,\n q: text,\n limit: 5,\n });\n searchResults.then((value) => {\n if (text !== textExpanderTextRef.current) {\n return;\n }\n console.log({ value, type, v: value[type] });\n const results = value[type] || value;\n console.log('RESULTS', value, results);\n let html = '';\n results.forEach((result) => {\n const {\n name,\n avatarStatic,\n displayName,\n username,\n acct,\n emojis,\n history,\n } = result;\n const displayNameWithEmoji = emojifyText(displayName, emojis);\n // const item = menuItem.cloneNode();\n if (acct) {\n html += `\n <li role=\"option\" data-value=\"${encodeHTML(acct)}\">\n <span class=\"avatar\">\n <img src=\"${encodeHTML(\n avatarStatic,\n )}\" width=\"16\" height=\"16\" alt=\"\" loading=\"lazy\" />\n </span>\n <span>\n <b>${displayNameWithEmoji || username}</b>\n <br><span class=\"bidi-isolate\">@${encodeHTML(\n acct,\n )}</span>\n </span>\n </li>\n `;\n } else {\n const total = history?.reduce?.(\n (acc, cur) => acc + +cur.uses,\n 0,\n );\n html += `\n <li role=\"option\" data-value=\"${encodeHTML(name)}\">\n <span class=\"grow\">#<b>${encodeHTML(name)}</b></span>\n ${\n total\n ? `<span class=\"count\">${shortenNumber(total)}</span>`\n : ''\n }\n </li>\n `;\n }\n });\n if (type === 'accounts') {\n html += `<li role=\"option\" data-value=\"\" data-more=\"${text}\">${t`More…`}</li>`;\n }\n menu.innerHTML = html;\n console.log('MENU', results, menu);\n resolve({\n matched: results.length > 0,\n fragment: menu,\n });\n });\n }),\n );\n };\n\n textExpanderRef.current.addEventListener(\n 'text-expander-change',\n handleChange,\n );\n\n handleValue = (e) => {\n const { key, item } = e.detail;\n const { value, more } = item.dataset;\n if (key === ':') {\n e.detail.value = value ? `:${value}:` : ''; // zero-width space\n if (more) {\n // Prevent adding space after the above value\n e.detail.continue = true;\n\n setTimeout(() => {\n onTrigger?.({\n name: 'custom-emojis',\n defaultSearchTerm: more,\n });\n }, 300);\n }\n } else if (key === '@') {\n e.detail.value = value ? `@${value} ` : ''; // zero-width space\n if (more) {\n e.detail.continue = true;\n setTimeout(() => {\n onTrigger?.({\n name: 'mention',\n defaultSearchTerm: more,\n });\n }, 300);\n }\n } else {\n e.detail.value = `${key}${value}`;\n }\n };\n\n textExpanderRef.current.addEventListener(\n 'text-expander-value',\n handleValue,\n );\n\n handleCommited = (e) => {\n const { input } = e.detail;\n setText(input.value);\n // fire input event\n if (ref.current) {\n const event = new Event('input', { bubbles: true });\n ref.current.dispatchEvent(event);\n }\n };\n\n textExpanderRef.current.addEventListener(\n 'text-expander-committed',\n handleCommited,\n );\n\n handleActivate = () => {\n hasTextExpanderRef.current = true;\n };\n\n textExpanderRef.current.addEventListener(\n 'text-expander-activate',\n handleActivate,\n );\n\n handleDeactivate = () => {\n hasTextExpanderRef.current = false;\n };\n\n textExpanderRef.current.addEventListener(\n 'text-expander-deactivate',\n handleDeactivate,\n );\n }\n\n return () => {\n if (textExpanderRef.current) {\n textExpanderRef.current.removeEventListener(\n 'text-expander-change',\n handleChange,\n );\n textExpanderRef.current.removeEventListener(\n 'text-expander-value',\n handleValue,\n );\n textExpanderRef.current.removeEventListener(\n 'text-expander-committed',\n handleCommited,\n );\n textExpanderRef.current.removeEventListener(\n 'text-expander-activate',\n handleActivate,\n );\n textExpanderRef.current.removeEventListener(\n 'text-expander-deactivate',\n handleDeactivate,\n );\n }\n };\n }, []);\n\n useEffect(() => {\n // Resize observer for textarea\n const textarea = ref.current;\n if (!textarea) return;\n const resizeObserver = new ResizeObserver(() => {\n // Get height of textarea, set height to textExpander\n if (textExpanderRef.current) {\n const { height } = textarea.getBoundingClientRect();\n textExpanderRef.current.style.height = height + 'px';\n }\n });\n resizeObserver.observe(textarea);\n }, []);\n\n const slowHighlightPerf = useRef(0); // increment if slow\n const composeHighlightRef = useRef();\n const throttleHighlightText = useThrottledCallback((text) => {\n if (!composeHighlightRef.current) return;\n if (slowHighlightPerf.current > 3) {\n // After 3 times of lag, disable highlighting\n composeHighlightRef.current.innerHTML = '';\n composeHighlightRef.current = null; // Destroy the whole thing\n throttleHighlightText?.cancel?.();\n return;\n }\n let start;\n let end;\n if (slowHighlightPerf.current <= 3) start = Date.now();\n composeHighlightRef.current.innerHTML =\n highlightText(text, {\n maxCharacters,\n }) + '\\n';\n if (slowHighlightPerf.current <= 3) end = Date.now();\n console.debug('HIGHLIGHT PERF', { start, end, diff: end - start });\n if (start && end && end - start > 50) {\n // if slow, increment\n slowHighlightPerf.current++;\n }\n // Newline to prevent multiple line breaks at the end from being collapsed, no idea why\n }, 500);\n\n const debouncedAutoDetectLanguage = useDebouncedCallback(() => {\n // Make use of the highlightRef to get the DOM\n // Clone the dom\n const dom = composeHighlightRef.current?.cloneNode(true);\n if (!dom) return;\n // Remove mark\n dom.querySelectorAll('mark').forEach((mark) => {\n mark.remove();\n });\n const text = dom.innerText?.trim();\n if (!text) return;\n (async () => {\n const langs = await detectLangs(text);\n if (langs?.length) {\n onTrigger?.({\n name: 'auto-detect-language',\n languages: langs,\n });\n }\n })();\n }, 2000);\n\n return (\n <text-expander\n ref={textExpanderRef}\n keys=\"@ # :\"\n class=\"compose-field-container\"\n >\n <textarea\n class=\"compose-field\"\n autoCapitalize=\"sentences\"\n autoComplete=\"on\"\n autoCorrect=\"on\"\n spellCheck=\"true\"\n dir=\"auto\"\n rows=\"6\"\n cols=\"50\"\n {...textareaProps}\n ref={ref}\n name=\"status\"\n value={text}\n onKeyDown={(e) => {\n // Get line before cursor position after pressing 'Enter'\n const { key, target } = e;\n const hasTextExpander = hasTextExpanderRef.current;\n if (key === 'Enter' && !(e.ctrlKey || e.metaKey || hasTextExpander)) {\n try {\n const { value, selectionStart } = target;\n const textBeforeCursor = value.slice(0, selectionStart);\n const lastLine = textBeforeCursor.split('\\n').slice(-1)[0];\n if (lastLine) {\n // If line starts with \"- \" or \"12. \"\n if (/^\\s*(-|\\d+\\.)\\s/.test(lastLine)) {\n // insert \"- \" at cursor position\n const [_, preSpaces, bullet, postSpaces, anything] =\n lastLine.match(/^(\\s*)(-|\\d+\\.)(\\s+)(.+)?/) || [];\n if (anything) {\n e.preventDefault();\n const [number] = bullet.match(/\\d+/) || [];\n const newBullet = number ? `${+number + 1}.` : '-';\n const text = `\\n${preSpaces}${newBullet}${postSpaces}`;\n target.setRangeText(text, selectionStart, selectionStart);\n const pos = selectionStart + text.length;\n target.setSelectionRange(pos, pos);\n } else {\n // trim the line before the cursor, then insert new line\n const pos = selectionStart - lastLine.length;\n target.setRangeText('', pos, selectionStart);\n }\n autoResizeTextarea(target);\n target.dispatchEvent(new Event('input'));\n }\n }\n } catch (e) {\n // silent fail\n console.error(e);\n }\n }\n if (composeHighlightRef.current) {\n composeHighlightRef.current.scrollTop = target.scrollTop;\n }\n }}\n onInput={(e) => {\n const { target } = e;\n // Replace zero-width space\n const text = target.value.replace(/\\u200b/g, '');\n setText(text);\n autoResizeTextarea(target);\n props.onInput?.(e);\n throttleHighlightText(text);\n debouncedAutoDetectLanguage();\n }}\n style={{\n width: '100%',\n height: '4em',\n // '--text-weight': (1 + charCount / 140).toFixed(1) || 1,\n }}\n onScroll={(e) => {\n if (composeHighlightRef.current) {\n const { scrollTop } = e.target;\n composeHighlightRef.current.scrollTop = scrollTop;\n }\n }}\n />\n <div\n ref={composeHighlightRef}\n class=\"compose-highlight\"\n aria-hidden=\"true\"\n />\n </text-expander>\n );\n});\n\nfunction CharCountMeter({ maxCharacters = 500, hidden }) {\n const snapStates = useSnapshot(states);\n const charCount = snapStates.composerCharacterCount;\n const leftChars = maxCharacters - charCount;\n if (hidden) {\n return <span class=\"char-counter\" hidden />;\n }\n return (\n <span\n class=\"char-counter\"\n title={`${leftChars}/${maxCharacters}`}\n style={{\n '--percentage': (charCount / maxCharacters) * 100,\n }}\n >\n <meter\n class={`${\n leftChars <= -10\n ? 'explode'\n : leftChars <= 0\n ? 'danger'\n : leftChars <= 20\n ? 'warning'\n : ''\n }`}\n value={charCount}\n max={maxCharacters}\n />\n <span class=\"counter\">{leftChars}</span>\n </span>\n );\n}\n\nfunction scaleDimension(matrix, matrixLimit, width, height) {\n // matrix = number of pixels\n // matrixLimit = max number of pixels\n // Calculate new width and height, downsize to within the limit, preserve aspect ratio, no decimals\n const scalingFactor = Math.sqrt(matrixLimit / matrix);\n const newWidth = Math.floor(width * scalingFactor);\n const newHeight = Math.floor(height * scalingFactor);\n return { newWidth, newHeight };\n}\n\nfunction MediaAttachment({\n attachment,\n disabled,\n lang,\n onDescriptionChange = () => {},\n onRemove = () => {},\n}) {\n const { i18n, t } = useLingui();\n const [uiState, setUIState] = useState('default');\n const supportsEdit = supports('@mastodon/edit-media-attributes');\n const { type, id, file } = attachment;\n const url = useMemo(\n () => (file ? URL.createObjectURL(file) : attachment.url),\n [file, attachment.url],\n );\n console.log({ attachment });\n\n const checkMaxError = !!file?.size;\n const configuration = checkMaxError ? getCurrentInstanceConfiguration() : {};\n const {\n mediaAttachments: {\n imageSizeLimit,\n imageMatrixLimit,\n videoSizeLimit,\n videoMatrixLimit,\n videoFrameRateLimit,\n } = {},\n } = configuration || {};\n\n const [maxError, setMaxError] = useState(() => {\n if (!checkMaxError) return null;\n if (\n type.startsWith('image') &&\n imageSizeLimit &&\n file.size > imageSizeLimit\n ) {\n return {\n type: 'imageSizeLimit',\n details: {\n imageSize: file.size,\n imageSizeLimit,\n },\n };\n } else if (\n type.startsWith('video') &&\n videoSizeLimit &&\n file.size > videoSizeLimit\n ) {\n return {\n type: 'videoSizeLimit',\n details: {\n videoSize: file.size,\n videoSizeLimit,\n },\n };\n }\n return null;\n });\n\n const [imageMatrix, setImageMatrix] = useState({});\n useEffect(() => {\n if (!checkMaxError || !imageMatrixLimit) return;\n if (imageMatrix?.matrix > imageMatrixLimit) {\n setMaxError({\n type: 'imageMatrixLimit',\n details: {\n imageMatrix: imageMatrix?.matrix,\n imageMatrixLimit,\n width: imageMatrix?.width,\n height: imageMatrix?.height,\n },\n });\n }\n }, [imageMatrix, imageMatrixLimit, checkMaxError]);\n\n const [videoMatrix, setVideoMatrix] = useState({});\n useEffect(() => {\n if (!checkMaxError || !videoMatrixLimit) return;\n if (videoMatrix?.matrix > videoMatrixLimit) {\n setMaxError({\n type: 'videoMatrixLimit',\n details: {\n videoMatrix: videoMatrix?.matrix,\n videoMatrixLimit,\n width: videoMatrix?.width,\n height: videoMatrix?.height,\n },\n });\n }\n }, [videoMatrix, videoMatrixLimit, checkMaxError]);\n\n const [description, setDescription] = useState(attachment.description);\n const [suffixType, subtype] = type.split('/');\n const debouncedOnDescriptionChange = useDebouncedCallback(\n onDescriptionChange,\n 250,\n );\n useEffect(() => {\n debouncedOnDescriptionChange(description);\n }, [description, debouncedOnDescriptionChange]);\n\n const [showModal, setShowModal] = useState(false);\n const textareaRef = useRef(null);\n useEffect(() => {\n let timer;\n if (showModal && textareaRef.current) {\n timer = setTimeout(() => {\n textareaRef.current.focus();\n }, 100);\n }\n return () => {\n clearTimeout(timer);\n };\n }, [showModal]);\n\n const descTextarea = (\n <>\n {!!id && !supportsEdit ? (\n <div class=\"media-desc\">\n <span class=\"tag\">\n <Trans>Uploaded</Trans>\n </span>\n <p title={description}>\n {attachment.description || <i>No description</i>}\n </p>\n </div>\n ) : (\n <textarea\n ref={textareaRef}\n value={description || ''}\n lang={lang}\n placeholder={\n {\n image: t`Image description`,\n video: t`Video description`,\n audio: t`Audio description`,\n }[suffixType]\n }\n autoCapitalize=\"sentences\"\n autoComplete=\"on\"\n autoCorrect=\"on\"\n spellCheck=\"true\"\n dir=\"auto\"\n disabled={disabled || uiState === 'loading'}\n class={uiState === 'loading' ? 'loading' : ''}\n maxlength=\"1500\" // Not unicode-aware :(\n // TODO: Un-hard-code this maxlength, ref: https://github.com/mastodon/mastodon/blob/b59fb28e90bc21d6fd1a6bafd13cfbd81ab5be54/app/models/media_attachment.rb#L39\n onInput={(e) => {\n const { value } = e.target;\n setDescription(value);\n // debouncedOnDescriptionChange(value);\n }}\n ></textarea>\n )}\n </>\n );\n\n const toastRef = useRef(null);\n useEffect(() => {\n return () => {\n toastRef.current?.hideToast?.();\n };\n }, []);\n\n const maxErrorToast = useRef(null);\n\n const maxErrorText = (err) => {\n const { type, details } = err;\n switch (type) {\n case 'imageSizeLimit': {\n const { imageSize, imageSizeLimit } = details;\n return t`File size too large. Uploading might encounter issues. Try reduce the file size from ${prettyBytes(\n imageSize,\n )} to ${prettyBytes(imageSizeLimit)} or lower.`;\n }\n case 'imageMatrixLimit': {\n const { imageMatrix, imageMatrixLimit, width, height } = details;\n const { newWidth, newHeight } = scaleDimension(\n imageMatrix,\n imageMatrixLimit,\n width,\n height,\n );\n return t`Dimension too large. Uploading might encounter issues. Try reduce dimension from ${i18n.number(\n width,\n )}×${i18n.number(height)}px to ${i18n.number(newWidth)}×${i18n.number(\n newHeight,\n )}px.`;\n }\n case 'videoSizeLimit': {\n const { videoSize, videoSizeLimit } = details;\n return t`File size too large. Uploading might encounter issues. Try reduce the file size from ${prettyBytes(\n videoSize,\n )} to ${prettyBytes(videoSizeLimit)} or lower.`;\n }\n case 'videoMatrixLimit': {\n const { videoMatrix, videoMatrixLimit, width, height } = details;\n const { newWidth, newHeight } = scaleDimension(\n videoMatrix,\n videoMatrixLimit,\n width,\n height,\n );\n return t`Dimension too large. Uploading might encounter issues. Try reduce dimension from ${i18n.number(\n width,\n )}×${i18n.number(height)}px to ${i18n.number(newWidth)}×${i18n.number(\n newHeight,\n )}px.`;\n }\n case 'videoFrameRateLimit': {\n // Not possible to detect this on client-side for now\n return t`Frame rate too high. Uploading might encounter issues.`;\n }\n }\n };\n\n return (\n <>\n <div class=\"media-attachment\">\n <div\n class=\"media-preview\"\n tabIndex=\"0\"\n onClick={() => {\n setShowModal(true);\n }}\n >\n {suffixType === 'image' ? (\n <img\n src={url}\n alt=\"\"\n onLoad={(e) => {\n if (!checkMaxError) return;\n const { naturalWidth, naturalHeight } = e.target;\n setImageMatrix({\n matrix: naturalWidth * naturalHeight,\n width: naturalWidth,\n height: naturalHeight,\n });\n }}\n />\n ) : suffixType === 'video' || suffixType === 'gifv' ? (\n <video\n src={url + '#t=0.1'} // Make Safari show 1st-frame preview\n playsinline\n muted\n disablePictureInPicture\n preload=\"metadata\"\n onLoadedMetadata={(e) => {\n if (!checkMaxError) return;\n const { videoWidth, videoHeight } = e.target;\n if (videoWidth && videoHeight) {\n setVideoMatrix({\n matrix: videoWidth * videoHeight,\n width: videoWidth,\n height: videoHeight,\n });\n }\n }}\n />\n ) : suffixType === 'audio' ? (\n <audio src={url} controls />\n ) : null}\n </div>\n {descTextarea}\n <div class=\"media-aside\">\n <button\n type=\"button\"\n class=\"plain close-button\"\n disabled={disabled}\n onClick={onRemove}\n >\n <Icon icon=\"x\" alt={t`Remove`} />\n </button>\n {!!maxError && (\n <button\n type=\"button\"\n class=\"media-error\"\n title={maxErrorText(maxError)}\n onClick={() => {\n if (maxErrorToast.current) {\n maxErrorToast.current.hideToast();\n }\n maxErrorToast.current = showToast({\n text: maxErrorText(maxError),\n duration: 10_000,\n });\n }}\n >\n <Icon icon=\"alert\" alt={t`Error`} />\n </button>\n )}\n </div>\n </div>\n {showModal && (\n <Modal\n onClose={() => {\n setShowModal(false);\n }}\n >\n <div id=\"media-sheet\" class=\"sheet sheet-max\">\n <button\n type=\"button\"\n class=\"sheet-close\"\n onClick={() => {\n setShowModal(false);\n }}\n >\n <Icon icon=\"x\" alt={t`Close`} />\n </button>\n <header>\n <h2>\n {\n {\n image: t`Edit image description`,\n video: t`Edit video description`,\n audio: t`Edit audio description`,\n }[suffixType]\n }\n </h2>\n </header>\n <main tabIndex=\"-1\">\n <div class=\"media-preview\">\n {suffixType === 'image' ? (\n <img src={url} alt=\"\" />\n ) : suffixType === 'video' || suffixType === 'gifv' ? (\n <video src={url} playsinline controls />\n ) : suffixType === 'audio' ? (\n <audio src={url} controls />\n ) : null}\n </div>\n <div class=\"media-form\">\n {descTextarea}\n <footer>\n {suffixType === 'image' &&\n /^(png|jpe?g|gif|webp)$/i.test(subtype) &&\n !!states.settings.mediaAltGenerator &&\n !!IMG_ALT_API_URL && (\n <Menu2\n portal={{\n target: document.body,\n }}\n containerProps={{\n style: {\n zIndex: 1001,\n },\n }}\n align=\"center\"\n position=\"anchor\"\n overflow=\"auto\"\n menuButton={\n <button type=\"button\" class=\"plain\">\n <Icon icon=\"more\" size=\"l\" alt={t`More`} />\n </button>\n }\n >\n <MenuItem\n disabled={uiState === 'loading'}\n onClick={() => {\n setUIState('loading');\n toastRef.current = showToast({\n text: t`Generating description. Please wait…`,\n duration: -1,\n });\n // POST with multipart\n (async function () {\n try {\n const body = new FormData();\n body.append('image', file);\n const response = await fetch(IMG_ALT_API_URL, {\n method: 'POST',\n body,\n }).then((r) => r.json());\n if (response.error) {\n throw new Error(response.error);\n }\n setDescription(response.description);\n } catch (e) {\n console.error(e);\n showToast(\n e.message\n ? t`Failed to generate description: ${e.message}`\n : t`Failed to generate description`,\n );\n } finally {\n setUIState('default');\n toastRef.current?.hideToast?.();\n }\n })();\n }}\n >\n <Icon icon=\"sparkles2\" />\n {lang && lang !== 'en' ? (\n <small>\n <Trans>Generate description…</Trans>\n <br />\n (English)\n </small>\n ) : (\n <span>\n <Trans>Generate description…</Trans>\n </span>\n )}\n </MenuItem>\n {!!lang && lang !== 'en' && (\n <MenuItem\n disabled={uiState === 'loading'}\n onClick={() => {\n setUIState('loading');\n toastRef.current = showToast({\n text: t`Generating description. Please wait…`,\n duration: -1,\n });\n // POST with multipart\n (async function () {\n try {\n const body = new FormData();\n body.append('image', file);\n const params = `?lang=${lang}`;\n const response = await fetch(\n IMG_ALT_API_URL + params,\n {\n method: 'POST',\n body,\n },\n ).then((r) => r.json());\n if (response.error) {\n throw new Error(response.error);\n }\n setDescription(response.description);\n } catch (e) {\n console.error(e);\n showToast(\n t`Failed to generate description${\n e?.message ? `: ${e.message}` : ''\n }`,\n );\n } finally {\n setUIState('default');\n toastRef.current?.hideToast?.();\n }\n })();\n }}\n >\n <Icon icon=\"sparkles2\" />\n <small>\n <Trans>Generate description…</Trans>\n <br />\n <Trans>\n ({localeCode2Text(lang)}){' '}\n <span class=\"more-insignificant\">\n — experimental\n </span>\n </Trans>\n </small>\n </MenuItem>\n )}\n </Menu2>\n )}\n <button\n type=\"button\"\n class=\"light block\"\n onClick={() => {\n setShowModal(false);\n }}\n disabled={uiState === 'loading'}\n >\n <Trans>Done</Trans>\n </button>\n </footer>\n </div>\n </main>\n </div>\n </Modal>\n )}\n </>\n );\n}\n\nfunction Poll({\n lang,\n poll,\n disabled,\n onInput = () => {},\n maxOptions,\n maxExpiration,\n minExpiration,\n maxCharactersPerOption,\n}) {\n const { t } = useLingui();\n const { options, expiresIn, multiple } = poll;\n\n return (\n <div class={`poll ${multiple ? 'multiple' : ''}`}>\n <div class=\"poll-choices\">\n {options.map((option, i) => (\n <div class=\"poll-choice\" key={i}>\n <input\n required\n type=\"text\"\n value={option}\n disabled={disabled}\n maxlength={maxCharactersPerOption}\n placeholder={t`Choice ${i + 1}`}\n lang={lang}\n spellCheck=\"true\"\n dir=\"auto\"\n onInput={(e) => {\n const { value } = e.target;\n options[i] = value;\n onInput(poll);\n }}\n />\n <button\n type=\"button\"\n class=\"plain2 poll-button\"\n disabled={disabled || options.length <= 1}\n onClick={() => {\n options.splice(i, 1);\n onInput(poll);\n }}\n >\n <Icon icon=\"x\" size=\"s\" alt={t`Remove`} />\n </button>\n </div>\n ))}\n </div>\n <div class=\"poll-toolbar\">\n <button\n type=\"button\"\n class=\"plain2 poll-button\"\n disabled={disabled || options.length >= maxOptions}\n onClick={() => {\n options.push('');\n onInput(poll);\n }}\n >\n +\n </button>{' '}\n <label class=\"multiple-choices\">\n <input\n type=\"checkbox\"\n checked={multiple}\n disabled={disabled}\n onChange={(e) => {\n const { checked } = e.target;\n poll.multiple = checked;\n onInput(poll);\n }}\n />{' '}\n <Trans>Multiple choices</Trans>\n </label>\n <label class=\"expires-in\">\n <Trans>Duration</Trans>{' '}\n <select\n value={expiresIn}\n disabled={disabled}\n onChange={(e) => {\n const { value } = e.target;\n poll.expiresIn = value;\n onInput(poll);\n }}\n >\n {Object.entries(expiryOptions)\n .filter(([value]) => {\n return value >= minExpiration && value <= maxExpiration;\n })\n .map(([value, label]) => (\n <option value={value} key={value}>\n {label()}\n </option>\n ))}\n </select>\n </label>\n </div>\n <div class=\"poll-toolbar\">\n <button\n type=\"button\"\n class=\"plain remove-poll-button\"\n disabled={disabled}\n onClick={() => {\n onInput(null);\n }}\n >\n <Trans>Remove poll</Trans>\n </button>\n </div>\n </div>\n );\n}\n\nfunction filterShortcodes(emojis, searchTerm) {\n searchTerm = searchTerm.toLowerCase();\n\n // Return an array of shortcodes that start with or contain the search term, sorted by relevance and limited to the first 5\n return emojis\n .sort((a, b) => {\n let aLower = a.shortcode.toLowerCase();\n let bLower = b.shortcode.toLowerCase();\n\n let aStartsWith = aLower.startsWith(searchTerm);\n let bStartsWith = bLower.startsWith(searchTerm);\n let aContains = aLower.includes(searchTerm);\n let bContains = bLower.includes(searchTerm);\n let bothStartWith = aStartsWith && bStartsWith;\n let bothContain = aContains && bContains;\n\n return bothStartWith\n ? a.length - b.length\n : aStartsWith\n ? -1\n : bStartsWith\n ? 1\n : bothContain\n ? a.length - b.length\n : aContains\n ? -1\n : bContains\n ? 1\n : 0;\n })\n .slice(0, 5);\n}\n\nfunction encodeHTML(str) {\n return str.replace(/[&<>\"']/g, function (char) {\n return '&#' + char.charCodeAt(0) + ';';\n });\n}\n\nfunction removeNullUndefined(obj) {\n for (let key in obj) {\n if (obj[key] === null || obj[key] === undefined) {\n delete obj[key];\n }\n }\n return obj;\n}\n\nfunction MentionModal({\n onClose = () => {},\n onSelect = () => {},\n defaultSearchTerm,\n}) {\n const { t } = useLingui();\n const { masto } = api();\n const [uiState, setUIState] = useState('default');\n const [accounts, setAccounts] = useState([]);\n const [relationshipsMap, setRelationshipsMap] = useState({});\n\n const [selectedIndex, setSelectedIndex] = useState(0);\n\n const loadRelationships = async (accounts) => {\n if (!accounts?.length) return;\n const relationships = await fetchRelationships(accounts, relationshipsMap);\n if (relationships) {\n setRelationshipsMap({\n ...relationshipsMap,\n ...relationships,\n });\n }\n };\n\n const loadAccounts = (term) => {\n if (!term) return;\n setUIState('loading');\n (async () => {\n try {\n const accounts = await masto.v1.accounts.search.list({\n q: term,\n limit: 40,\n resolve: false,\n });\n setAccounts(accounts);\n loadRelationships(accounts);\n setUIState('default');\n } catch (e) {\n setUIState('error');\n console.error(e);\n }\n })();\n };\n\n const debouncedLoadAccounts = useDebouncedCallback(loadAccounts, 1000);\n\n useEffect(() => {\n loadAccounts();\n }, [loadAccounts]);\n\n const inputRef = useRef();\n useEffect(() => {\n if (inputRef.current) {\n inputRef.current.focus();\n // Put cursor at the end\n if (inputRef.current.value) {\n inputRef.current.selectionStart = inputRef.current.value.length;\n inputRef.current.selectionEnd = inputRef.current.value.length;\n }\n }\n }, []);\n\n useEffect(() => {\n if (defaultSearchTerm) {\n loadAccounts(defaultSearchTerm);\n }\n }, [defaultSearchTerm]);\n\n const selectAccount = (account) => {\n const socialAddress = account.acct;\n onSelect(socialAddress);\n onClose();\n };\n\n useHotkeys(\n 'enter',\n () => {\n const selectedAccount = accounts[selectedIndex];\n if (selectedAccount) {\n selectAccount(selectedAccount);\n }\n },\n {\n preventDefault: true,\n enableOnFormTags: ['input'],\n },\n );\n\n const listRef = useRef();\n useHotkeys(\n 'down',\n () => {\n if (selectedIndex < accounts.length - 1) {\n setSelectedIndex(selectedIndex + 1);\n } else {\n setSelectedIndex(0);\n }\n setTimeout(() => {\n const selectedItem = listRef.current.querySelector('.selected');\n if (selectedItem) {\n selectedItem.scrollIntoView({\n behavior: 'smooth',\n block: 'center',\n inline: 'center',\n });\n }\n }, 1);\n },\n {\n preventDefault: true,\n enableOnFormTags: ['input'],\n },\n );\n\n useHotkeys(\n 'up',\n () => {\n if (selectedIndex > 0) {\n setSelectedIndex(selectedIndex - 1);\n } else {\n setSelectedIndex(accounts.length - 1);\n }\n setTimeout(() => {\n const selectedItem = listRef.current.querySelector('.selected');\n if (selectedItem) {\n selectedItem.scrollIntoView({\n behavior: 'smooth',\n block: 'center',\n inline: 'center',\n });\n }\n }, 1);\n },\n {\n preventDefault: true,\n enableOnFormTags: ['input'],\n },\n );\n\n return (\n <div id=\"mention-sheet\" class=\"sheet\">\n {!!onClose && (\n <button type=\"button\" class=\"sheet-close\" onClick={onClose}>\n <Icon icon=\"x\" alt={t`Close`} />\n </button>\n )}\n <header>\n <form\n onSubmit={(e) => {\n e.preventDefault();\n debouncedLoadAccounts.flush?.();\n // const searchTerm = inputRef.current.value;\n // debouncedLoadAccounts(searchTerm);\n }}\n >\n <input\n ref={inputRef}\n required\n type=\"search\"\n class=\"block\"\n placeholder={t`Search accounts`}\n onInput={(e) => {\n const { value } = e.target;\n debouncedLoadAccounts(value);\n }}\n autocomplete=\"off\"\n autocorrect=\"off\"\n autocapitalize=\"off\"\n spellCheck=\"false\"\n dir=\"auto\"\n defaultValue={defaultSearchTerm || ''}\n />\n </form>\n </header>\n <main>\n {accounts?.length > 0 ? (\n <ul\n ref={listRef}\n class={`accounts-list ${uiState === 'loading' ? 'loading' : ''}`}\n >\n {accounts.map((account, i) => {\n const relationship = relationshipsMap[account.id];\n return (\n <li\n key={account.id}\n class={i === selectedIndex ? 'selected' : ''}\n >\n <AccountBlock\n avatarSize=\"xxl\"\n account={account}\n relationship={relationship}\n showStats\n showActivity\n />\n <button\n type=\"button\"\n class=\"plain2\"\n onClick={() => {\n selectAccount(account);\n }}\n >\n <Icon icon=\"plus\" size=\"xl\" alt={t`Add`} />\n </button>\n </li>\n );\n })}\n </ul>\n ) : uiState === 'loading' ? (\n <div class=\"ui-state\">\n <Loader abrupt />\n </div>\n ) : uiState === 'error' ? (\n <div class=\"ui-state\">\n <p>\n <Trans>Error loading accounts</Trans>\n </p>\n </div>\n ) : null}\n </main>\n </div>\n );\n}\n\nfunction CustomEmojisModal({\n masto,\n instance,\n onClose = () => {},\n onSelect = () => {},\n defaultSearchTerm,\n}) {\n const { t } = useLingui();\n const [uiState, setUIState] = useState('default');\n const customEmojisList = useRef([]);\n const [customEmojis, setCustomEmojis] = useState([]);\n const recentlyUsedCustomEmojis = useMemo(\n () => store.account.get('recentlyUsedCustomEmojis') || [],\n );\n const searcherRef = useRef();\n useEffect(() => {\n setUIState('loading');\n (async () => {\n try {\n const [emojis, searcher] = await getCustomEmojis(instance, masto);\n console.log('emojis', emojis);\n searcherRef.current = searcher;\n setCustomEmojis(emojis);\n setUIState('default');\n } catch (e) {\n setUIState('error');\n console.error(e);\n }\n })();\n }, []);\n\n const customEmojisCatList = useMemo(() => {\n // Group emojis by category\n const emojisCat = {\n '--recent--': recentlyUsedCustomEmojis.filter((emoji) =>\n customEmojis.find((e) => e.shortcode === emoji.shortcode),\n ),\n };\n const othersCat = [];\n customEmojis.forEach((emoji) => {\n customEmojisList.current?.push?.(emoji);\n if (!emoji.category) {\n othersCat.push(emoji);\n return;\n }\n if (!emojisCat[emoji.category]) {\n emojisCat[emoji.category] = [];\n }\n emojisCat[emoji.category].push(emoji);\n });\n if (othersCat.length) {\n emojisCat['--others--'] = othersCat;\n }\n return emojisCat;\n }, [customEmojis]);\n\n const scrollableRef = useRef();\n const [matches, setMatches] = useState(null);\n const onFind = useCallback(\n (e) => {\n const { value } = e.target;\n if (value) {\n const results = searcherRef.current?.search(value, {\n limit: CUSTOM_EMOJIS_COUNT,\n });\n setMatches(results.map((r) => r.item));\n scrollableRef.current?.scrollTo?.(0, 0);\n } else {\n setMatches(null);\n }\n },\n [customEmojis],\n );\n useEffect(() => {\n if (defaultSearchTerm && customEmojis?.length) {\n onFind({ target: { value: defaultSearchTerm } });\n }\n }, [defaultSearchTerm, onFind, customEmojis]);\n\n const onSelectEmoji = useCallback(\n (emoji) => {\n onSelect?.(emoji);\n onClose?.();\n\n queueMicrotask(() => {\n let recentlyUsedCustomEmojis =\n store.account.get('recentlyUsedCustomEmojis') || [];\n const recentlyUsedEmojiIndex = recentlyUsedCustomEmojis.findIndex(\n (e) => e.shortcode === emoji.shortcode,\n );\n if (recentlyUsedEmojiIndex !== -1) {\n // Move emoji to index 0\n recentlyUsedCustomEmojis.splice(recentlyUsedEmojiIndex, 1);\n recentlyUsedCustomEmojis.unshift(emoji);\n } else {\n recentlyUsedCustomEmojis.unshift(emoji);\n // Remove unavailable ones\n recentlyUsedCustomEmojis = recentlyUsedCustomEmojis.filter((e) =>\n customEmojisList.current?.find?.(\n (emoji) => emoji.shortcode === e.shortcode,\n ),\n );\n // Limit to 10\n recentlyUsedCustomEmojis = recentlyUsedCustomEmojis.slice(0, 10);\n }\n\n // Store back\n store.account.set('recentlyUsedCustomEmojis', recentlyUsedCustomEmojis);\n });\n },\n [onSelect],\n );\n\n const inputRef = useRef();\n useEffect(() => {\n if (inputRef.current) {\n inputRef.current.focus();\n // Put cursor at the end\n if (inputRef.current.value) {\n inputRef.current.selectionStart = inputRef.current.value.length;\n inputRef.current.selectionEnd = inputRef.current.value.length;\n }\n }\n }, []);\n\n return (\n <div id=\"custom-emojis-sheet\" class=\"sheet\">\n {!!onClose && (\n <button type=\"button\" class=\"sheet-close\" onClick={onClose}>\n <Icon icon=\"x\" alt={t`Close`} />\n </button>\n )}\n <header>\n <div>\n <b>\n <Trans>Custom emojis</Trans>\n </b>{' '}\n {uiState === 'loading' ? (\n <Loader />\n ) : (\n <small class=\"insignificant\"> • {instance}</small>\n )}\n </div>\n <form\n onSubmit={(e) => {\n e.preventDefault();\n const emoji = matches[0];\n if (emoji) {\n onSelectEmoji(`:${emoji.shortcode}:`);\n }\n }}\n >\n <input\n ref={inputRef}\n type=\"search\"\n placeholder={t`Search emoji`}\n onInput={onFind}\n autocomplete=\"off\"\n autocorrect=\"off\"\n autocapitalize=\"off\"\n spellCheck=\"false\"\n dir=\"auto\"\n defaultValue={defaultSearchTerm || ''}\n />\n </form>\n </header>\n <main ref={scrollableRef}>\n {matches !== null ? (\n <ul class=\"custom-emojis-matches custom-emojis-list\">\n {matches.map((emoji) => (\n <li key={emoji.shortcode} class=\"custom-emojis-match\">\n <CustomEmojiButton\n emoji={emoji}\n onClick={() => {\n onSelectEmoji(`:${emoji.shortcode}:`);\n }}\n showCode\n />\n </li>\n ))}\n </ul>\n ) : (\n <div class=\"custom-emojis-list\">\n {uiState === 'error' && (\n <div class=\"ui-state\">\n <p>\n <Trans>Error loading custom emojis</Trans>\n </p>\n </div>\n )}\n {uiState === 'default' &&\n Object.entries(customEmojisCatList).map(\n ([category, emojis]) =>\n !!emojis?.length && (\n <div class=\"section-container\">\n <div class=\"section-header\">\n {{\n '--recent--': t`Recently used`,\n '--others--': t`Others`,\n }[category] || category}\n </div>\n <CustomEmojisList\n emojis={emojis}\n onSelect={onSelectEmoji}\n />\n </div>\n ),\n )}\n </div>\n )}\n </main>\n </div>\n );\n}\n\nconst CustomEmojisList = memo(({ emojis, onSelect }) => {\n const { i18n } = useLingui();\n const [max, setMax] = useState(CUSTOM_EMOJIS_COUNT);\n const showMore = emojis.length > max;\n return (\n <section>\n {emojis.slice(0, max).map((emoji) => (\n <CustomEmojiButton\n key={emoji.shortcode}\n emoji={emoji}\n onClick={() => {\n onSelect(`:${emoji.shortcode}:`);\n }}\n />\n ))}\n {showMore && (\n <button\n type=\"button\"\n class=\"plain small\"\n onClick={() => setMax(max + CUSTOM_EMOJIS_COUNT)}\n >\n <Trans>{i18n.number(emojis.length - max)} more…</Trans>\n </button>\n )}\n </section>\n );\n});\n\nconst CustomEmojiButton = memo(({ emoji, onClick, showCode }) => {\n const addEdges = (e) => {\n // Add edge-left or edge-right class based on self position relative to scrollable parent\n // If near left edge, add edge-left, if near right edge, add edge-right\n const buffer = 88;\n const parent = e.currentTarget.closest('main');\n if (parent) {\n const rect = parent.getBoundingClientRect();\n const selfRect = e.currentTarget.getBoundingClientRect();\n const targetClassList = e.currentTarget.classList;\n if (selfRect.left < rect.left + buffer) {\n targetClassList.add('edge-left');\n targetClassList.remove('edge-right');\n } else if (selfRect.right > rect.right - buffer) {\n targetClassList.add('edge-right');\n targetClassList.remove('edge-left');\n } else {\n targetClassList.remove('edge-left', 'edge-right');\n }\n }\n };\n\n return (\n <button\n type=\"button\"\n className=\"plain4\"\n onClick={onClick}\n data-title={showCode ? undefined : emoji.shortcode}\n onPointerEnter={addEdges}\n onFocus={addEdges}\n >\n <picture>\n {!!emoji.staticUrl && (\n <source\n srcSet={emoji.staticUrl}\n media=\"(prefers-reduced-motion: reduce)\"\n />\n )}\n <img\n className=\"shortcode-emoji\"\n src={emoji.url || emoji.staticUrl}\n alt={emoji.shortcode}\n width=\"24\"\n height=\"24\"\n loading=\"lazy\"\n decoding=\"async\"\n />\n </picture>\n {showCode && (\n <>\n {' '}\n <code>{emoji.shortcode}</code>\n </>\n )}\n </button>\n );\n});\n\nconst GIFS_PER_PAGE = 20;\nfunction GIFPickerModal({ onClose = () => {}, onSelect = () => {} }) {\n const { i18n, t } = useLingui();\n const [uiState, setUIState] = useState('default');\n const [results, setResults] = useState([]);\n const formRef = useRef(null);\n const qRef = useRef(null);\n const currentOffset = useRef(0);\n const scrollableRef = useRef(null);\n\n function fetchGIFs({ offset }) {\n console.log('fetchGIFs', { offset });\n if (!qRef.current?.value) return;\n setUIState('loading');\n scrollableRef.current?.scrollTo?.({\n top: 0,\n left: 0,\n behavior: 'smooth',\n });\n (async () => {\n try {\n const query = {\n api_key: GIPHY_API_KEY,\n q: qRef.current.value,\n rating: 'g',\n limit: GIFS_PER_PAGE,\n bundle: 'messaging_non_clips',\n offset,\n lang: i18n.locale || 'en',\n };\n const response = await fetch(\n 'https://api.giphy.com/v1/gifs/search?' + new URLSearchParams(query),\n {\n referrerPolicy: 'no-referrer',\n },\n ).then((r) => r.json());\n currentOffset.current = response.pagination?.offset || 0;\n setResults(response);\n setUIState('results');\n } catch (e) {\n setUIState('error');\n console.error(e);\n }\n })();\n }\n\n useEffect(() => {\n qRef.current?.focus();\n }, []);\n\n const debouncedOnInput = useDebouncedCallback(() => {\n fetchGIFs({ offset: 0 });\n }, 1000);\n\n return (\n <div id=\"gif-picker-sheet\" class=\"sheet\">\n {!!onClose && (\n <button type=\"button\" class=\"sheet-close\" onClick={onClose}>\n <Icon icon=\"x\" alt={t`Close`} />\n </button>\n )}\n <header>\n <form\n ref={formRef}\n onSubmit={(e) => {\n e.preventDefault();\n fetchGIFs({ offset: 0 });\n }}\n >\n <input\n ref={qRef}\n type=\"search\"\n name=\"q\"\n placeholder={t`Search GIFs`}\n required\n autocomplete=\"off\"\n autocorrect=\"off\"\n autocapitalize=\"off\"\n spellCheck=\"false\"\n dir=\"auto\"\n onInput={debouncedOnInput}\n />\n <input\n type=\"image\"\n class=\"powered-button\"\n src={poweredByGiphyURL}\n width=\"86\"\n height=\"30\"\n alt={t`Powered by GIPHY`}\n />\n </form>\n </header>\n <main ref={scrollableRef} class={uiState === 'loading' ? 'loading' : ''}>\n {uiState === 'default' && (\n <div class=\"ui-state\">\n <p class=\"insignificant\">\n <Trans>Type to search GIFs</Trans>\n </p>\n </div>\n )}\n {uiState === 'loading' && !results?.data?.length && (\n <div class=\"ui-state\">\n <Loader abrupt />\n </div>\n )}\n {results?.data?.length > 0 ? (\n <>\n <ul>\n {results.data.map((gif) => {\n const { id, images, title, alt_text } = gif;\n const {\n fixed_height_small,\n fixed_height_downsampled,\n fixed_height,\n original,\n } = images;\n const theImage = fixed_height_small?.url\n ? fixed_height_small\n : fixed_height_downsampled?.url\n ? fixed_height_downsampled\n : fixed_height;\n let { url, webp, width, height } = theImage;\n if (+height > 100) {\n width = (width / height) * 100;\n height = 100;\n }\n const urlObj = URL.parse(url);\n const strippedURL = urlObj.origin + urlObj.pathname;\n let strippedWebP;\n if (webp) {\n const webpObj = URL.parse(webp);\n strippedWebP = webpObj.origin + webpObj.pathname;\n }\n return (\n <li key={id}>\n <button\n type=\"button\"\n onClick={() => {\n const { mp4, url } = original;\n const theURL = mp4 || url;\n const urlObj = URL.parse(theURL);\n const strippedURL = urlObj.origin + urlObj.pathname;\n onClose();\n onSelect({\n url: strippedURL,\n type: mp4 ? 'video/mp4' : 'image/gif',\n alt_text: alt_text || title,\n });\n }}\n >\n <figure\n style={{\n '--figure-width': width + 'px',\n // width: width + 'px'\n }}\n >\n <picture>\n {strippedWebP && (\n <source srcset={strippedWebP} type=\"image/webp\" />\n )}\n <img\n src={strippedURL}\n width={width}\n height={height}\n loading=\"lazy\"\n decoding=\"async\"\n alt={alt_text}\n referrerpolicy=\"no-referrer\"\n onLoad={(e) => {\n e.target.style.backgroundColor = 'transparent';\n }}\n />\n </picture>\n <figcaption>{alt_text || title}</figcaption>\n </figure>\n </button>\n </li>\n );\n })}\n </ul>\n <p class=\"pagination\">\n {results.pagination?.offset > 0 && (\n <button\n type=\"button\"\n class=\"light small\"\n disabled={uiState === 'loading'}\n onClick={() => {\n fetchGIFs({\n offset: results.pagination?.offset - GIFS_PER_PAGE,\n });\n }}\n >\n <Icon icon=\"chevron-left\" />\n <span>\n <Trans>Previous</Trans>\n </span>\n </button>\n )}\n <span />\n {results.pagination?.offset + results.pagination?.count <\n results.pagination?.total_count && (\n <button\n type=\"button\"\n class=\"light small\"\n disabled={uiState === 'loading'}\n onClick={() => {\n fetchGIFs({\n offset: results.pagination?.offset + GIFS_PER_PAGE,\n });\n }}\n >\n <span>\n <Trans>Next</Trans>\n </span>{' '}\n <Icon icon=\"chevron-right\" />\n </button>\n )}\n </p>\n </>\n ) : (\n uiState === 'results' && (\n <div class=\"ui-state\">\n <p>No results</p>\n </div>\n )\n )}\n {uiState === 'error' && (\n <div class=\"ui-state\">\n <p>\n <Trans>Error loading GIFs</Trans>\n </p>\n </div>\n )}\n </main>\n </div>\n );\n}\n\nexport default Compose;\n"],"file":"assets/compose-DzFQRJS6.js"} |