@fieldia/viewer 0.19.1 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/bundle/fieldia.ar.js +2 -2
- package/bundle/fieldia.ar.js.map +2 -2
- package/bundle/fieldia.choice.js +5 -0
- package/bundle/fieldia.choice.js.map +7 -0
- package/bundle/fieldia.de.js +2 -2
- package/bundle/fieldia.de.js.map +2 -2
- package/bundle/fieldia.filters.js +5 -0
- package/bundle/fieldia.filters.js.map +7 -0
- package/bundle/fieldia.fr.js +2 -2
- package/bundle/fieldia.fr.js.map +2 -2
- package/bundle/fieldia.head.js +5 -0
- package/bundle/fieldia.head.js.map +7 -0
- package/bundle/fieldia.js +44 -44
- package/bundle/fieldia.js.map +4 -4
- package/bundle/fieldia.path.js +5 -0
- package/bundle/fieldia.path.js.map +7 -0
- package/bundle/fieldia.text.js +24 -0
- package/bundle/fieldia.text.js.map +7 -0
- package/package.json +7 -3
- package/src/index.d.mts +2 -1
- package/src/index.d.ts +2 -1
- package/src/index.js +6 -1
- package/src/index.js.map +1 -1
- package/src/index.mjs +1 -0
- package/src/index.mjs.map +1 -1
- package/src/lib/button-parts.d.mts +30 -0
- package/src/lib/button-parts.d.ts +30 -0
- package/src/lib/button-parts.js +24 -0
- package/src/lib/button-parts.js.map +1 -0
- package/src/lib/button-parts.mjs +18 -0
- package/src/lib/button-parts.mjs.map +1 -0
- package/src/lib/dialog-window.d.mts +11 -0
- package/src/lib/dialog-window.d.ts +11 -0
- package/src/lib/dialog-window.js +86 -0
- package/src/lib/dialog-window.js.map +1 -0
- package/src/lib/dialog-window.mjs +82 -0
- package/src/lib/dialog-window.mjs.map +1 -0
- package/src/lib/dialog.d.mts +14 -3
- package/src/lib/dialog.d.ts +14 -3
- package/src/lib/dialog.js +84 -14
- package/src/lib/dialog.js.map +1 -1
- package/src/lib/dialog.mjs +85 -15
- package/src/lib/dialog.mjs.map +1 -1
- package/src/lib/filter-bar.d.mts +39 -0
- package/src/lib/filter-bar.d.ts +39 -0
- package/src/lib/filter-bar.js +290 -0
- package/src/lib/filter-bar.js.map +1 -0
- package/src/lib/filter-bar.mjs +287 -0
- package/src/lib/filter-bar.mjs.map +1 -0
- package/src/lib/filter-styles.d.mts +4 -0
- package/src/lib/filter-styles.d.ts +4 -0
- package/src/lib/filter-styles.js +63 -0
- package/src/lib/filter-styles.js.map +1 -0
- package/src/lib/filter-styles.mjs +59 -0
- package/src/lib/filter-styles.mjs.map +1 -0
- package/src/lib/filters-part.d.mts +8 -0
- package/src/lib/filters-part.d.ts +8 -0
- package/src/lib/filters-part.js +14 -0
- package/src/lib/filters-part.js.map +1 -0
- package/src/lib/filters-part.mjs +9 -0
- package/src/lib/filters-part.mjs.map +1 -0
- package/src/lib/group-styles.d.mts +9 -0
- package/src/lib/group-styles.d.ts +9 -0
- package/src/lib/group-styles.js +64 -0
- package/src/lib/group-styles.js.map +1 -0
- package/src/lib/group-styles.mjs +60 -0
- package/src/lib/group-styles.mjs.map +1 -0
- package/src/lib/head-part.d.mts +15 -0
- package/src/lib/head-part.d.ts +15 -0
- package/src/lib/head-part.js +26 -0
- package/src/lib/head-part.js.map +1 -0
- package/src/lib/head-part.mjs +16 -0
- package/src/lib/head-part.mjs.map +1 -0
- package/src/lib/head-styles.d.mts +28 -0
- package/src/lib/head-styles.d.ts +28 -0
- package/src/lib/head-styles.js +320 -0
- package/src/lib/head-styles.js.map +1 -0
- package/src/lib/head-styles.mjs +316 -0
- package/src/lib/head-styles.mjs.map +1 -0
- package/src/lib/labels.d.mts +29 -0
- package/src/lib/labels.d.ts +29 -0
- package/src/lib/labels.js +16 -0
- package/src/lib/labels.js.map +1 -1
- package/src/lib/labels.mjs +16 -0
- package/src/lib/labels.mjs.map +1 -1
- package/src/lib/list-styles.d.mts +1 -1
- package/src/lib/list-styles.d.ts +1 -1
- package/src/lib/list-styles.js +88 -1
- package/src/lib/list-styles.js.map +1 -1
- package/src/lib/list-styles.mjs +88 -1
- package/src/lib/list-styles.mjs.map +1 -1
- package/src/lib/list.d.mts +16 -1
- package/src/lib/list.d.ts +16 -1
- package/src/lib/list.js +281 -51
- package/src/lib/list.js.map +1 -1
- package/src/lib/list.mjs +282 -52
- package/src/lib/list.mjs.map +1 -1
- package/src/lib/locales/ar.js +16 -0
- package/src/lib/locales/ar.js.map +1 -1
- package/src/lib/locales/ar.mjs +16 -0
- package/src/lib/locales/ar.mjs.map +1 -1
- package/src/lib/locales/de.js +16 -0
- package/src/lib/locales/de.js.map +1 -1
- package/src/lib/locales/de.mjs +16 -0
- package/src/lib/locales/de.mjs.map +1 -1
- package/src/lib/locales/fr.js +16 -0
- package/src/lib/locales/fr.js.map +1 -1
- package/src/lib/locales/fr.mjs +16 -0
- package/src/lib/locales/fr.mjs.map +1 -1
- package/src/lib/look.d.mts +1 -1
- package/src/lib/look.d.ts +1 -1
- package/src/lib/look.js +3 -0
- package/src/lib/look.js.map +1 -1
- package/src/lib/look.mjs +3 -0
- package/src/lib/look.mjs.map +1 -1
- package/src/lib/record-bar.d.mts +10 -1
- package/src/lib/record-bar.d.ts +10 -1
- package/src/lib/record-bar.js +15 -7
- package/src/lib/record-bar.js.map +1 -1
- package/src/lib/record-bar.mjs +14 -7
- package/src/lib/record-bar.mjs.map +1 -1
- package/src/lib/record-head.d.mts +58 -0
- package/src/lib/record-head.d.ts +58 -0
- package/src/lib/record-head.js +245 -0
- package/src/lib/record-head.js.map +1 -0
- package/src/lib/record-head.mjs +240 -0
- package/src/lib/record-head.mjs.map +1 -0
- package/src/lib/rich-button.d.mts +12 -0
- package/src/lib/rich-button.d.ts +12 -0
- package/src/lib/rich-button.js +186 -0
- package/src/lib/rich-button.js.map +1 -0
- package/src/lib/rich-button.mjs +183 -0
- package/src/lib/rich-button.mjs.map +1 -0
- package/src/lib/section-head.d.mts +26 -0
- package/src/lib/section-head.d.ts +26 -0
- package/src/lib/section-head.js +65 -0
- package/src/lib/section-head.js.map +1 -0
- package/src/lib/section-head.mjs +56 -0
- package/src/lib/section-head.mjs.map +1 -0
- package/src/lib/section-tools.d.mts +12 -0
- package/src/lib/section-tools.d.ts +12 -0
- package/src/lib/section-tools.js +124 -0
- package/src/lib/section-tools.js.map +1 -0
- package/src/lib/section-tools.mjs +121 -0
- package/src/lib/section-tools.mjs.map +1 -0
- package/src/lib/viewer-parts.d.mts +33 -0
- package/src/lib/viewer-parts.d.ts +33 -0
- package/src/lib/viewer-parts.js +75 -0
- package/src/lib/viewer-parts.js.map +1 -0
- package/src/lib/viewer-parts.mjs +70 -0
- package/src/lib/viewer-parts.mjs.map +1 -0
- package/src/lib/viewer.d.mts +30 -7
- package/src/lib/viewer.d.ts +30 -7
- package/src/lib/viewer.js +317 -97
- package/src/lib/viewer.js.map +1 -1
- package/src/lib/viewer.mjs +319 -99
- package/src/lib/viewer.mjs.map +1 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["fieldia-shared:7", "fieldia-shared:8", "fieldia-shared:9", "fieldia-shared:16", "fieldia-shared:13", "fieldia-shared:15", "fieldia-shared:10", "../../../../fieldia.text.ts", "../../../../libs/widgets/src/lib/formatted-text.ts", "../../../../libs/widgets/src/lib/markdown.ts", "../../../../libs/widgets/src/lib/text-tools.ts", "../../../../libs/widgets/src/lib/text-menu.ts", "../../../../libs/widgets/src/lib/styles-editor.ts", "../../../../libs/widgets/src/lib/html-field.ts", "../../../../libs/widgets/src/lib/links.ts"],
|
|
4
|
+
"sourcesContent": ["module.exports = __fieldia[7];", "module.exports = __fieldia[8];", "module.exports = __fieldia[9];", "module.exports = __fieldia[16];", "module.exports = __fieldia[13];", "module.exports = __fieldia[15];", "module.exports = __fieldia[10];", "export * from \"/home/rthm/IWork/fieldia-dev/fieldia-lanes/wi-join/libs/widgets/src/lib/text-part.ts\";", "import { drawIcon, type IconSet } from './icons';\nimport { fillIn, maker } from './kind-parts';\nimport { WIDGET_LABELS, type WidgetLabels } from './labels';\nimport { htmlToMarkdown, markdownLoses, markdownToHtml } from './markdown';\nimport { CHOOSING, EMOJI, HIGHLIGHTS, MARKDOWN_TOOLS, RICH_TOOLS, TEXT_COLOURS, TEXT_SIZES, TOGGLES, chevron, moreIcon, swatch, toolIcon, toolLabel, type TextTool } from './text-tools';\nimport { textMenu, type MenuChoice } from './text-menu';\nimport { linkAddress, sanitizeHtml } from './sanitize';\nimport { installEditorStyles } from './styles-editor';\n\n/**\n * A formatted text's editor, on its own: the rich editor (words formatted in\n * place, the browser's own editing, no library) or the Markdown one (a box of\n * Markdown, a hint, a preview), each with its toolbar, and a link under it to\n * switch between them. The html field draws it, and so does a conversation's\n * comment box (`formattedText(doc, options)`).\n *\n * Whatever it holds is handed on as clean HTML (`sanitizeHtml`): Markdown is\n * turned into HTML as it is typed, and HTML into Markdown to edit it.\n *\n * Its toolbar is one Tab stop; the arrow keys move along it, mirrored right to\n * left. Tools that find no room go under \"\u2026\", a menu. Every tool is a named\n * button with a tooltip; none looks pressed-out: Remove link with no link\n * under the cursor says so.\n */\n\nexport interface TextSuggestion {\n id: string | number;\n label: string;\n}\n\n/** A kind of record linked in the text by a key: \"#\" for a work item, \"!\" for a pull request. */\nexport interface TextReference {\n key: string;\n label: string;\n icon?: string;\n /** The model the record is of, kept on the link (`data-model`). */\n model?: string;\n search(query: string): Promise<TextSuggestion[]>;\n}\n\nexport type TextEditor = 'rich' | 'markdown';\n\nexport interface FormattedTextOptions {\n /** The id of the box typed in, which the field's label points at. */\n id?: string;\n /** What names the box: an element's id, or words. */\n labelledBy?: string;\n label?: string;\n placeholder?: string;\n labels?: WidgetLabels;\n icons?: IconSet;\n editor?: TextEditor;\n /** The tools of the editor it starts in; the other editor has its own set. */\n tools?: readonly TextTool[];\n /** When the rich editor shows its toolbar: always, while it is worked in, or never. */\n toolbar?: 'always' | 'focus' | 'never';\n toolbarAt?: 'top' | 'bottom';\n /** A link under the box that switches between the editors: shown while it is worked in, or (`always`) at rest too. */\n switchEditor?: boolean | 'always';\n mention?: { search(query: string): Promise<TextSuggestion[]> };\n references?: readonly TextReference[];\n /** What it holds after each change made in it, as clean HTML; null when it is empty. */\n onInput?(html: string | null): void;\n /** A key pressed in the box before the editor acts on it: true when the caller took it. */\n onKey?(event: KeyboardEvent): boolean;\n /** The editor switched to, by the link. */\n onSwitch?(editor: TextEditor): void;\n}\n\nexport interface FormattedText {\n readonly element: HTMLElement;\n /** The box typed in: the rich text, or the Markdown. */\n input(): HTMLElement;\n editor(): TextEditor;\n value(): string | null;\n /** Show this text. While it is being typed, the same text leaves the box alone. */\n setValue(html: string | null): void;\n /** Switch editors; from rich to Markdown, ask first when formatting would be lost (`ask`). */\n setEditor(editor: TextEditor, ask?: boolean): void;\n setReadonly(readonly: boolean): void;\n focus(): void;\n /** Words under the box for a moment, read out too. */\n say(text: string): void;\n destroy(): void;\n}\n\nlet editors = 0;\n\n/** A text that reads as nothing: no words, no picture, no list. */\nconst isEmpty = (html: string) => !html.replace(/<br\\s*\\/?>|<\\/?(p|div|span)>| |\\s/gi, '');\n\nexport function formattedText(doc: Document, options: FormattedTextOptions = {}): FormattedText {\n installEditorStyles(doc);\n const make = maker(doc);\n const labels = options.labels ?? WIDGET_LABELS.en;\n const n = ++editors;\n const references = options.references ?? [];\n const toolbarWhen = options.toolbar ?? 'always';\n let editor: TextEditor = options.editor ?? 'rich';\n let readonly = false;\n /** The last HTML handed on or shown: the same coming back leaves the box as it is. */\n let last: string | null = null;\n\n const element = make('div', { class: 'fd-text', 'data-editor': editor, 'data-toolbar': toolbarWhen, 'data-bar-at': options.toolbarAt ?? (toolbarWhen === 'focus' ? 'bottom' : 'top') });\n if (options.switchEditor === 'always') element.setAttribute('data-switch', 'always');\n const name = (box: HTMLElement) => {\n if (options.labelledBy) box.setAttribute('aria-labelledby', options.labelledBy);\n else if (options.label) box.setAttribute('aria-label', options.label);\n };\n\n // ---- the rich editor --------------------------------------------------------------\n const area = make('div', { class: 'fd-text-area', role: 'textbox', 'aria-multiline': 'true', contenteditable: 'true', id: editor === 'rich' ? options.id : undefined });\n name(area);\n if (options.placeholder) {\n area.setAttribute('data-placeholder', options.placeholder);\n area.setAttribute('aria-placeholder', options.placeholder);\n }\n const address = make('input', { class: 'fd-input', type: 'url', placeholder: 'https://', 'aria-label': labels.linkAddress });\n const applyLink = make('button', { type: 'button', class: 'fd-button fd-link-apply' }, labels.applyLink);\n const linkRow = make('div', { class: 'fd-link-row', hidden: '' }, address, applyLink);\n const richBox = make('div', { class: 'fd-text-box' });\n\n // ---- the Markdown editor --------------------------------------------------------------\n const markdown = make('textarea', { class: 'fd-md-input', rows: '3', spellcheck: 'true', id: editor === 'markdown' ? options.id : undefined });\n name(markdown);\n if (options.placeholder) markdown.placeholder = options.placeholder;\n const preview = make('div', { class: 'fd-md-preview', hidden: '', tabindex: '0', role: 'document' });\n name(preview);\n const info = drawIcon(doc, 'info');\n const hint = make('p', { class: 'fd-md-hint', id: `fd-md-hint-${n}` }, ...(info ? [info] : []), make('span', { class: 'fd-md-supported' }, labels.markdownSupported), ` ${labels.pasteOrSelect}`);\n markdown.setAttribute('aria-describedby', hint.id);\n const previewSwitch = make('button', { type: 'button', role: 'switch', class: 'fd-md-preview-switch', 'aria-checked': 'false' }, make('span', { class: 'fd-md-track', 'aria-hidden': 'true' }), make('span', {}, labels.preview));\n const mdRow = make('div', { class: 'fd-md-row' });\n const mdCard = make('div', { class: 'fd-md-card' }, markdown, preview, hint, mdRow);\n\n // ---- under the box --------------------------------------------------------------------\n const said = make('p', { class: 'fd-text-say', role: 'status', 'aria-live': 'polite' });\n const switcher = make('button', { type: 'button', class: 'fd-text-switch' });\n const under = make('div', { class: 'fd-text-under' }, said, ...(options.switchEditor ? [switcher] : []));\n const askWords = make('span', {}, labels.formattingLost);\n const askYes = make('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.switchAnyway);\n const askNo = make('button', { type: 'button', class: 'fd-button fd-button-link' }, labels.cancel);\n const ask = make('div', { class: 'fd-text-ask', role: 'group', 'aria-label': labels.switchToMarkdown, hidden: '' }, askWords, askYes, askNo);\n const suggest = make('ul', { class: 'fd-text-suggest', role: 'listbox', id: `fd-text-suggest-${n}`, hidden: '', 'aria-label': labels.search });\n element.append(richBox, mdCard, under, ask, suggest);\n\n let sayTimer: ReturnType<typeof setTimeout> | undefined;\n function say(text: string) {\n said.textContent = '';\n said.textContent = text;\n clearTimeout(sayTimer);\n sayTimer = setTimeout(() => (said.textContent = ''), 6000);\n }\n\n // ---- values ---------------------------------------------------------------------------\n function emit() {\n const html = editor === 'rich' ? sanitizeHtml(area.innerHTML, doc) : sanitizeHtml(markdownToHtml(markdown.value), doc);\n const value = isEmpty(html) ? null : html;\n area.classList.toggle('fd-blank', editor === 'rich' && !area.textContent?.trim() && !area.querySelector('img, li'));\n if (value === last) return;\n last = value;\n options.onInput?.(value);\n }\n function show(html: string | null) {\n const clean = html ? sanitizeHtml(html, doc) : '';\n if (editor === 'rich') {\n if (area.innerHTML !== clean) area.innerHTML = clean;\n area.classList.toggle('fd-blank', !area.textContent?.trim() && !area.querySelector('img, li'));\n } else {\n const text = htmlToMarkdown(clean, doc);\n if (markdown.value !== text) markdown.value = text;\n if (previewSwitch.getAttribute('aria-checked') === 'true') preview.innerHTML = clean;\n }\n }\n\n // ---- the selection, kept for the tools ----------------------------------------------------\n let lastRange: Range | null = null;\n const restore = () => {\n area.focus();\n const selection = doc.getSelection();\n if (lastRange && selection) {\n selection.removeAllRanges();\n selection.addRange(lastRange);\n }\n };\n const exec = (command: string, value?: string) => {\n restore();\n doc.execCommand?.(command, false, value);\n emit();\n };\n const selectedLink = (): HTMLAnchorElement | null => {\n const node = lastRange?.commonAncestorContainer ?? doc.getSelection()?.anchorNode ?? null;\n const at = node?.nodeType === Node.TEXT_NODE ? node.parentElement : (node as Element | null);\n const link = at?.closest?.('a');\n return link && area.contains(link) ? link : null;\n };\n\n // ---- Markdown edits ------------------------------------------------------------------\n /** Marks round the selection, or round a word to type when nothing is selected. */\n function wrapMarkdown(before: string, after = before, empty = '') {\n const [start, end] = [markdown.selectionStart, markdown.selectionEnd];\n const picked = markdown.value.slice(start, end) || empty;\n markdown.setRangeText(`${before}${picked}${after}`, start, end, 'end');\n markdown.setSelectionRange(start + before.length, start + before.length + picked.length);\n markdown.focus();\n emit();\n }\n /** A mark at the start of each line selected: a list, a checklist, a heading. */\n function prefixMarkdown(mark: (line: number) => string) {\n const value = markdown.value;\n const start = value.lastIndexOf('\\n', markdown.selectionStart - 1) + 1;\n const endAt = value.indexOf('\\n', markdown.selectionEnd);\n const end = endAt === -1 ? value.length : endAt;\n const lines = value.slice(start, end).split('\\n').map((line, i) => mark(i) + line.replace(/^(#{1,4} |[-*+] (\\[[ xX]\\] )?|\\d+\\. )/, ''));\n markdown.setRangeText(lines.join('\\n'), start, end, 'end');\n markdown.focus();\n emit();\n }\n function insertMarkdown(text: string) {\n markdown.setRangeText(text, markdown.selectionStart, markdown.selectionEnd, 'end');\n markdown.focus();\n emit();\n }\n\n // ---- pictures ---------------------------------------------------------------------------\n const picker = make('input', { type: 'file', accept: 'image/png,image/jpeg,image/gif,image/webp', hidden: '', tabindex: '-1', 'aria-hidden': 'true' });\n element.append(picker);\n const MAX_PICTURE = 2 * 1024 * 1024;\n function insertPicture(file: File) {\n if (!/^image\\/(png|jpeg|gif|webp)$/.test(file.type) || file.size > MAX_PICTURE) return;\n const reader = new FileReader();\n reader.addEventListener('load', () => {\n const src = String(reader.result);\n if (editor === 'rich') {\n restore();\n const img = make('img', { src, alt: file.name });\n doc.execCommand?.('insertHTML', false, img.outerHTML);\n emit();\n } else insertMarkdown(`![${file.name.replace(/[[\\]]/g, '')}](${src})`);\n });\n reader.readAsDataURL(file);\n }\n picker.addEventListener('change', () => {\n for (const file of picker.files ?? []) insertPicture(file);\n picker.value = '';\n });\n markdown.addEventListener('paste', (event) => {\n const files = [...(event.clipboardData?.files ?? [])].filter((file) => file.type.startsWith('image/'));\n if (!files.length) return;\n event.preventDefault();\n files.forEach(insertPicture);\n });\n\n // ---- the tools --------------------------------------------------------------------------------\n /** What a tool does when pressed, in the editor shown now. */\n function run(tool: TextTool, reference?: TextReference) {\n say('');\n if (editor === 'markdown' && previewSwitch.getAttribute('aria-checked') === 'true') setPreview(false);\n if (editor === 'markdown') return runMarkdown(tool, reference);\n switch (tool) {\n case 'bold': return exec('bold');\n case 'italic': return exec('italic');\n case 'underline': return exec('underline');\n case 'strike': return exec('strikeThrough');\n case 'bulletList': return exec('insertUnorderedList');\n case 'numberList': return exec('insertOrderedList');\n case 'outdent': return exec('outdent');\n case 'indent': return exec('indent');\n case 'clearFormatting': return exec('removeFormat');\n case 'code': {\n restore();\n const text = doc.getSelection()?.toString() || labels.code.toLowerCase();\n doc.execCommand?.('insertHTML', false, `<code>${text.replace(/[&<>]/g, (c) => ({ '&': '&', '<': '<', '>': '>' })[c] as string)}</code>`);\n return emit();\n }\n case 'taskList': {\n exec('insertUnorderedList');\n const item = (doc.getSelection()?.anchorNode as Node | null)?.parentElement?.closest('li');\n if (item && area.contains(item)) item.setAttribute('data-task', 'open');\n return emit();\n }\n case 'image':\n case 'attach':\n return picker.click();\n case 'link':\n linkRow.hidden = false;\n address.value = selectedLink()?.getAttribute('href') ?? '';\n address.setAttribute('aria-invalid', 'false');\n return address.focus();\n case 'unlink': {\n const link = selectedLink();\n if (!link) return say(labels.cursorInLink);\n restore();\n const range = doc.createRange();\n range.selectNodeContents(link);\n const selection = doc.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n doc.execCommand?.('unlink', false);\n return emit();\n }\n case 'mention':\n return startSuggesting('@');\n case 'reference':\n return startSuggesting(reference?.key ?? '#');\n default:\n return;\n }\n }\n\n function runMarkdown(tool: TextTool, reference?: TextReference) {\n switch (tool) {\n case 'bold': return wrapMarkdown('**');\n case 'italic': return wrapMarkdown('*');\n case 'strike': return wrapMarkdown('~~');\n case 'code': return wrapMarkdown('`');\n case 'highlight': return wrapMarkdown('==');\n case 'link': {\n const start = markdown.selectionStart;\n const words = markdown.value.slice(start, markdown.selectionEnd) || labels.link.toLowerCase();\n markdown.setRangeText(`[${words}](https://)`, start, markdown.selectionEnd, 'end');\n // The address selected, to type over.\n markdown.setSelectionRange(start + words.length + 3, start + words.length + 11);\n markdown.focus();\n return emit();\n }\n case 'bulletList': return prefixMarkdown(() => '- ');\n case 'numberList': return prefixMarkdown((i) => `${i + 1}. `);\n case 'taskList': return prefixMarkdown(() => '- [ ] ');\n case 'image':\n case 'attach':\n return picker.click();\n case 'mention':\n return startSuggesting('@');\n case 'reference':\n return startSuggesting(reference?.key ?? '#');\n default:\n return;\n }\n }\n\n /** The choices of a tool that opens a list: colours, sizes, a heading's level, emoji. */\n function choicesOf(tool: TextTool): MenuChoice[] {\n const names = labels.colourNames.split('|');\n const md = editor === 'markdown';\n switch (tool) {\n case 'highlight':\n return HIGHLIGHTS.map(([at, value]) => ({ label: names[at], lead: swatch(doc, value), run: () => colour('hiliteColor', value ?? 'transparent') }));\n case 'colour':\n return TEXT_COLOURS.map(([at, value]) => ({ label: names[at], lead: swatch(doc, value), run: () => colour('foreColor', value ?? 'inherit') }));\n case 'size':\n return TEXT_SIZES.map((size) => ({ label: `${size}px`, run: () => resize(size) }));\n case 'heading':\n return [1, 2, 3].map((level) => ({ label: fillIn(labels.headingLevel, { n: level }), run: () => (md ? prefixMarkdown(() => `${'#'.repeat(level)} `) : exec('formatBlock', `<h${level}>`)) })).concat(md ? [] : [{ label: labels.paragraph, run: () => exec('formatBlock', '<p>') }]);\n case 'emoji':\n return EMOJI.map((emoji) => ({ label: emoji, run: () => (md ? insertMarkdown(emoji) : exec('insertText', emoji)) }));\n default:\n return [];\n }\n }\n\n /**\n * A colour, a highlight or a size the browser put on a bold or italic element, moved to a span inside it: the\n * stored text keeps them on spans alone.\n */\n function spanStyles() {\n for (const marked of [...area.querySelectorAll<HTMLElement>('[style]:not(span)')]) {\n const kept = (['color', 'background-color', 'font-size'] as const).filter((name) => marked.style.getPropertyValue(name));\n if (!kept.length) continue;\n const span = make('span');\n for (const name of kept) {\n span.style.setProperty(name, marked.style.getPropertyValue(name));\n marked.style.removeProperty(name);\n }\n span.append(...marked.childNodes);\n marked.append(span);\n if (!marked.getAttribute('style')?.trim()) marked.removeAttribute('style');\n }\n }\n const colour = (command: 'hiliteColor' | 'foreColor', value: string) => {\n restore();\n doc.execCommand?.('styleWithCSS', false, 'true');\n doc.execCommand?.(command, false, value);\n spanStyles();\n emit();\n };\n\n /** Words in one of the sizes a stored text keeps. */\n function resize(size: number) {\n restore();\n doc.execCommand?.('styleWithCSS', false, 'false');\n doc.execCommand?.('fontSize', false, '7');\n for (const font of [...area.querySelectorAll('font[size=\"7\"]')]) {\n const span = make('span', { style: `font-size: ${size}px;` }, ...font.childNodes);\n font.replaceWith(span);\n }\n for (const span of [...area.querySelectorAll<HTMLElement>('[style*=\"xxx-large\"]')]) span.style.fontSize = `${size}px`;\n spanStyles();\n emit();\n }\n\n /** A tool's button, or the button of a reference kind; a tool with choices opens them. */\n interface Stop {\n tool: TextTool;\n label: string;\n button: HTMLButtonElement;\n menu?: ReturnType<typeof textMenu>;\n press(from: HTMLElement): void;\n }\n\n function stopsFor(list: readonly TextTool[]): Stop[] {\n const stops: Stop[] = [];\n for (const tool of list) {\n if (tool === 'mention' && !options.mention) continue;\n if (tool === 'unlink' && editor === 'markdown') continue;\n const kinds: (TextReference | undefined)[] = tool === 'reference' ? [...references] : [undefined];\n for (const reference of kinds) {\n const label = reference ? fillIn(labels.linkRecordNamed, { kind: kindWords(reference.label) }) : toolLabel(tool, labels);\n const choosing = CHOOSING.has(tool) && !(tool === 'highlight' && editor === 'markdown');\n // Emoji opens its list too, though its face alone says so: no chevron.\n const chevroned = choosing && tool !== 'emoji';\n const button = make('button', { type: 'button', class: `fd-text-tool${chevroned ? ' fd-text-tool-choice' : ''}`, 'data-tool': tool, 'aria-label': label, title: label, tabindex: '-1' }, toolIcon(doc, tool, options.icons, reference?.icon, editor));\n if (choosing) {\n if (chevroned) button.append(chevron(doc));\n button.setAttribute('aria-haspopup', 'menu');\n button.setAttribute('aria-expanded', 'false');\n }\n if (TOGGLES.has(tool) && editor === 'rich') button.setAttribute('aria-pressed', 'false');\n if (reference) button.setAttribute('data-key', reference.key);\n // The text keeps its selection when a tool is pressed.\n button.addEventListener('mousedown', (event) => event.preventDefault());\n const stop: Stop = {\n tool,\n label,\n button,\n press(from) {\n if (!choosing) return run(tool, reference);\n const menu = from === button ? (stop.menu ??= textMenu(doc, button, { label, grid: tool === 'emoji', className: tool === 'emoji' ? 'fd-text-emoji' : undefined, within: element })) : moreMenuFor(from, label, tool);\n menu.open(choicesOf(tool));\n },\n };\n button.addEventListener('click', () => stop.press(button));\n stops.push(stop);\n }\n }\n return stops;\n }\n\n /** The kind of record in a tool's name as a sentence has it: \"Link work item\". */\n function kindWords(kind: string): string {\n return /^[A-Z][a-z]/.test(kind) && labels === WIDGET_LABELS.en ? kind[0].toLowerCase() + kind.slice(1) : kind;\n }\n\n /** A tool's choices opened from \"\u2026\": under that button, in place of the menu it came from. */\n const fromMore = new Map<TextTool, ReturnType<typeof textMenu>>();\n function moreMenuFor(more: HTMLElement, label: string, tool: TextTool) {\n let menu = fromMore.get(tool);\n if (!menu) {\n menu = textMenu(doc, more, { label, align: 'end', grid: tool === 'emoji', className: tool === 'emoji' ? 'fd-text-emoji' : undefined, within: element });\n fromMore.set(tool, menu);\n }\n return menu;\n }\n\n /** A toolbar of these tools: one Tab stop, the arrows along it, \"\u2026\" for what has no room. */\n function toolbar(list: readonly TextTool[], extra: HTMLElement[] = []) {\n const bar = make('div', { class: 'fd-text-bar', role: 'toolbar', 'aria-label': labels.formatting });\n const stops = stopsFor(list);\n const more = make('button', { type: 'button', class: 'fd-text-tool fd-text-more', 'aria-label': labels.moreTools, title: labels.moreTools, tabindex: '-1', hidden: '' }, moreIcon(doc));\n more.addEventListener('mousedown', (event) => event.preventDefault());\n const moreMenu = textMenu(doc, more, { label: labels.moreTools, align: 'end', within: element });\n more.addEventListener('click', () =>\n moreMenu.open(stops.filter((stop) => stop.button.hidden).map((stop) => ({ label: stop.label, lead: toolIcon(doc, stop.tool, options.icons, stop.button.getAttribute('data-key') ? references.find((r) => r.key === stop.button.getAttribute('data-key'))?.icon : undefined, editor), run: () => stop.press(more) })))\n );\n bar.append(...stops.map((stop) => stop.button), more, ...extra);\n // One stop on Tab, the first tool; the rest, Preview too, by the arrows.\n for (const button of extra) if (button.matches('button')) button.tabIndex = -1;\n if (stops[0]) stops[0].button.tabIndex = 0;\n else if (extra[0]) extra[0].tabIndex = 0;\n const shown = () => [...stops.map((stop) => stop.button), more, ...extra.filter((e) => e.matches('button'))].filter((b) => !b.hidden) as HTMLElement[];\n bar.addEventListener('keydown', (event) => {\n const all = shown();\n const at = all.indexOf(doc.activeElement as HTMLElement);\n if (at < 0) return;\n const rtl = getComputedStyle(bar).direction === 'rtl';\n const step = { ArrowRight: rtl ? -1 : 1, ArrowLeft: rtl ? 1 : -1, Home: -at, End: all.length - 1 - at }[event.key];\n if (step === undefined) return;\n event.preventDefault();\n const next = all[(at + step + all.length) % all.length];\n for (const b of all) b.tabIndex = b === next ? 0 : -1;\n next.focus();\n });\n /** As many tools as fit, in order; \"\u2026\" holds the rest. */\n const fit = () => {\n // Out of sight (a toolbar shown only while the text is worked in), it is measured once it shows.\n if (!bar.clientWidth) return;\n for (const stop of stops) stop.button.hidden = false;\n more.hidden = true;\n const room = bar.clientWidth - parseFloat(getComputedStyle(bar).paddingInlineStart || '0') - parseFloat(getComputedStyle(bar).paddingInlineEnd || '0');\n const gap = parseFloat(getComputedStyle(bar).columnGap || '0') || 0;\n const widths = stops.map((stop) => stop.button.offsetWidth + gap);\n const others = extra.reduce((sum, e) => sum + e.offsetWidth + gap, 0);\n const total = widths.reduce((sum, w) => sum + w, 0) + others;\n if (total - gap <= room) return;\n more.hidden = false;\n let used = others + more.offsetWidth + gap;\n let count = 0;\n while (count < stops.length && used + widths[count] - gap <= room) used += widths[count++];\n stops.forEach((stop, i) => (stop.button.hidden = i >= count));\n // The Tab stop is a tool in sight.\n if (!shown().some((b) => b.tabIndex === 0)) (shown()[0] ?? more).tabIndex = 0;\n };\n const watcher = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(() => fit());\n watcher?.observe(bar);\n // Each tool says whether the selection has its format; Unlink, with no link where the caret is, is drawn idle, its\n // tooltip saying why \u2014 still a button, and a press says it too: never greyed out without a reason.\n const reflect = () => {\n for (const stop of stops) {\n if (stop.tool === 'unlink') {\n const idle = !selectedLink();\n stop.button.toggleAttribute('data-idle', idle);\n stop.button.title = idle ? `${stop.label} \u2014 ${labels.cursorInLink}` : stop.label;\n }\n if (!stop.button.hasAttribute('aria-pressed')) continue;\n const command = stop.tool === 'strike' ? 'strikeThrough' : stop.tool;\n stop.button.setAttribute('aria-pressed', String(!!doc.queryCommandState?.(command)));\n }\n };\n return { bar, stops, fit, reflect, destroy: () => watcher?.disconnect() };\n }\n\n // ---- the two toolbars, built for the editor they belong to -------------------------------------\n let richBar: ReturnType<typeof toolbar> | null = null;\n let mdBar: ReturnType<typeof toolbar> | null = null;\n const richTools = () => (options.editor !== 'markdown' && options.tools ? options.tools : RICH_TOOLS);\n const mdTools = () => (options.editor === 'markdown' && options.tools ? options.tools : MARKDOWN_TOOLS);\n\n function drawRich() {\n if (!richBar && toolbarWhen !== 'never') {\n richBar = toolbar(richTools());\n // Its tools as the text is now: Unlink idle until the caret is in a link.\n richBar.reflect();\n }\n const parts: HTMLElement[] = [area, linkRow];\n if (richBar) {\n if (element.getAttribute('data-bar-at') === 'top') parts.unshift(richBar.bar);\n else parts.push(richBar.bar);\n }\n richBox.replaceChildren(...parts);\n }\n function drawMarkdown() {\n if (!mdBar) mdBar = toolbar(mdTools(), [previewSwitch]);\n mdRow.replaceChildren(mdBar.bar);\n }\n\n function setPreview(on: boolean) {\n previewSwitch.setAttribute('aria-checked', String(on));\n if (on) preview.innerHTML = decorateLinks(sanitizeHtml(markdownToHtml(markdown.value), doc), doc);\n preview.style.minHeight = on ? `${markdown.offsetHeight}px` : '';\n markdown.hidden = on;\n preview.hidden = !on;\n (on ? preview : markdown).focus();\n }\n previewSwitch.addEventListener('click', () => setPreview(previewSwitch.getAttribute('aria-checked') !== 'true'));\n\n function setEditor(next: TextEditor, asking = false) {\n if (next === editor) return;\n if (next === 'markdown' && asking && last && markdownLoses(last, doc)) {\n ask.hidden = false;\n askNo.focus();\n return;\n }\n const value = last;\n editor = next;\n element.setAttribute('data-editor', editor);\n // The label points at the box typed in.\n if (options.id) {\n area.id = editor === 'rich' ? options.id : '';\n markdown.id = editor === 'markdown' ? options.id : '';\n if (!area.id) area.removeAttribute('id');\n if (!markdown.id) markdown.removeAttribute('id');\n }\n draw();\n show(value);\n options.onSwitch?.(editor);\n }\n askYes.addEventListener('click', () => {\n ask.hidden = true;\n setEditor('markdown');\n markdown.focus();\n });\n const keepEditor = () => {\n ask.hidden = true;\n switcher.focus();\n };\n askNo.addEventListener('click', keepEditor);\n ask.addEventListener('keydown', (event) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n event.stopPropagation();\n keepEditor();\n });\n switcher.addEventListener('click', () => {\n setEditor(editor === 'rich' ? 'markdown' : 'rich', true);\n if (ask.hidden) (editor === 'rich' ? area : markdown).focus();\n });\n\n function draw() {\n richBox.hidden = editor !== 'rich';\n mdCard.hidden = editor !== 'markdown';\n if (editor === 'rich') drawRich();\n else drawMarkdown();\n switcher.textContent = editor === 'rich' ? labels.switchToMarkdown : labels.switchToRich;\n (editor === 'rich' ? richBar : mdBar)?.fit();\n }\n\n // ---- the link row ----------------------------------------------------------------------------\n applyLink.addEventListener('click', () => {\n const url = linkAddress(address.value);\n if (!url) {\n address.setAttribute('aria-invalid', 'true');\n return;\n }\n address.setAttribute('aria-invalid', 'false');\n restore();\n if (doc.getSelection()?.isCollapsed) doc.execCommand?.('insertHTML', false, make('a', { href: url }, url).outerHTML);\n else doc.execCommand?.('createLink', false, url);\n linkRow.hidden = true;\n emit();\n });\n address.addEventListener('keydown', (event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n applyLink.click();\n } else if (event.key === 'Escape') {\n event.preventDefault();\n event.stopPropagation();\n linkRow.hidden = true;\n restore();\n }\n });\n\n // ---- people and records, as they are typed after their key ----------------------------------------\n const keys = [...(options.mention ? ['@'] : []), ...references.map((r) => r.key)];\n let found: TextSuggestion[] = [];\n let active = 0;\n let asking = 0;\n let suggesting: { key: string; start: number; node?: Text } | null = null;\n\n const closeSuggestions = () => {\n suggest.hidden = true;\n found = [];\n suggesting = null;\n for (const box of [area, markdown]) box.removeAttribute('aria-activedescendant');\n };\n function startSuggesting(key: string) {\n if (editor === 'rich') {\n restore();\n doc.execCommand?.('insertText', false, key);\n } else insertMarkdown(key);\n void lookUp();\n }\n /** What is typed after a key, up to the cursor, in the box shown. */\n function typed(): { key: string; query: string; start: number; node?: Text } | null {\n if (!keys.length) return null;\n const pattern = new RegExp(`(?:^|\\\\s)([${keys.map((k) => k.replace(/[\\\\\\]^-]/g, '\\\\$&')).join('')}])([\\\\p{L}\\\\p{N}._-]*)$`, 'u');\n if (editor === 'markdown') {\n const before = markdown.value.slice(0, markdown.selectionStart);\n const match = pattern.exec(before);\n return match ? { key: match[1], query: match[2], start: before.length - match[2].length - 1 } : null;\n }\n const selection = doc.getSelection();\n const node = selection?.anchorNode;\n if (!selection?.isCollapsed || node?.nodeType !== Node.TEXT_NODE || !area.contains(node)) return null;\n const before = (node.textContent ?? '').slice(0, selection.anchorOffset);\n const match = pattern.exec(before);\n return match ? { key: match[1], query: match[2], start: before.length - match[2].length - 1, node: node as Text } : null;\n }\n async function lookUp() {\n const at = typed();\n if (!at) return closeSuggestions();\n const search = at.key === '@' && options.mention ? options.mention.search : references.find((r) => r.key === at.key)?.search;\n if (!search) return closeSuggestions();\n const mine = ++asking;\n const results = await search(at.query);\n if (mine !== asking) return;\n found = results.slice(0, 8);\n active = 0;\n suggesting = { key: at.key, start: at.start, node: at.node };\n drawSuggestions();\n }\n function drawSuggestions() {\n const box = editor === 'rich' ? area : markdown;\n suggest.replaceChildren(\n ...(found.length\n ? found.map((item, i) => {\n const option = make('li', { role: 'option', id: `${suggest.id}-${i}`, 'aria-selected': String(i === active) }, suggestionWords(item));\n option.addEventListener('mousedown', (event) => event.preventDefault());\n option.addEventListener('click', () => pick(item));\n return option;\n })\n : [make('li', { class: 'fd-empty' }, labels.noResults)])\n );\n suggest.hidden = false;\n box.setAttribute('aria-controls', suggest.id);\n if (found.length) box.setAttribute('aria-activedescendant', `${suggest.id}-${active}`);\n }\n const suggestionWords = (item: TextSuggestion) => (suggesting?.key === '@' ? item.label : `${suggesting?.key ?? ''}${item.id} ${item.label}`);\n function pick(item: TextSuggestion) {\n const at = suggesting;\n if (!at) return;\n const reference = references.find((r) => r.key === at.key);\n const words = at.key === '@' ? `@${item.label}` : `${at.key}${item.id}`;\n if (editor === 'markdown') {\n markdown.setRangeText(`${words} `, at.start, markdown.selectionStart, 'end');\n closeSuggestions();\n markdown.focus();\n return emit();\n }\n const node = at.node;\n const selection = doc.getSelection();\n if (!node || !selection) return closeSuggestions();\n const range = doc.createRange();\n range.setStart(node, at.start);\n range.setEnd(node, Math.min(selection.anchorOffset, node.length));\n range.deleteContents();\n const mark = make('span', at.key === '@' ? { 'data-mention': String(item.id) } : { 'data-record': String(item.id), ...(reference?.model ? { 'data-model': reference.model } : {}) }, words);\n const space = doc.createTextNode('\u00A0');\n range.insertNode(space);\n range.insertNode(mark);\n range.setStartAfter(space);\n range.collapse(true);\n selection.removeAllRanges();\n selection.addRange(range);\n closeSuggestions();\n area.focus();\n emit();\n }\n const suggestKeys = (event: KeyboardEvent) => {\n if (suggest.hidden || !found.length) return false;\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n active = (active + (event.key === 'ArrowDown' ? 1 : -1) + found.length) % found.length;\n drawSuggestions();\n } else if ((event.key === 'Enter' && !event.ctrlKey && !event.metaKey) || event.key === 'Tab') pick(found[active]);\n else if (event.key === 'Escape') closeSuggestions();\n else return false;\n event.preventDefault();\n event.stopPropagation();\n return true;\n };\n\n // ---- typing --------------------------------------------------------------------------------\n for (const box of [area, markdown] as HTMLElement[]) {\n box.addEventListener('keydown', (event) => {\n if (suggestKeys(event)) return;\n if (options.onKey?.(event)) return;\n });\n box.addEventListener('input', () => {\n say('');\n emit();\n void lookUp();\n });\n }\n area.addEventListener('blur', () => {\n // What is shown is what was kept: anything unsafe typed or pasted is gone.\n if (editor === 'rich' && area.innerHTML !== (last ?? '') && last !== null) area.innerHTML = last;\n setTimeout(() => {\n if (!element.contains(doc.activeElement)) closeSuggestions();\n });\n });\n // A checklist's box ticks and unticks at a press.\n area.addEventListener('click', (event) => {\n const item = (event.target as Element).closest?.('li[data-task]');\n if (!item || readonly) return;\n const box = item.getBoundingClientRect();\n const rtl = getComputedStyle(item).direction === 'rtl';\n const offset = rtl ? box.right - event.clientX : event.clientX - box.left;\n if (offset > 18) return;\n item.setAttribute('data-task', item.getAttribute('data-task') === 'done' ? 'open' : 'done');\n emit();\n });\n const reflect = () => {\n const selection = doc.getSelection();\n if (!selection?.rangeCount || !area.contains(selection.anchorNode)) return;\n lastRange = selection.getRangeAt(0).cloneRange();\n richBar?.reflect();\n };\n doc.addEventListener('selectionchange', reflect);\n\n draw();\n // Empty to start: its placeholder shows.\n show(null);\n\n return {\n element,\n input: () => (editor === 'rich' ? area : markdown),\n editor: () => editor,\n value: () => last,\n setValue(html) {\n const clean = html ? sanitizeHtml(html, doc) : null;\n const value = clean && !isEmpty(clean) ? clean : null;\n const typing = element.contains(doc.activeElement);\n if (value === last && typing) return;\n last = value;\n show(value);\n },\n setEditor,\n setReadonly(on) {\n readonly = on;\n area.setAttribute('contenteditable', String(!on));\n area.setAttribute('aria-readonly', String(on));\n markdown.readOnly = on;\n for (const bar of [richBar, mdBar]) if (bar) bar.bar.hidden = on;\n under.hidden = on;\n if (on) linkRow.hidden = true;\n },\n focus: () => (editor === 'rich' ? area : previewSwitch.getAttribute('aria-checked') === 'true' ? preview : markdown).focus(),\n say,\n destroy() {\n clearTimeout(sayTimer);\n doc.removeEventListener('selectionchange', reflect);\n richBar?.destroy();\n mdBar?.destroy();\n },\n };\n}\n\n/**\n * Links that leave the page, as drawn: opened in a tab of their own, an icon\n * after each saying so. The stored text keeps none of it.\n */\nexport function decorateLinks(html: string, doc: Document): string {\n const box = doc.createElement('template');\n box.innerHTML = html;\n for (const link of box.content.querySelectorAll('a[href]')) {\n if (!/^https?:/i.test(link.getAttribute('href') ?? '')) continue;\n link.setAttribute('target', '_blank');\n link.setAttribute('rel', 'noopener noreferrer');\n const icon = drawIcon(doc, 'external');\n if (icon) {\n icon.classList.add('fd-external');\n link.after(icon);\n }\n }\n const out = doc.createElement('div');\n out.append(box.content);\n return out.innerHTML;\n}\n", "/**\n * Markdown and the formatted text Fieldia keeps, both ways, written by hand so\n * the one-tag script stays small: a field edited in Markdown is still stored\n * as clean HTML, and HTML is written back as Markdown to edit it again.\n *\n * The subset of CommonMark it reads: paragraphs, line breaks (two spaces or a\n * backslash at a line's end), **bold**, *italic*, ~~strikethrough~~, `code`,\n * ==highlighted== words, fenced code, [links](https://\u2026), <https://\u2026> and bare web addresses,\n * , headings 1 to 4, `-`/`*`/`+` lists, `1.` lists,\n * `- [ ]` checklists, nested by indenting, and `>` quotes. Raw HTML is\n * escaped: it shows as written, never runs.\n */\n\nconst ESCAPES: Record<string, string> = { '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' };\nconst escapeHtml = (text: string) => text.replace(/[&<>\"']/g, (c) => ESCAPES[c]);\n\n/** An address a link may go to: the web and mail only. */\nconst SAFE_LINK = /^(https?:\\/\\/|mailto:)[^\\s<>\"]+$/i;\n/** An address a picture may come from: the web, or a picture written into the text. */\nconst SAFE_IMAGE = /^(https:\\/\\/[^\\s<>\"]+|data:image\\/(png|jpeg|gif|webp);base64,[A-Za-z0-9+/=]+)$/i;\n/** A bare web address in running text, without the stop or bracket that ends its sentence. */\nconst BARE_URL = /\\bhttps?:\\/\\/[^\\s<>\"\\uE000]*[^\\s<>\".,;:!?)\\]'*_~\\uE000]/gi;\n\n// ---- Markdown \u2192 HTML ----------------------------------------------------------\n\n/** Words with their Markdown marks as HTML, every other character escaped. */\nexport function inlineMarkdown(text: string): string {\n // Code spans and escapes first, held aside as tokens so nothing inside them is read as marks.\n const held: string[] = [];\n const hold = (html: string) => `\\uE000${held.push(html) - 1}\\uE000`;\n let out = text\n .replace(/\\uE000/g, '')\n .replace(/(`+)([\\s\\S]*?[^`])\\1(?!`)/g, (_, _ticks: string, code: string) => hold(`<code>${escapeHtml(code.replace(/^ (.*) $/, '$1'))}</code>`))\n .replace(/\\\\([\\\\`*_{}[\\]()#+\\-.!~<>|])/g, (_, c: string) => hold(escapeHtml(c)));\n // Pictures and links, their words read for marks of their own.\n // A picture from an address it may not come from is a link to it.\n out = out.replace(/!\\[([^\\]]*)\\]\\(\\s*<?([^\\s)>]+)>?\\s*\\)/g, (whole, alt: string, src: string) =>\n SAFE_IMAGE.test(src) ? hold(`<img src=\"${escapeHtml(src)}\" alt=\"${escapeHtml(alt)}\">`) : SAFE_LINK.test(src) ? hold(`<a href=\"${escapeHtml(src)}\">${escapeHtml(alt || src)}</a>`) : whole\n );\n out = out.replace(/\\[([^\\]]+)\\]\\(\\s*<?([^\\s)>]+)>?\\s*\\)/g, (whole, words: string, href: string) =>\n SAFE_LINK.test(href) ? hold(`<a href=\"${escapeHtml(href)}\">${inlineMarks(escapeHtml(words))}</a>`) : whole\n );\n out = out.replace(/<((?:https?:\\/\\/|mailto:)[^\\s<>]+)>/gi, (_, href: string) => hold(`<a href=\"${escapeHtml(href)}\">${escapeHtml(href)}</a>`));\n out = out.replace(BARE_URL, (href) => hold(`<a href=\"${escapeHtml(href)}\">${escapeHtml(href)}</a>`));\n out = inlineMarks(escapeHtml(out));\n // Held parts may hold others (code in a link's words): put back until none is left.\n while (/\\uE000\\d+\\uE000/.test(out)) out = out.replace(/\\uE000(\\d+)\\uE000/g, (_, i: string) => held[Number(i)]);\n return out;\n}\n\n/** Bold, italic and strikethrough in words already escaped. */\nfunction inlineMarks(text: string): string {\n return text\n .replace(/(\\*\\*|__)(?=\\S)([\\s\\S]*?\\S)\\1/g, '<strong>$2</strong>')\n .replace(/(^|[^\\w*])\\*(?=\\S)([^*]*?\\S)\\*(?![\\w*])/g, '$1<em>$2</em>')\n .replace(/(^|[^\\w_])_(?=\\S)([^_]*?\\S)_(?![\\w_])/g, '$1<em>$2</em>')\n .replace(/~~(?=\\S)([\\s\\S]*?\\S)~~/g, '<s>$1</s>')\n .replace(/==(?=\\S)([\\s\\S]*?\\S)==/g, `<span style=\"background-color: ${HIGHLIGHT};\">$1</span>`);\n}\n\n/** The colour ==highlighted words== take. */\nconst HIGHLIGHT = 'rgb(255, 255, 0)';\n\nconst LIST_ITEM = /^( *)([-*+]|\\d{1,9}[.)])( +|$)(.*)$/;\nconst FENCE = /^ {0,3}(`{3,}|~{3,})\\s*([\\w+-]*)\\s*$/;\nconst HEADING = /^ {0,3}(#{1,4})(?: +(.*?))?(?: +#+)? *$/;\nconst QUOTE = /^ {0,3}> ?(.*)$/;\nconst RULE = /^ {0,3}([-*_])( *\\1){2,} *$/;\n\n/** Markdown as clean HTML: the subset above, raw HTML escaped. Nothing at all gives an empty string. */\nexport function markdownToHtml(markdown: string): string {\n return blocks(markdown.replace(/\\r\\n?/g, '\\n').replace(/\\t/g, ' ').split('\\n'));\n}\n\nfunction blocks(lines: string[]): string {\n const out: string[] = [];\n let i = 0;\n while (i < lines.length) {\n const line = lines[i];\n if (!line.trim()) {\n i++;\n continue;\n }\n const fence = FENCE.exec(line);\n if (fence) {\n const code: string[] = [];\n i++;\n while (i < lines.length && !lines[i].trim().startsWith(fence[1])) code.push(lines[i++]);\n i++;\n out.push(`<pre><code>${escapeHtml(code.join('\\n'))}</code></pre>`);\n continue;\n }\n const heading = HEADING.exec(line);\n if (heading) {\n out.push(`<h${heading[1].length}>${inlineMarkdown(heading[2] ?? '')}</h${heading[1].length}>`);\n i++;\n continue;\n }\n if (QUOTE.test(line)) {\n const quoted: string[] = [];\n while (i < lines.length && QUOTE.test(lines[i])) quoted.push((QUOTE.exec(lines[i++]) as RegExpExecArray)[1]);\n out.push(`<blockquote>${blocks(quoted)}</blockquote>`);\n continue;\n }\n if (LIST_ITEM.test(line) && !RULE.test(line)) {\n const [html, next] = list(lines, i);\n out.push(html);\n i = next;\n continue;\n }\n // A paragraph: lines up to a blank one or the start of another block.\n const para: string[] = [];\n while (i < lines.length && lines[i].trim() && !(para.length && (FENCE.test(lines[i]) || HEADING.test(lines[i]) || QUOTE.test(lines[i]) || LIST_ITEM.test(lines[i])))) para.push(lines[i++]);\n out.push(`<p>${paragraph(para)}</p>`);\n }\n return out.join('');\n}\n\n/** A paragraph's lines: a hard break where a line ends in two spaces or a backslash, a soft one elsewhere. */\nfunction paragraph(lines: string[]): string {\n return lines\n .map((line, n) => {\n const last = n === lines.length - 1;\n const hard = !last && (/ {2,}$/.test(line) || /\\\\$/.test(line));\n const text = line.trim().replace(/\\\\$/, last ? '\\\\' : '');\n return inlineMarkdown(text) + (last ? '' : hard ? '<br>' : '\\n');\n })\n .join('');\n}\n\n/** A list from line `start`, its items and the lists nested in them, and where the lines after it begin. */\nfunction list(lines: string[], start: number): [string, number] {\n const first = LIST_ITEM.exec(lines[start]) as RegExpExecArray;\n const indent = first[1].length;\n const ordered = /\\d/.test(first[2]);\n const items: string[] = [];\n let i = start;\n while (i < lines.length) {\n const item = LIST_ITEM.exec(lines[i]);\n // A list goes on while its marks do: another bullet, or another stop after the number, starts a new one.\n if (!item || item[1].length !== indent || (ordered ? !/\\d/.test(item[2]) || item[2].slice(-1) !== first[2].slice(-1) : item[2] !== first[2])) break;\n // The item's own lines: the next ones indented under it, blank lines inside it included.\n const own = [item[4]];\n const inner = indent + item[2].length + Math.max(1, item[3].length);\n i++;\n while (i < lines.length) {\n const next = lines[i];\n if (!next.trim()) {\n if (i + 1 < lines.length && lines[i + 1].search(/\\S/) >= Math.min(inner, indent + 2)) {\n own.push('');\n i++;\n continue;\n }\n break;\n }\n const depth = next.search(/\\S/);\n if (depth < Math.min(inner, indent + 2) && (LIST_ITEM.test(next) || depth <= indent)) break;\n own.push(next.slice(Math.min(depth, inner)));\n i++;\n }\n const task = !ordered ? /^\\[( |x|X)\\] +(.*)$/.exec(own[0]) : null;\n if (task) own[0] = task[2];\n // A single line stays words; more makes blocks of them (a nested list).\n const body = own.length === 1 || !own.slice(1).some((l) => l.trim()) ? inlineMarkdown(own[0].trim()) : itemBlocks(own);\n items.push(task ? `<li data-task=\"${task[1] === ' ' ? 'open' : 'done'}\">${body}</li>` : `<li>${body}</li>`);\n }\n while (i < lines.length && !lines[i].trim() && i + 1 < lines.length && LIST_ITEM.exec(lines[i + 1])?.[1].length === indent) i++;\n const tag = ordered ? 'ol' : 'ul';\n return [`<${tag}>${items.join('')}</${tag}>`, i];\n}\n\n/** An item of several lines: its first words as they are, and any list under them as a list. */\nfunction itemBlocks(own: string[]): string {\n const nested = own.findIndex((line, n) => n > 0 && LIST_ITEM.test(line));\n if (nested === -1) return blocks(own).replace(/^<p>([\\s\\S]*)<\\/p>$/, '$1');\n const lead = own.slice(0, nested).filter((l) => l.trim());\n return paragraph(lead) + blocks(own.slice(nested));\n}\n\n// ---- HTML \u2192 Markdown ----------------------------------------------------------\n\nconst BLOCK_TAGS = new Set(['P', 'DIV', 'H1', 'H2', 'H3', 'H4', 'UL', 'OL', 'LI', 'BLOCKQUOTE', 'PRE']);\n\n/** Marks that would read as Markdown in plain words, escaped with a backslash. */\nconst escapeMarkdown = (text: string) =>\n text\n .replace(/([\\\\`*_[\\]<~])/g, '\\\\$1')\n .replace(/^(\\s*)([#>+-])(?=\\s)/gm, '$1\\\\$2')\n .replace(/^(\\s*\\d+)\\.(?=\\s)/gm, '$1\\\\.');\n\n/** Formatted text written as Markdown, as near as Markdown can say it. */\nexport function htmlToMarkdown(html: string, doc: Document = globalThis.document): string {\n const box = doc.createElement('template');\n box.innerHTML = html;\n return blockChildren(box.content, '').replace(/\\n{3,}/g, '\\n\\n').trim();\n}\n\nfunction blockChildren(parent: ParentNode, prefix: string): string {\n const parts: string[] = [];\n let inline: Node[] = [];\n const flush = () => {\n const text = inlineOf(inline).trim();\n if (text) parts.push(text);\n inline = [];\n };\n for (const node of [...parent.childNodes]) {\n if (node.nodeType === Node.ELEMENT_NODE && BLOCK_TAGS.has((node as Element).tagName)) {\n flush();\n const md = blockOf(node as Element, prefix);\n if (md.trim()) parts.push(md);\n } else inline.push(node);\n }\n flush();\n return parts.join('\\n\\n');\n}\n\nfunction blockOf(element: Element, prefix: string): string {\n const tag = element.tagName;\n if (/^H[1-4]$/.test(tag)) return `${'#'.repeat(Number(tag[1]))} ${inlineOf([...element.childNodes]).trim()}`;\n if (tag === 'PRE') return '```\\n' + (element.textContent ?? '').replace(/\\n$/, '') + '\\n```';\n if (tag === 'BLOCKQUOTE') return blockChildren(element, prefix).split('\\n').map((line) => (line ? `> ${line}` : '>')).join('\\n');\n if (tag === 'UL' || tag === 'OL') {\n let n = 0;\n return [...element.children]\n .filter((li) => li.tagName === 'LI')\n .map((li) => {\n n++;\n const task = li.getAttribute('data-task');\n const mark = tag === 'OL' ? `${n}.` : '-';\n const box = tag === 'UL' && (task === 'open' || task === 'done') ? `[${task === 'done' ? 'x' : ' '}] ` : '';\n const pad = ' '.repeat(mark.length + 1);\n const body = blockChildren(li, prefix).replace(/\\n\\n(?=\\s*([-*+]|\\d+\\.) )/g, '\\n');\n return `${mark} ${box}${body.split('\\n').map((line, i) => (i && line ? pad + line : line)).join('\\n')}`;\n })\n .join('\\n');\n }\n return blockChildren(element, prefix);\n}\n\nfunction inlineOf(nodes: Node[]): string {\n return nodes.map(inlineNode).join('');\n}\n\nfunction inlineNode(node: Node): string {\n if (node.nodeType === Node.TEXT_NODE) return escapeMarkdown((node.textContent ?? '').replace(/\\s*\\n\\s*/g, ' '));\n if (node.nodeType !== Node.ELEMENT_NODE) return '';\n const element = node as Element;\n const inner = () => inlineOf([...element.childNodes]);\n const wrap = (mark: string) => {\n const text = inner();\n const [, lead, core, trail] = /^(\\s*)([\\s\\S]*?)(\\s*)$/.exec(text) as RegExpExecArray;\n return core ? `${lead}${mark}${core}${mark}${trail}` : text;\n };\n switch (element.tagName) {\n case 'BR':\n return '\\\\\\n';\n case 'STRONG':\n case 'B':\n return wrap('**');\n case 'EM':\n case 'I':\n return wrap('*');\n case 'S':\n case 'STRIKE':\n case 'DEL':\n return wrap('~~');\n case 'CODE': {\n const code = element.textContent ?? '';\n const ticks = '`'.repeat((code.match(/`+/g) ?? ['']).reduce((most, run) => Math.max(most, run.length), 0) + 1);\n return ticks.length > 1 || /^`|`$/.test(code) ? `${ticks} ${code} ${ticks}` : `\\`${code}\\``;\n }\n case 'A': {\n const href = element.getAttribute('href') ?? '';\n const words = inner();\n if (!href) return words;\n if (element.textContent !== href) return `[${words}](${href})`;\n // An address shown as itself: bare when it reads back whole, else in <\u2026>.\n return (href.match(BARE_URL) ?? [])[0] === href ? href : `<${href}>`;\n }\n case 'SPAN':\n // Highlighted words, the one colour Markdown here can say.\n return highlightOnly(element) ? wrap('==') : inner();\n case 'IMG':\n return ` ?? ''})`;\n default:\n return inner();\n }\n}\n\n/**\n * Whether writing this formatted text as Markdown would lose some of it:\n * underlining, colours, sizes, alignment, a person or record linked in place.\n * Asked before a field switches from the rich editor to Markdown.\n */\nexport function markdownLoses(html: string, doc: Document = globalThis.document): boolean {\n const box = doc.createElement('template');\n box.innerHTML = html;\n return [...box.content.querySelectorAll('*')].some(\n (element) =>\n element.tagName === 'U' ||\n element.hasAttribute('data-mention') ||\n element.hasAttribute('data-record') ||\n (element.hasAttribute('style') && !highlightOnly(element)) ||\n (element.tagName === 'SPAN' && element.attributes.length > 0 && !highlightOnly(element))\n );\n}\n\n/** A span that only highlights its words, as ==words== write it. */\nfunction highlightOnly(element: Element): boolean {\n if (element.tagName !== 'SPAN' || element.attributes.length !== 1) return false;\n const style = (element as HTMLElement).style;\n return !!style?.backgroundColor && style.length === 1;\n}\n", "import { drawIcon, type IconSet } from './icons';\nimport type { WidgetLabels } from './labels';\nimport type { TextTool } from './text-tool-names';\n\n/**\n * A formatted text's tools: what each is called, how it is drawn, and in\n * which order a page lists them. Icons are 16px lines in the words' colour;\n * a list's marks and an indent's arrow take the accent, a highlight and a\n * text colour show the colour they give, as an editor's toolbar draws them.\n */\n\nexport { MARKDOWN_TOOLS, RICH_TOOLS, TEXT_TOOLS, type TextTool } from './text-tool-names';\n\n/** Tools that open a list of choices: a colour, a size, a heading's level, an emoji. */\nexport const CHOOSING: ReadonlySet<TextTool> = new Set(['highlight', 'colour', 'size', 'heading', 'emoji']);\n/** Tools whose button says whether the selection already has their format. */\nexport const TOGGLES: ReadonlySet<TextTool> = new Set(['bold', 'italic', 'underline', 'strike']);\n\n/** Each tool's name, in the page's language. */\nexport function toolLabel(tool: TextTool, labels: WidgetLabels): string {\n const key: Record<TextTool, keyof WidgetLabels> = {\n bold: 'bold', italic: 'italic', underline: 'underline', bulletList: 'bulletList', numberList: 'numberList', highlight: 'highlight', colour: 'textColour',\n emoji: 'emoji', outdent: 'outdent', indent: 'indent', strike: 'strike', size: 'textSize', code: 'code', mention: 'mention', reference: 'linkRecordNamed',\n clearFormatting: 'clearFormatting', image: 'image', link: 'link', unlink: 'removeLink', taskList: 'taskList', heading: 'heading', attach: 'attachFile',\n };\n return labels[key[tool]];\n}\n\nconst PATHS: Partial<Record<TextTool, string>> = {\n italic: '<path d=\"M7 2.5h5.5M3.5 13.5H9M9.8 2.5l-3.6 11\"/>',\n underline: '<path d=\"M4.5 2v5.5a3.5 3.5 0 0 0 7 0V2M3.5 14.5h9\"/>',\n // Four thin lines, a dotted column of markers before them; three lines and tiny numbers (20.22.28). They run a little past\n // the box's end, as the tracker's do.\n bulletList: '<path d=\"M5 4.5h13M5 7.5h13M5 10.5h13M5 13.5h13\" stroke-width=\"1\" stroke-linecap=\"butt\"/><g class=\"fd-text-accent\"><rect x=\"2\" y=\"4\" width=\"1\" height=\"1\"/><rect x=\"2\" y=\"7\" width=\"1\" height=\"1\"/><rect x=\"2\" y=\"10\" width=\"1\" height=\"1\"/><rect x=\"2\" y=\"13\" width=\"1\" height=\"1\"/></g>',\n numberList: '<path d=\"M5 4.5h12M5 8.5h12M5 12.5h12\" stroke-width=\"1\" stroke-linecap=\"butt\"/><path class=\"fd-text-accent-line\" stroke-width=\".8\" d=\"M1.6 3.6l1-.6v3M1.4 7.4c.3-.5 1.6-.4 1.4.4-.1.5-1.4 1-1.4 1.7h1.6M1.4 11.1h1.4l-.7.9c.5 0 .8.3.8.7s-.4.7-.8.7c-.3 0-.6-.1-.7-.3\"/>',\n highlight: '<path d=\"M1.6 2.6c.3-.4.8-.6 1.3-.6.8 0 1.3.5 1.3 1.3V6.6M4.2 4.4c-1.9-.1-2.9.4-2.9 1.2 0 .6.4 1 1 1 1 0 1.9-.6 1.9-1.6M5.9 .9v5.7M5.9 4.3c.2-.9.8-1.4 1.5-1.4.9 0 1.4.8 1.4 1.9s-.5 1.9-1.4 1.9c-.7 0-1.3-.5-1.5-1.4\"/><path d=\"M5.4 13.4l.7-2.6 6.6-6.6 1.9 1.9-6.6 6.6z\"/><rect class=\"fd-text-swatch\" x=\"1.2\" y=\"13\" width=\"9.6\" height=\"2.2\" rx=\".3\"/>',\n // A thin A over a bar of the colour, the bar on whole pixels at the box's foot (20.22.28).\n colour: '<path d=\"M1.8 13.5L6.5 1.2l4.7 12.3M3.3 9.5h6.4\" stroke-width=\"1\"/><rect class=\"fd-text-swatch\" x=\"1\" y=\"15\" width=\"11\" height=\"2\"/>',\n // A round face lit from above, light yellow to orange at its foot, no outline; its eyes and smile in brown (20.22.28).\n emoji: '<defs><radialGradient id=\"fd-face\" cy=\".22\" r=\".85\"><stop stop-color=\"#fffbd2\"/><stop offset=\".3\" stop-color=\"#fde24f\"/><stop offset=\".62\" stop-color=\"#fbc12b\"/><stop offset=\"1\" stop-color=\"#ea8a0b\"/></radialGradient></defs><circle class=\"fd-text-face\" cx=\"8\" cy=\"8\" r=\"7.4\" fill=\"url(#fd-face)\"/><path class=\"fd-text-smile\" d=\"M5.2 10.4q2.8 1.7 5.6 0\"/><ellipse class=\"fd-text-dot\" cx=\"5.8\" cy=\"6.7\" rx=\".6\" ry=\"1.1\"/><ellipse class=\"fd-text-dot\" cx=\"10.2\" cy=\"6.7\" rx=\".6\" ry=\"1.1\"/>',\n outdent: '<path d=\"M8 3.5h6.5M8 6.5h6.5M8 9.5h6.5M8 12.5h6.5\"/><path class=\"fd-text-accent-line\" d=\"M6 8H1.5M3.5 6L1.5 8l2 2\"/>',\n indent: '<path d=\"M8 3.5h6.5M8 6.5h6.5M8 9.5h6.5M8 12.5h6.5\"/><path class=\"fd-text-accent-line\" d=\"M1.5 8H6M4 6l2 2-2 2\"/>',\n size: '<path d=\"M2 14l2.8-7.4L7.6 14M3 11.6h3.6M10 14l3.7-12.6L17.4 14M11.2 10h5\"/>',\n code: '<path d=\"M4 4L.5 7.5 4 11M12 4l3.5 3.5L12 11M9.8 2.5L6.6 13.5\" stroke-width=\"1\"/>',\n // A thin A and a pink eraser on the slant, its tip parted from it (20.22.28).\n clearFormatting: '<path d=\"M4.6 9.8L7.5 1.2l2.9 8.6M5.4 7.5h4.2\" stroke-width=\"1\"/><g class=\"fd-text-eraser\" transform=\"rotate(-45 10.5 11)\"><rect x=\"5.5\" y=\"8.9\" width=\"2.7\" height=\"4.2\" rx=\".8\"/><rect x=\"9\" y=\"8.9\" width=\"6.5\" height=\"4.2\" rx=\".8\"/></g>',\n image: '<rect x=\"1.5\" y=\"3\" width=\"13\" height=\"10\" rx=\".6\"/><path class=\"fd-text-accent-fill\" d=\"M2 12.5l3.6-4 2.6 2.6 2-1.8 3.8 3.2z\"/><circle cx=\"11\" cy=\"6\" r=\"1\"/>',\n // Two rings linked, as a rich editor draws a link; Remove link, the same rings with a red cross.\n link: '<g stroke-width=\"1\"><rect x=\"2.3\" y=\"3.5\" width=\"9.4\" height=\"6\" rx=\"3\"/><rect x=\"7.6\" y=\"6.5\" width=\"9.3\" height=\"6\" rx=\"3\"/></g>',\n unlink: '<g stroke-width=\"1\"><rect x=\"2.3\" y=\"3.5\" width=\"9.4\" height=\"6\" rx=\"3\"/><path d=\"M11.7 6.5h2.2a3 3 0 0 1 0 6h-3.3\"/></g><path class=\"fd-text-cross\" d=\"M13.5 12.5l4 4M17.5 12.5l-4 4\"/>',\n taskList: '<path d=\"M7 3.5h7.5M7 8h7.5M7 12.5h7.5\"/><path class=\"fd-text-accent-line\" d=\"M1.5 3.5l1.2 1.2L5 2.2M1.5 8l1.2 1.2L5 6.7\"/><rect x=\"1.6\" y=\"11\" width=\"3\" height=\"3\" rx=\".4\"/>',\n // A heading's level: a letter and a pen, its list of levels beside it.\n heading: '<path d=\"M1.4 8.2L3.9 1.6l2.5 6.6M2.3 5.9h3.2\"/><path d=\"M5.4 13.4l.7-2.6 6.6-6.6 1.9 1.9-6.6 6.6z\"/>',\n};\n\n/** The Markdown editor's own drawings, where they differ: its marks on words, not a colour; a link across; ticks for a task list. */\nconst MARKDOWN_PATHS: Partial<Record<TextTool, string>> = {\n highlight: '<path d=\"M1.6 2.6c.3-.4.8-.6 1.3-.6.8 0 1.3.5 1.3 1.3V6.6M4.2 4.4c-1.9-.1-2.9.4-2.9 1.2 0 .6.4 1 1 1 1 0 1.9-.6 1.9-1.6M5.9 .9v5.7M5.9 4.3c.2-.9.8-1.4 1.5-1.4.9 0 1.4.8 1.4 1.9s-.5 1.9-1.4 1.9c-.7 0-1.3-.5-1.5-1.4\"/><path d=\"M5.4 13.4l.7-2.6 6.6-6.6 1.9 1.9-6.6 6.6z\"/>',\n link: '<path d=\"M6.5 5H4.8a3 3 0 0 0 0 6h1.7M9.5 5h1.7a3 3 0 0 1 0 6H9.5M5.5 8h5\"/>',\n // Its code a smaller </>, thin (20.21.54).\n code: '<path d=\"M5.2 5.2L2.8 7.7l2.4 2.4M11.8 5.2l2.4 2.5-2.4 2.4M10.4 3.2L7 12.6\" stroke-width=\"1\"/>',\n bulletList: '<path d=\"M5.5 3.5h9M5.5 8h9M5.5 12.5h9\"/><g class=\"fd-text-ink\"><circle cx=\"2.2\" cy=\"3.5\" r=\".9\"/><circle cx=\"2.2\" cy=\"8\" r=\".9\"/><circle cx=\"2.2\" cy=\"12.5\" r=\".9\"/></g>',\n taskList: '<path d=\"M7 3.5h7.5M7 8h7.5M7 12.5h7.5M1.5 3.5l1.1 1.1L4.8 2.4M1.5 8l1.1 1.1 2.2-2.2M1.5 12.5l1.1 1.1 2.2-2.2\"/>',\n};\n\nconst SVG = 'http://www.w3.org/2000/svg';\n/** Emoji faces drawn so far: each its own gradient's id. */\nlet faces = 0;\n\n/** A tool's icon: its own drawing, a letter, or one of Fieldia's icons by name (an @, a #, a link to a pull request). */\nexport function toolIcon(doc: Document, tool: TextTool, icons?: IconSet, iconName?: string, editor: 'rich' | 'markdown' = 'rich'): Element {\n // Bold and struck words, as letters.\n if (tool === 'bold' || tool === 'strike') {\n const letters = doc.createElement('span');\n letters.className = `fd-text-glyph fd-text-glyph-${tool}`;\n letters.setAttribute('aria-hidden', 'true');\n letters.textContent = tool === 'bold' ? 'B' : 'ab';\n return letters;\n }\n const shared: Partial<Record<TextTool, string>> = { mention: 'mention', reference: iconName ?? 'hash', attach: 'attach' };\n const named = shared[tool] ? drawIcon(doc, shared[tool], icons) : null;\n if (named) {\n named.classList.add('fd-text-icon');\n return named;\n }\n const svg = doc.createElementNS(SVG, 'svg');\n // The size's two letters, small and large, take a wider box.\n svg.setAttribute('viewBox', tool === 'size' ? '0 0 20 16' : '0 0 16 16');\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('focusable', 'false');\n svg.setAttribute('class', `fd-text-icon fd-text-icon-${tool}`);\n // The face's light is a gradient of its own in each drawing: an id is the whole document's, and a toolbar may be hidden.\n const drawing = (editor === 'markdown' ? MARKDOWN_PATHS[tool] : undefined) ?? PATHS[tool] ?? '';\n svg.innerHTML = tool === 'emoji' ? drawing.replace(/fd-face/g, `fd-face${++faces}`) : drawing;\n return svg;\n}\n\n/** The chevron of a tool that opens a list. */\nexport function chevron(doc: Document): Element {\n const svg = doc.createElementNS(SVG, 'svg');\n svg.setAttribute('viewBox', '0 0 12 12');\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('class', 'fd-text-chevron');\n // Across the whole box, 11 by 5.5: as wide as the tracker's list chevrons.\n svg.innerHTML = '<path d=\"M.5 3.5L6 9l5.5-5.5\"/>';\n return svg;\n}\n\n/** \"\u2026\": the tools with no room, in a menu. */\nexport function moreIcon(doc: Document): Element {\n const svg = doc.createElementNS(SVG, 'svg');\n svg.setAttribute('viewBox', '0 0 16 16');\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('class', 'fd-text-icon');\n svg.innerHTML = '<circle cx=\"1.5\" cy=\"8\" r=\"0.5\"/><circle cx=\"8\" cy=\"8\" r=\"0.5\"/><circle cx=\"14.5\" cy=\"8\" r=\"0.5\"/>';\n return svg;\n}\n\n/** Highlights by Flectra's colour numbers (their names are the widgets' `colourNames`): yellow first, none last. */\nexport const HIGHLIGHTS: readonly [number, string | null][] = [[3, '#ffff00'], [10, '#b4f0a8'], [4, '#9eecf2'], [9, '#ffb3d0'], [2, '#ffd08a'], [0, null]];\n/** Words' colours: the words' own colour last. */\nexport const TEXT_COLOURS: readonly [number, string | null][] = [[1, '#d13438'], [2, '#ca5010'], [10, '#107c10'], [8, '#0078d4'], [5, '#8764b8'], [7, '#038387'], [0, null]];\n/** Sizes of words, in pixels: the sizes a stored text keeps. */\nexport const TEXT_SIZES: readonly number[] = [12, 14, 16, 20, 28];\nexport const EMOJI: readonly string[] = ['\uD83D\uDE00', '\uD83D\uDE42', '\uD83D\uDE09', '\uD83D\uDE0D', '\uD83D\uDE0E', '\uD83E\uDD14', '\uD83D\uDE22', '\uD83D\uDE20', '\uD83D\uDC4D', '\uD83D\uDC4E', '\uD83D\uDC4F', '\uD83D\uDE4F', '\uD83C\uDF89', '\u2705', '\u274C', '\u26A0\uFE0F', '\uD83D\uDD25', '\uD83D\uDC1B', '\uD83D\uDCA1', '\uD83D\uDE80'];\n\n/** A colour's swatch, for a menu of colours. */\nexport function swatch(doc: Document, colour: string | null): HTMLElement {\n const box = doc.createElement('span');\n box.className = 'fd-text-colour';\n box.setAttribute('aria-hidden', 'true');\n if (colour) box.style.background = colour;\n else box.classList.add('fd-text-colour-none');\n return box;\n}\n", "/**\n * A menu that floats under the button that opens it \u2014 a formatted text's\n * colours, sizes and hidden tools, a links box's Add link \u2014 in a form it is\n * placed over the page from there, so a group or a scrolling box never clips\n * it, and goes back where it came from when it closes. Its start edge meets\n * the button's (`align: 'start'`) or its end edge the button's (`'end'`),\n * mirrored right to left; kept on the screen.\n *\n * It is a real menu: \u2193 \u2191 Home End move, Enter and Space choose, Escape and\n * Tab close it and give the focus back, a press outside closes it.\n */\n\nexport interface MenuChoice {\n label: string;\n /** Drawn before the words: an icon, a colour's swatch. */\n lead?: Node | null;\n /** A choice that is on now, as a colour picked: \u2713 and `aria-checked`. */\n checked?: boolean;\n run(): void;\n}\n\nexport interface TextMenu {\n readonly element: HTMLElement;\n open(choices: MenuChoice[], options?: { focus?: 'first' | 'checked' | 'none' }): void;\n close(giveBack?: boolean): void;\n isOpen(): boolean;\n}\n\nlet menus = 0;\n\nexport function textMenu(doc: Document, anchor: HTMLElement, options: { label: string; align?: 'start' | 'end'; className?: string; grid?: boolean; within?: HTMLElement }): TextMenu {\n const element = doc.createElement('div');\n element.className = `fd-text-menu${options.className ? ` ${options.className}` : ''}`;\n element.id = `fd-text-menu-${++menus}`;\n element.setAttribute('role', 'menu');\n element.setAttribute('aria-label', options.label);\n element.hidden = true;\n anchor.setAttribute('aria-haspopup', 'menu');\n anchor.setAttribute('aria-expanded', 'false');\n anchor.setAttribute('aria-controls', element.id);\n let items: HTMLElement[] = [];\n\n const outside = (event: Event) => {\n if (!element.contains(event.target as Node) && !anchor.contains(event.target as Node)) close(false);\n };\n const move = (to: number) => {\n if (!items.length) return;\n const at = (to + items.length) % items.length;\n items.forEach((item, i) => (item.tabIndex = i === at ? 0 : -1));\n items[at].focus();\n };\n\n function place() {\n // Where it floats: what the caller names \u2014 a formatted text keeps its menus inside itself, so it still holds\n // the focus while one is open \u2014 else over the form.\n const host = options.within ?? anchor.closest<HTMLElement>('.fd-form, .fd-theme') ?? doc.body;\n host.append(element);\n Object.assign(element.style, { position: 'absolute', top: '0px', left: '0px' });\n const [a, origin, own] = [anchor.getBoundingClientRect(), element.getBoundingClientRect(), element.offsetWidth];\n const rtl = getComputedStyle(anchor).direction === 'rtl';\n const end = (options.align ?? 'start') === 'end';\n const width = doc.documentElement.clientWidth || own;\n // The edge it shares with the button: the start of the line, or its end, whichever way the words run.\n const wanted = end !== rtl ? a.right - own : a.left;\n const left = Math.max(8, Math.min(wanted, width - own - 8));\n Object.assign(element.style, { top: `${a.bottom - origin.top}px`, left: `${left - origin.left}px` });\n }\n\n function open(choices: MenuChoice[], how: { focus?: 'first' | 'checked' | 'none' } = {}) {\n items = choices.map((choice) => {\n const item = doc.createElement('button');\n item.type = 'button';\n item.className = 'fd-text-menu-item';\n item.setAttribute('role', choice.checked === undefined ? 'menuitem' : 'menuitemradio');\n if (choice.checked !== undefined) item.setAttribute('aria-checked', String(choice.checked));\n item.tabIndex = -1;\n const words = doc.createElement('span');\n words.className = 'fd-text-menu-words';\n words.textContent = choice.label;\n if (options.grid) item.setAttribute('aria-label', choice.label);\n item.append(...(choice.lead ? [choice.lead] : []), ...(options.grid ? [] : [words]));\n // The text keeps its selection: the press acts on what was selected there.\n item.addEventListener('mousedown', (event) => event.preventDefault());\n item.addEventListener('click', () => {\n close(true);\n choice.run();\n });\n return item;\n });\n element.replaceChildren(...items);\n element.hidden = false;\n anchor.setAttribute('aria-expanded', 'true');\n anchor.classList.add('fd-pressed');\n place();\n doc.addEventListener('pointerdown', outside, true);\n const checked = items.findIndex((item) => item.getAttribute('aria-checked') === 'true');\n if (how.focus !== 'none') move(how.focus === 'checked' && checked >= 0 ? checked : 0);\n else if (items[0]) items[0].tabIndex = 0;\n }\n\n function close(giveBack = true) {\n if (element.hidden) return;\n // The focus back on the button first: hidden while focused, the menu would drop it on the page.\n if (giveBack) anchor.focus();\n element.hidden = true;\n anchor.setAttribute('aria-expanded', 'false');\n anchor.classList.remove('fd-pressed');\n doc.removeEventListener('pointerdown', outside, true);\n // Back beside its button, out of sight.\n const home = anchor.parentElement;\n if (home && element.parentElement !== home) home.append(element);\n for (const key of ['position', 'top', 'left'] as const) element.style.removeProperty(key);\n }\n\n element.addEventListener('keydown', (event) => {\n const at = items.indexOf(doc.activeElement as HTMLElement);\n const rtl = getComputedStyle(element).direction === 'rtl';\n const across = options.grid ? { ArrowRight: rtl ? -1 : 1, ArrowLeft: rtl ? 1 : -1 } : {};\n const step = ({ ArrowDown: 1, ArrowUp: -1, ...across } as Record<string, number>)[event.key];\n if (step !== undefined) {\n event.preventDefault();\n move(at + step);\n } else if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault();\n move(event.key === 'Home' ? 0 : items.length - 1);\n } else if (event.key === 'Escape') {\n event.preventDefault();\n event.stopPropagation();\n close(true);\n } else if (event.key === 'Tab') {\n close(false);\n }\n });\n\n return { element, open, close, isOpen: () => !element.hidden };\n}\n", "import { installPartStyles, PART_RANK } from './styles';\n\n/**\n * The formatted text's editors (rich and Markdown) with their toolbars and\n * menus, a field's own tools, and a links box: the text part's sheet\n * (text-part.ts), put in its place among Fieldia's the first time a page\n * draws one (installPartStyles, PART_RANK.text).\n */\nexport const EDITOR_CSS = /* css */ `.fd-field-tool{display:inline-grid;place-items:center;width:32px;height:32px;padding:0;border:0;border-radius:2px;background:none;color:var(--fd-text);cursor:pointer;font:inherit}.fd-field-tool:hover{background:var(--fd-text-hover)}.fd-field-tool:active{background:var(--fd-text-pressed)}.fd-field-tool:focus-visible{outline:1px solid var(--fd-focus);outline-offset:-1px}.fd-field-tool svg{width:18px;height:18px;stroke-width:1.34}.fd-text{position:relative;display:grid;min-width:0;--fd-text-pad-x: 5px}.fd-text[hidden]{display:none}.fd-text-box{position:relative;display:flex;flex-direction:column;min-width:0;border:1px solid var(--fd-border);border-radius:2px;background:var(--fd-surface)}.fd-text-box:focus-within{border-color:var(--fd-focus)}.fd-text-area{position:relative;min-height:85px;padding:5px var(--fd-text-pad-x);line-height:20px;color:var(--fd-text);outline:none;overflow-wrap:anywhere;cursor:text}.fd-text-area.fd-blank:not(:focus):before{content:attr(data-placeholder);position:absolute;color:var(--fd-muted);font-style:italic;pointer-events:none}.fd-form :is(.fd-text-area,.fd-md-input,.fd-md-preview,.fd-md-view):focus-visible{outline:none}.fd-text-area[contenteditable=false]{cursor:default}:is(.fd-text-area,.fd-md-view,.fd-md-preview) :is(p,ul,ol,blockquote,pre,h1,h2,h3,h4){margin:0 0 6px}:is(.fd-text-area,.fd-md-view,.fd-md-preview)>:last-child{margin-block-end:0}:is(.fd-text-area,.fd-md-view,.fd-md-preview)>*{unicode-bidi:plaintext}:is(.fd-text-area,.fd-md-view,.fd-md-preview) :is(ul,ol){padding-inline-start:24px}:is(.fd-text-area,.fd-md-view,.fd-md-preview) a{color:var(--fd-text-link);text-decoration:underline}:is(.fd-md-view,.fd-md-preview) a{padding-block:4px}:is(.fd-text-area,.fd-md-view,.fd-md-preview) code{padding:0 3px;border-radius:2px;background:var(--fd-text-fill);font:13px/1.4 ui-monospace,SF Mono,Menlo,Consolas,monospace}:is(.fd-text-area,.fd-md-view,.fd-md-preview) pre{padding:8px 10px;background:var(--fd-text-fill);overflow-x:auto}:is(.fd-text-area,.fd-md-view,.fd-md-preview) pre code{padding:0;background:none}:is(.fd-text-area,.fd-md-view,.fd-md-preview) blockquote{padding-inline-start:10px;border-inline-start:3px solid var(--fd-border);color:var(--fd-muted)}:is(.fd-text-area,.fd-md-view,.fd-md-preview) img{max-width:100%;height:auto}:is(.fd-text-area,.fd-md-view,.fd-md-preview) li[data-task]{list-style:none;position:relative}:is(.fd-text-area,.fd-md-view,.fd-md-preview) li[data-task]:before{content:\"\";position:absolute;inset-inline-start:-20px;inset-block-start:4px;width:12px;height:12px;border:1px solid var(--fd-border-strong);border-radius:2px;background:var(--fd-surface)}:is(.fd-text-area,.fd-md-view,.fd-md-preview) li[data-task=done]:before{background:var(--fd-accent);border-color:var(--fd-accent);box-shadow:inset 0 0 0 2px var(--fd-surface)}:is(.fd-text-area,.fd-md-view,.fd-md-preview) li[data-task=done]{text-decoration:line-through;color:var(--fd-muted)}:is(.fd-text-area,.fd-md-view,.fd-md-preview) :is([data-mention],[data-record]){color:var(--fd-text-link);font-weight:600}.fd-text[data-toolbar=focus]:not(:where([data-editor=markdown])){padding-block-end:17px}.fd-text[data-toolbar=focus]>.fd-text-box{border-color:transparent;background:transparent;border-radius:max(var(--fd-control-radius, 2px),4px)}.fd-text[data-toolbar=focus]:focus-within>.fd-text-box{background:var(--fd-surface)}.fd-text[data-toolbar=focus]>.fd-text-box:hover{border-color:var(--fd-border)}.fd-text[data-toolbar=focus]:focus-within>.fd-text-box{border-color:var(--fd-focus)}.fd-text[data-toolbar=focus]:not(:focus-within) .fd-text-bar{display:none}.fd-text[data-toolbar=focus]:not(:focus-within) .fd-text-area{min-height:48px}.fd-text:not([data-switch=always]):not(:focus-within) .fd-text-switch{display:none}.fd-text-under{display:flex;flex-wrap:wrap;align-items:start;justify-content:flex-end;gap:0 12px;min-width:0}.fd-text-under:empty,.fd-text-under:not(:has(.fd-text-switch)):has(>.fd-text-say:empty){display:none}.fd-text-say{flex:1 1 auto;margin:2px 0 0;color:var(--fd-muted);font-size:12px;line-height:16px}.fd-text-say:empty{display:none}.fd-text-switch{margin:2px 0 0;padding:0;border:0;background:none;color:var(--fd-text-link);font:12px/16px var(--fd-font);text-decoration:underline;cursor:pointer}.fd-text-switch:focus-visible,.fd-links-empty-link:focus-visible,.fd-md-preview-switch:focus-visible,.fd-links-name:focus-visible{outline:1px solid var(--fd-focus);outline-offset:1px}.fd-text-ask{display:flex;flex-wrap:wrap;align-items:center;gap:4px 12px;margin-block-start:6px;padding:8px 10px;border-radius:2px;background:var(--fd-warning-soft);color:var(--fd-text);font-size:13px}.fd-text-bar{display:flex;align-items:center;gap:3px;min-width:0;padding:0 12px 5px 6px;padding-inline:6px 12px;overflow:hidden}.fd-text[data-bar-at=top] .fd-text-box>.fd-text-bar{padding-block:5px 0}.fd-text-tool{position:relative;display:inline-flex;align-items:center;justify-content:center;flex:none;width:32px;height:32px;padding:0;border:0;border-radius:2px;background:none;color:var(--fd-text);font:inherit;cursor:pointer}.fd-text-tool[hidden]{display:none}.fd-text-tool-choice{width:46px;justify-content:flex-start;padding-inline-start:5px}.fd-text-tool-choice[data-tool=size]{width:56px;padding-inline-start:10px}.fd-text-tool-choice[data-tool=size]>.fd-text-chevron{margin-inline-start:6px}.fd-text-icon-size{width:20px}.fd-text-tool:hover{background:var(--fd-text-hover)}.fd-text-tool[data-idle]{color:color-mix(in srgb,var(--fd-text) 48%,var(--fd-surface))}.fd-text-tool[data-idle] .fd-text-cross{opacity:.5}.fd-text-tool:is([aria-pressed=true],.fd-pressed,[aria-expanded=true]){background:var(--fd-text-pressed)}.fd-text-tool:focus-visible,.fd-text-menu-item:focus-visible,.fd-links-add:focus-visible,.fd-links-remove:focus-visible{outline:1px solid var(--fd-focus);outline-offset:-1px;box-shadow:inset 0 0 0 3px color-mix(in srgb,var(--fd-focus) 25%,transparent)}.fd-text-icon{width:16px;height:16px;flex:none;overflow:visible;fill:none;stroke:currentColor;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round}.fd-text-tool>svg.fd-icon{stroke-width:1.6}.fd-text-accent{fill:var(--fd-accent);stroke:none}.fd-text-ink{fill:currentColor;stroke:none}.fd-text-accent-line{stroke:var(--fd-accent)}.fd-text-accent-fill{fill:var(--fd-accent);stroke:none}.fd-text-icon-highlight .fd-text-swatch{fill:#ff0;stroke:none}.fd-text-icon-colour .fd-text-swatch{fill:#e81123;stroke:none}.fd-text-face{stroke:none}.fd-text-dot{fill:#7a4304;stroke:none}.fd-text-icon-emoji .fd-text-smile{stroke:#a0640c;stroke-width:1}.fd-text-eraser{fill:#e68497;stroke:none}.fd-text-cross{stroke:#e81123;stroke-width:1.2}.fd-text-glyph-bold{font:700 16px/1 var(--fd-font)}.fd-text-glyph-strike{font:400 15px/1 var(--fd-font);text-decoration:line-through;text-decoration-thickness:1px}.fd-text-icon-emoji{width:20px;height:20px}.fd-text-chevron{width:12px;height:12px;margin-inline-start:4px;fill:none;stroke:currentColor;stroke-width:1}.fd-text-tool-choice>.fd-text-chevron{color:var(--fd-muted)}.fd-md-card{display:grid;min-width:0;margin-block:12px 11px;margin-inline:calc(-1 * var(--fd-group-inset, 0px));padding:20px 16px;border-radius:4px;background:var(--fd-surface);box-shadow:var(--fd-depth-4)}.fd-text:not([data-editor=markdown])>.fd-md-card,.fd-text:not([data-editor=rich])>.fd-text-box{display:none}.fd-md-input,.fd-md-preview{display:block;width:100%;min-width:0;min-height:84px;box-sizing:border-box;margin:0;padding:1px 4px 4px;border:1px solid var(--fd-border);border-radius:4px;background:var(--fd-surface);color:var(--fd-text);font:14px/20px var(--fd-font);resize:vertical}.fd-md-input:focus,.fd-md-preview:focus{outline:none;border-color:var(--fd-focus)}.fd-md-card :is(.fd-md-input,.fd-md-preview),.fd-md-card :is(.fd-md-input,.fd-md-preview):focus{border-color:var(--fd-border);resize:none}.fd-md-card .fd-text-bar :is(.fd-text-accent,.fd-text-accent-fill){fill:currentColor}.fd-md-card .fd-text-bar .fd-text-accent-line{stroke:currentColor}.fd-md-card .fd-text-tool-choice>.fd-text-chevron{color:inherit;stroke-width:1.3;margin-inline:8px -4px}.fd-md-input[hidden],.fd-md-preview[hidden]{display:none}.fd-md-hint{display:flex;flex-wrap:wrap;align-items:center;gap:0 4px;margin:7px 0 0;color:var(--fd-muted);font-size:12px;line-height:16px}.fd-md-hint>.fd-icon{width:12px;height:12px;stroke-width:2}.fd-md-supported{color:var(--fd-text-link)}.fd-md-row{display:flex;align-items:center;min-width:0;margin-block-start:2px}.fd-md-row>.fd-text-bar{flex:1 1 auto;padding:0}.fd-md-preview-switch{display:inline-flex;align-items:center;gap:8px;flex:none;margin-inline-start:auto;padding:0 0 0 8px;padding-inline:8px 0;border:0;background:none;color:var(--fd-text);font:14px/20px var(--fd-font);cursor:pointer}.fd-md-track{position:relative;width:40px;height:20px;box-sizing:border-box;border:1px solid var(--fd-muted);border-radius:10px;background:var(--fd-surface)}.fd-md-track:after{content:\"\";position:absolute;inset-block-start:3px;inset-inline-start:4px;width:12px;height:12px;border-radius:50%;background:var(--fd-muted);transition:inset-inline-start .1s ease}.fd-md-preview-switch[aria-checked=true]>.fd-md-track{border-color:var(--fd-accent);background:var(--fd-accent)}.fd-md-preview-switch[aria-checked=true]>.fd-md-track:after{inset-inline-start:22px;background:var(--fd-accent-text, #fff)}.fd-md-field{position:relative;display:grid;min-width:0}.fd-md-view{min-height:50px;box-sizing:border-box;padding:2px 9px;border:1px solid transparent;border-radius:2px;line-height:20px;overflow-wrap:anywhere;cursor:text;outline:none}.fd-md-view:hover{border-color:var(--fd-border)}.fd-md-view:focus-visible{border-color:var(--fd-focus)}.fd-md-view[aria-readonly=true]{cursor:default;border-color:transparent}.fd-md-view.fd-blank:before{content:attr(data-placeholder);color:var(--fd-muted);font-style:italic}.fd-md-view[hidden]{display:none}.fd-form .fd-field:has(>.fd-md-field>.fd-field-tools:empty):has(>.fd-md-field>.fd-md-view.fd-blank:not([data-placeholder],[hidden])){display:none}.fd-form .fd-section[data-head]>.fd-grid:has(>.fd-field:only-child>.fd-md-field>.fd-field-tools:empty):has(>.fd-field:only-child>.fd-md-field>.fd-md-view.fd-blank:not([data-placeholder],[hidden])){padding-block-start:0}.fd-form .fd-section[data-head]:has(>.fd-grid>.fd-field:only-child>.fd-md-field>.fd-field-tools:empty):has(>.fd-grid>.fd-field:only-child>.fd-md-field>.fd-md-view.fd-blank:not([data-placeholder],[hidden])){margin-block-end:-3px}.fd-field-tools{display:flex;justify-content:flex-end;gap:2px}.fd-field-tools:not(:has(>:not([hidden]))){display:none}.fd-section-tools .fd-field-tool[hidden]{display:none}.fd-form .fd-section[data-head]>.fd-grid>.fd-field :is(.fd-text[data-toolbar=focus]>.fd-text-box,.fd-md-view){margin-inline:2px}.fd-form .fd-section[data-head]>.fd-grid>.fd-field .fd-text[data-toolbar=focus]>.fd-text-box{margin-block-start:1px}.fd-form .fd-section[data-head]>.fd-grid>.fd-field>.fd-label .fd-lock-wrap{height:16px;vertical-align:top;align-items:center}.fd-form .fd-section[data-head]>.fd-grid>.fd-field>.fd-label .fd-lock{height:16px}.fd-text-menu{z-index:60;display:grid;min-width:160px;box-sizing:border-box;padding:8px 0;border-radius:2px;background:var(--fd-surface);color:var(--fd-text);box-shadow:var(--fd-depth-8)}.fd-text-menu[hidden]{display:none}.fd-text-menu-item{display:flex;align-items:center;gap:10px;min-height:31px;box-sizing:border-box;padding:0 16px;padding-inline:16px;border:0;background:none;color:var(--fd-text);font:14px/20px var(--fd-font);text-align:start;white-space:nowrap;cursor:pointer}.fd-text-menu-item:hover,.fd-text-menu-item:focus-visible{background:var(--fd-text-hover)}.fd-text-menu-item>:is(svg,.fd-text-colour){width:16px;height:16px;flex:none}.fd-text-menu-item>svg.fd-icon{stroke-width:1.6}.fd-text-menu-item[aria-checked=true]{font-weight:600}.fd-text-colour{display:inline-block;box-sizing:border-box;border:1px solid color-mix(in srgb,var(--fd-text) 25%,transparent);border-radius:2px}.fd-text-colour-none{background:linear-gradient(to top right,transparent calc(50% - 1px),#d13438 calc(50% - 1px),#d13438 calc(50% + 1px),transparent calc(50% + 1px))}.fd-text-emoji{grid-template-columns:repeat(5,36px);min-width:0;padding:6px}.fd-text-emoji>.fd-text-menu-item{justify-content:center;min-height:32px;padding:0;font-size:18px}.fd-links-menu{width:223px}.fd-links-menu .fd-text-menu-item{gap:12px;padding-inline:14px}.fd-text-suggest{position:absolute;z-index:50;inset-inline-start:0;inset-block-start:100%;min-width:220px;max-width:100%;max-height:240px;overflow:auto;margin:4px 0 0;padding:4px 0;list-style:none;border-radius:2px;background:var(--fd-surface);box-shadow:var(--fd-depth-8)}.fd-text-suggest>li{padding:6px 12px;cursor:pointer}.fd-text-suggest>li[aria-selected=true]{background:var(--fd-accent-soft)}.fd-text-suggest>li.fd-empty{color:var(--fd-muted);cursor:default}.fd-links-box{display:grid;justify-items:start;min-width:0}.fd-links-add{display:inline-flex;align-items:center;gap:8px;height:31px;padding:0 13px;border:0;border-radius:2px;background:none;color:var(--fd-text);font:600 14px/20px var(--fd-font);cursor:pointer}.fd-links-add:hover{background:var(--fd-text-hover)}.fd-links-add:is(.fd-pressed,[aria-expanded=true]){background:var(--fd-text-pressed)}.fd-links-add>.fd-text-chevron{width:12px;height:12px;margin:0;stroke-width:1.2}.fd-links-add[hidden],.fd-links-list[hidden]{display:none}.fd-links-list{justify-self:stretch;display:grid;margin:0;padding:0;list-style:none}.fd-links-list>li{display:flex;align-items:center;gap:8px;min-height:32px;padding-inline:13px 0;border-block-end:1px solid var(--fd-border)}.fd-links-name{flex:1 1 auto;min-width:0;padding:0;border:0;background:none;color:var(--fd-text-link);font:inherit;text-align:start;overflow-wrap:anywhere;cursor:pointer}span.fd-links-name{color:var(--fd-text);cursor:default}.fd-links-remove{display:inline-grid;place-items:center;width:32px;height:32px;padding:0;border:0;border-radius:2px;background:none;color:var(--fd-text);cursor:pointer}.fd-links-remove:hover{background:var(--fd-text-hover)}.fd-links-remove>svg{width:14px;height:14px}.fd-links-help{position:relative;justify-self:stretch;display:block;padding:10px 12px;padding-inline:50px 12px;background:var(--fd-text-help);font-size:14px;line-height:17px;overflow-wrap:anywhere}.fd-links-help>p{margin:0}.fd-links-help-tile{display:grid;place-items:center;border-radius:2px;color:#fff;background:linear-gradient(color-mix(in srgb,var(--fd-tile) 88%,#fff),var(--fd-tile))}.fd-links-help-tile>.fd-icon{width:18px;height:18px;margin:0;stroke-width:1.6}.fd-links-help[hidden],.fd-links-empty[hidden]{display:none}.fd-links-empty{justify-self:stretch;padding:10px;background:var(--fd-text-help);line-height:17px}.fd-links-empty-link{padding:0;border:0;background:none;color:var(--fd-text-link);font:14px/17px var(--fd-font);text-align:start;text-decoration:underline;cursor:pointer}`;\n\n/** The sheet in a document, once, in its place among Fieldia's. */\nexport function installEditorStyles(doc: Document): void {\n installPartStyles(doc, 'fieldia-editor-styles', EDITOR_CSS, PART_RANK.text);\n}\n", "import type { JsonValue } from '@fieldia/core';\nimport { decorateLinks, formattedText, type TextReference } from './formatted-text';\nimport { drawIcon } from './icons';\nimport { fillIn, maker, setAttr } from './kind-parts';\nimport { WIDGET_LABELS } from './labels';\nimport { sanitizeHtml } from './sanitize';\nimport { TEXT_TOOLS, type TextTool } from './text-tools';\nimport type { Widget, WidgetContext } from './widgets';\n\n/**\n * A formatted text field drawn as a work item draws one. Its options:\n *\n * toolbar 'always' (true), 'focus' \u2014 no edge and no toolbar at rest, a\n * light box when pointed at, the accent box with the toolbar\n * inside it while worked in \u2014 or 'never' (false)\n * toolbarAt 'top' or 'bottom' (the foot unless said, with 'focus')\n * tools the tools, in order: bold \u2026 attach (text-tools.ts)\n * editor 'rich', or 'markdown': at rest the text as it reads, its\n * links opening in a tab of their own; a click on its words,\n * Enter, or Edit in its group's heading opens the Markdown\n * card; Done keeps what was typed, Escape puts back what it held\n * switchEditor a link under it to the other editor\n * mention { model }: people @mentioned, found with form.search\n * references [{ key, model, label, icon }]: records linked by \"#\", \"!\" \u2026\n *\n * Whichever the editor, the value is stored as clean HTML.\n */\n\nconst isTool = (tool: unknown): tool is TextTool => typeof tool === 'string' && (TEXT_TOOLS as readonly string[]).includes(tool);\nconst record = (value: JsonValue | undefined): Record<string, JsonValue> | null => (value !== null && typeof value === 'object' && !Array.isArray(value) ? value : null);\n\nexport function modernHtml(context: WidgetContext): Widget {\n const { form, name, node, id, document, labels = WIDGET_LABELS.en } = context;\n const make = maker(document);\n const options = node.options ?? {};\n const pageEditor = options['editor'] === 'markdown' ? 'markdown' : 'rich';\n const toolbar = options['toolbar'] === false || options['toolbar'] === 'never' ? 'never' : options['toolbar'] === 'focus' ? 'focus' : 'always';\n const tools = Array.isArray(options['tools']) ? options['tools'].filter(isTool) : undefined;\n const mention = record(options['mention']);\n const mentionModel = typeof mention?.['model'] === 'string' ? mention['model'] : null;\n const references: TextReference[] = (Array.isArray(options['references']) ? options['references'] : []).flatMap((given) => {\n const r = record(given);\n if (!r || typeof r['key'] !== 'string' || typeof r['model'] !== 'string' || typeof r['label'] !== 'string') return [];\n const model = r['model'];\n return [{ key: r['key'], label: r['label'], model, ...(typeof r['icon'] === 'string' ? { icon: r['icon'] } : {}), search: (query: string) => form.search(name, query, 8, { model }) }];\n });\n\n let editing = pageEditor === 'rich';\n let readonly = false;\n /** What the field held as editing began: Escape puts it back. */\n let before: string | null = null;\n\n const text = formattedText(document, {\n id: pageEditor === 'rich' ? id : `${id}-markdown`,\n labelledBy: `${id}-label`,\n placeholder: node.placeholder,\n labels,\n editor: pageEditor,\n tools,\n toolbar,\n ...(typeof options['toolbarAt'] === 'string' ? { toolbarAt: options['toolbarAt'] === 'top' ? 'top' : 'bottom' } : {}),\n switchEditor: options['switchEditor'] === true,\n ...(mentionModel ? { mention: { search: (query: string) => form.search(name, query, 8, { model: mentionModel }) } } : {}),\n references,\n onInput: (html) => form.setValue(name, html),\n onKey(event) {\n if (event.key !== 'Escape' || pageEditor !== 'markdown' || !editing) return false;\n event.preventDefault();\n event.stopPropagation();\n finish(false);\n return true;\n },\n });\n\n if (pageEditor === 'rich') {\n return {\n element: text.element,\n focus: () => text.focus(),\n destroy: () => text.destroy(),\n update(state) {\n readonly = state.readonly;\n text.setValue(typeof state.value === 'string' ? state.value : null);\n text.setReadonly(state.readonly);\n const box = text.input();\n setAttr(box, 'aria-invalid', String(state.invalid));\n setAttr(box, 'aria-describedby', state.describedBy || null);\n },\n };\n }\n\n // ---- Markdown: the text as it reads at rest, the card while it is edited ----\n const view = make('div', { class: 'fd-md-view', id, role: 'textbox', 'aria-multiline': 'true', 'aria-readonly': 'false', tabindex: '0', 'aria-labelledby': `${id}-label` });\n if (node.placeholder) view.setAttribute('data-placeholder', node.placeholder);\n const label = () => document.getElementById(`${id}-label`)?.textContent?.trim() || form.page.fields[name]?.label || name;\n const editButton = make('button', { type: 'button', class: 'fd-field-tool', 'data-tool': 'edit' });\n const doneButton = make('button', { type: 'button', class: 'fd-field-tool', 'data-tool': 'done', hidden: '' });\n const pencil = drawIcon(document, 'edit');\n const tick = drawIcon(document, 'check');\n if (pencil) editButton.append(pencil);\n if (tick) doneButton.append(tick);\n const toolBox = make('div', { class: 'fd-field-tools' }, editButton, doneButton);\n const element = make('div', { class: 'fd-md-field' }, toolBox, view, text.element);\n text.element.hidden = true;\n\n const name_ = () => {\n const words = fillIn(labels.editNamed, { name: label() });\n setAttr(editButton, 'aria-label', words);\n setAttr(editButton, 'title', words);\n setAttr(doneButton, 'aria-label', labels.doneEditing);\n setAttr(doneButton, 'title', labels.doneEditing);\n };\n name_();\n\n function render(value: string | null) {\n const clean = value ? sanitizeHtml(value, document) : '';\n const shown = decorateLinks(clean, document);\n if (view.innerHTML !== shown) view.innerHTML = shown;\n view.classList.toggle('fd-blank', !clean);\n }\n function start() {\n if (editing || readonly) return;\n editing = true;\n before = (form.getState().values[name] as string | null | undefined) ?? null;\n text.setValue(before);\n view.hidden = true;\n text.element.hidden = false;\n editButton.hidden = true;\n doneButton.hidden = false;\n element.setAttribute('data-editing', '');\n text.focus();\n }\n function finish(keep: boolean) {\n if (!editing) return;\n editing = false;\n if (!keep) form.setValue(name, before);\n view.hidden = false;\n text.element.hidden = true;\n editButton.hidden = readonly;\n doneButton.hidden = true;\n element.removeAttribute('data-editing');\n render((form.getState().values[name] as string | null | undefined) ?? null);\n view.focus();\n }\n editButton.addEventListener('click', start);\n doneButton.addEventListener('click', () => finish(true));\n view.addEventListener('click', (event) => {\n if ((event.target as Element).closest?.('a')) return;\n start();\n });\n view.addEventListener('keydown', (event) => {\n if (event.key !== 'Enter' || (event.target as Element).closest?.('a')) return;\n event.preventDefault();\n start();\n });\n\n return {\n element,\n tools: [editButton, doneButton],\n focus: () => (editing ? text.focus() : view.focus()),\n destroy: () => text.destroy(),\n update(state) {\n readonly = state.readonly;\n const value = typeof state.value === 'string' ? state.value : null;\n if (editing) text.setValue(value);\n else render(value);\n text.setReadonly(state.readonly);\n if (readonly && editing) finish(true);\n editButton.hidden = readonly || editing;\n setAttr(view, 'aria-readonly', String(readonly));\n setAttr(view, 'tabindex', readonly ? '-1' : '0');\n name_();\n for (const box of [view, text.input()]) {\n setAttr(box, 'aria-invalid', String(state.invalid));\n setAttr(box, 'aria-describedby', state.describedBy || null);\n }\n },\n };\n}\n", "import type { Field, RelatedRecord } from '@fieldia/core';\nimport { drawIcon } from './icons';\nimport { fillIn, maker, setAttr, setHidden } from './kind-parts';\nimport { WIDGET_LABELS } from './labels';\nimport { linkedWords } from './linked-words';\nimport { textMenu } from './text-menu';\nimport { chevron } from './text-tools';\nimport { installEditorStyles } from './styles-editor';\nimport type { WidgetFactory } from './widgets';\n\n/**\n * A many2many as a work item's links (`many2many.links`): \"Add link\" \u2014 a\n * menu of Existing item and New item (`add: 'menu'`), or a search at once\n * (`add: 'search'`) \u2014 then a row for each record linked, its name opening\n * it and \u00D7 taking it away, never deleting it. While none is linked, a light\n * box says what to link (`help`, with [words](address) links in it and an\n * icon before them, `helpIcon` \u2014 white on a tile of `helpTile`'s colour,\n * `#rrggbb`, as a tracker marks its code's links), or offers a link that\n * finds an existing record (`emptyLink`). `addLabel` words the button.\n *\n * Existing item searches with the dialog's Search more\u2026; New item opens a\n * new record of the relation in a dialog, and links it once saved.\n */\nexport const linksWidget: WidgetFactory = ({ form, name, field, node, id, document, labels = WIDGET_LABELS.en, dialogs }) => {\n installEditorStyles(document);\n const def = field as Extract<Field, { type: 'many2many' }>;\n const make = maker(document);\n const options = node.options ?? {};\n const words = (key: string) => (typeof options[key] === 'string' && (options[key] as string).trim() ? (options[key] as string) : null);\n const asMenu = options['add'] === 'menu';\n const addWords = words('addLabel') ?? labels.addLink;\n\n const add = make('button', { type: 'button', class: 'fd-links-add' }, make('span', {}, addWords));\n if (asMenu) add.append(chevron(document));\n const menu = asMenu ? textMenu(document, add, { label: addWords, align: 'end', className: 'fd-links-menu' }) : null;\n const list = make('ul', { class: 'fd-links-list' });\n const helpText = words('help');\n const drawn = typeof options['helpIcon'] === 'string' ? drawIcon(document, options['helpIcon']) : null;\n const tile = typeof options['helpTile'] === 'string' && /^#[0-9a-fA-F]{6}$/.test(options['helpTile']) ? options['helpTile'] : null;\n // Its icon in the muted colour, or white on a tile of the page's colour.\n const helpIcon = drawn && tile ? make('span', { class: 'fd-links-help-icon fd-links-help-tile', 'aria-hidden': 'true' }, drawn) : drawn;\n if (drawn && tile) helpIcon?.style.setProperty('--fd-tile', tile);\n else drawn?.classList.add('fd-links-help-icon');\n const help = helpText ? make('div', { class: 'fd-links-help' }, ...(helpIcon ? [helpIcon] : []), make('p', {}, ...linkedWords(document, helpText))) : null;\n const emptyWords = words('emptyLink');\n const emptyButton = emptyWords ? make('button', { type: 'button', class: 'fd-links-empty-link' }, emptyWords) : null;\n const empty = emptyButton ? make('div', { class: 'fd-links-empty' }, emptyButton) : null;\n const element = make('div', { class: 'fd-links-box', id, role: 'group' }, add, ...(menu ? [menu.element] : []), list, ...(help ? [help] : []), ...(empty ? [empty] : []));\n\n let readonly = false;\n let shown: RelatedRecord[] = [];\n const linked = () => (form.getState().values[name] as RelatedRecord[] | null) ?? [];\n const link = (record: RelatedRecord | null) => {\n if (!record || linked().some((r) => r.id === record.id)) return;\n form.setValue(name, [...linked(), { id: record.id, label: record.label }]);\n };\n\n async function existing() {\n if (!dialogs || readonly) return;\n link(await dialogs.searchMore({ title: def.label, search: (query, limit) => form.search(name, query, limit) }));\n }\n async function created() {\n if (!dialogs || readonly) return;\n link(await dialogs.openRecord(def.relation, { title: def.label }));\n }\n\n add.addEventListener('click', () => {\n if (!menu) return void existing();\n if (menu.isOpen()) return menu.close();\n const canMake = !!dialogs?.canOpen(def.relation);\n menu.open([\n { label: labels.existingItem, lead: drawIcon(document, 'link'), run: () => void existing() },\n ...(canMake ? [{ label: labels.newItem, lead: drawIcon(document, 'edit'), run: () => void created() }] : []),\n ]);\n });\n add.addEventListener('keydown', (event) => {\n if (menu && event.key === 'ArrowDown' && !menu.isOpen()) {\n event.preventDefault();\n add.click();\n }\n });\n emptyButton?.addEventListener('click', () => void existing());\n\n async function open(record: RelatedRecord) {\n const saved = await dialogs?.openRecord(def.relation, { recordId: record.id, title: record.label });\n if (saved && saved.label !== record.label) form.setValue(name, linked().map((r) => (r.id === record.id ? { id: r.id, label: saved.label } : r)));\n }\n\n function row(record: RelatedRecord): HTMLLIElement {\n const canOpen = !!dialogs?.canOpen(def.relation);\n const title = canOpen ? make('button', { type: 'button', class: 'fd-links-name' }, record.label) : make('span', { class: 'fd-links-name' }, record.label);\n if (canOpen) title.addEventListener('click', () => void open(record));\n const item = make('li', { 'data-record': String(record.id) }, title);\n if (!readonly) {\n const remove = make('button', { type: 'button', class: 'fd-links-remove', 'aria-label': fillIn(labels.remove, { name: record.label }), title: fillIn(labels.remove, { name: record.label }) });\n const cross = drawIcon(document, 'close');\n if (cross) remove.append(cross);\n remove.addEventListener('click', () => {\n const at = shown.indexOf(record);\n form.setValue(name, linked().filter((r) => r.id !== record.id));\n // The focus to the next row's \u00D7, else the one before, else Add link.\n queueMicrotask(() => ((list.querySelectorAll<HTMLElement>('.fd-links-remove')[Math.min(at, shown.length - 1)] ?? add) as HTMLElement).focus());\n });\n item.append(remove);\n }\n return item;\n }\n\n return {\n element,\n focus: () => add.focus(),\n destroy: () => menu?.close(false),\n update(state) {\n const now = (state.value as RelatedRecord[] | null) ?? [];\n const changed = now !== shown || readonly !== state.readonly;\n readonly = state.readonly;\n shown = now;\n setHidden(add, readonly || !dialogs);\n if (help) setHidden(help, now.length > 0);\n if (empty) setHidden(empty, now.length > 0 || readonly || !dialogs);\n setHidden(list, !now.length);\n if (changed) list.replaceChildren(...now.map(row));\n setAttr(element, 'aria-invalid', String(state.invalid));\n setAttr(element, 'aria-describedby', state.describedBy || null);\n },\n };\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["require__", "__commonJSMin", "exports", "module", "require__", "__commonJSMin", "exports", "module", "require__", "__commonJSMin", "exports", "module", "require__", "__commonJSMin", "exports", "module", "require__", "__commonJSMin", "exports", "module", "require__", "__commonJSMin", "exports", "module", "require__", "__commonJSMin", "exports", "module", "fieldia_text_exports", "__export", "decorateLinks", "formattedText", "htmlToMarkdown", "linksWidget", "markdownLoses", "markdownToHtml", "modernHtml", "textMenu", "import_icons", "import_kind_parts", "import_labels", "ESCAPES", "escapeHtml", "text", "c", "SAFE_LINK", "SAFE_IMAGE", "BARE_URL", "inlineMarkdown", "held", "hold", "html", "out", "_", "_ticks", "code", "whole", "alt", "src", "words", "href", "inlineMarks", "i", "HIGHLIGHT", "LIST_ITEM", "FENCE", "HEADING", "QUOTE", "RULE", "markdownToHtml", "markdown", "blocks", "lines", "line", "fence", "heading", "quoted", "next", "list", "para", "paragraph", "n", "last", "hard", "start", "first", "indent", "ordered", "items", "item", "own", "inner", "depth", "task", "body", "l", "itemBlocks", "tag", "nested", "lead", "BLOCK_TAGS", "escapeMarkdown", "htmlToMarkdown", "doc", "box", "blockChildren", "parent", "prefix", "parts", "inline", "flush", "inlineOf", "node", "md", "blockOf", "element", "li", "mark", "pad", "nodes", "inlineNode", "wrap", "core", "trail", "ticks", "most", "run", "highlightOnly", "markdownLoses", "style", "import_icons", "import_text_tool_names", "CHOOSING", "TOGGLES", "toolLabel", "tool", "labels", "PATHS", "MARKDOWN_PATHS", "SVG", "faces", "toolIcon", "doc", "icons", "iconName", "editor", "letters", "shared", "named", "svg", "drawing", "chevron", "moreIcon", "HIGHLIGHTS", "TEXT_COLOURS", "TEXT_SIZES", "EMOJI", "swatch", "colour", "box", "menus", "textMenu", "doc", "anchor", "options", "element", "items", "outside", "event", "close", "move", "to", "at", "item", "i", "place", "a", "origin", "own", "rtl", "end", "width", "wanted", "left", "open", "choices", "how", "choice", "words", "checked", "giveBack", "home", "key", "step", "import_sanitize", "import_styles", "EDITOR_CSS", "installEditorStyles", "doc", "editors", "isEmpty", "html", "formattedText", "doc", "options", "installEditorStyles", "make", "labels", "n", "references", "toolbarWhen", "editor", "readonly", "last", "element", "name", "box", "area", "address", "applyLink", "linkRow", "richBox", "markdown", "preview", "info", "hint", "previewSwitch", "mdRow", "mdCard", "said", "switcher", "under", "askWords", "askYes", "askNo", "ask", "suggest", "sayTimer", "say", "text", "emit", "markdownToHtml", "value", "show", "clean", "htmlToMarkdown", "lastRange", "restore", "selection", "exec", "command", "selectedLink", "node", "link", "wrapMarkdown", "before", "after", "empty", "start", "end", "picked", "prefixMarkdown", "mark", "endAt", "lines", "line", "i", "insertMarkdown", "picker", "MAX_PICTURE", "insertPicture", "file", "reader", "src", "img", "event", "files", "run", "tool", "reference", "setPreview", "runMarkdown", "item", "range", "startSuggesting", "words", "choicesOf", "names", "md", "HIGHLIGHTS", "at", "swatch", "colour", "TEXT_COLOURS", "TEXT_SIZES", "size", "resize", "level", "EMOJI", "emoji", "spanStyles", "marked", "kept", "span", "font", "stopsFor", "list", "stops", "kinds", "label", "kindWords", "toolLabel", "choosing", "CHOOSING", "chevroned", "button", "toolIcon", "chevron", "TOGGLES", "stop", "from", "textMenu", "moreMenuFor", "kind", "fromMore", "more", "menu", "toolbar", "extra", "bar", "moreIcon", "moreMenu", "r", "shown", "e", "b", "all", "rtl", "step", "next", "fit", "room", "gap", "widths", "others", "sum", "w", "used", "count", "watcher", "idle", "richBar", "mdBar", "richTools", "mdTools", "drawRich", "parts", "drawMarkdown", "on", "decorateLinks", "setEditor", "asking", "markdownLoses", "draw", "keepEditor", "url", "keys", "found", "active", "suggesting", "closeSuggestions", "key", "lookUp", "typed", "pattern", "k", "match", "search", "mine", "results", "drawSuggestions", "option", "suggestionWords", "pick", "space", "suggestKeys", "reflect", "typing", "icon", "out", "import_icons", "import_kind_parts", "import_labels", "import_sanitize", "isTool", "tool", "record", "value", "modernHtml", "context", "form", "name", "node", "id", "document", "labels", "make", "options", "pageEditor", "toolbar", "tools", "mention", "mentionModel", "references", "given", "r", "model", "query", "editing", "readonly", "before", "text", "formattedText", "html", "event", "finish", "state", "box", "view", "label", "editButton", "doneButton", "pencil", "tick", "toolBox", "element", "name_", "words", "render", "clean", "shown", "decorateLinks", "start", "keep", "import_icons", "import_kind_parts", "import_labels", "import_linked_words", "linksWidget", "form", "name", "field", "node", "id", "document", "labels", "dialogs", "installEditorStyles", "def", "make", "options", "words", "key", "asMenu", "addWords", "add", "chevron", "menu", "textMenu", "list", "helpText", "drawn", "tile", "helpIcon", "help", "emptyWords", "emptyButton", "empty", "element", "readonly", "shown", "linked", "link", "record", "r", "existing", "query", "limit", "created", "canMake", "event", "open", "saved", "row", "canOpen", "title", "item", "remove", "cross", "at", "state", "now", "changed"]
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fieldia/viewer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "Mount a Fieldia page in any web page: plain DOM, no framework.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://fieldia.dev",
|
|
@@ -24,11 +24,15 @@
|
|
|
24
24
|
"./bundle/fieldia.ar.js": "./bundle/fieldia.ar.js",
|
|
25
25
|
"./bundle/fieldia.de.js": "./bundle/fieldia.de.js",
|
|
26
26
|
"./bundle/fieldia.fr.js": "./bundle/fieldia.fr.js",
|
|
27
|
+
"./bundle/fieldia.filters.js": "./bundle/fieldia.filters.js",
|
|
28
|
+
"./bundle/fieldia.head.js": "./bundle/fieldia.head.js",
|
|
29
|
+
"./bundle/fieldia.path.js": "./bundle/fieldia.path.js",
|
|
30
|
+
"./bundle/fieldia.text.js": "./bundle/fieldia.text.js",
|
|
27
31
|
"./package.json": "./package.json"
|
|
28
32
|
},
|
|
29
33
|
"dependencies": {
|
|
30
|
-
"@fieldia/core": "0.
|
|
31
|
-
"@fieldia/widgets": "0.
|
|
34
|
+
"@fieldia/core": "0.20.0",
|
|
35
|
+
"@fieldia/widgets": "0.20.0",
|
|
32
36
|
"tslib": "^2.8.1"
|
|
33
37
|
},
|
|
34
38
|
"sideEffects": false,
|
package/src/index.d.mts
CHANGED
|
@@ -2,7 +2,8 @@ export * from './lib/viewer.mjs';
|
|
|
2
2
|
export * from './lib/dialog.mjs';
|
|
3
3
|
export { addLanguage, type LanguageWords } from './lib/add-language.mjs';
|
|
4
4
|
export { installListStyles } from './lib/list-styles.mjs';
|
|
5
|
-
export
|
|
5
|
+
export { filtersPart, headPart, loadParts, partsFor, type FiltersPart, type HeadPart } from './lib/viewer-parts.mjs';
|
|
6
|
+
export type { ListViewContext, ListViewFactory, ListViewPart, OpenRowOptions } from './lib/list.mjs';
|
|
6
7
|
export type { MapPart, MapPartContext, MapPartFactory } from './lib/map-part.mjs';
|
|
7
8
|
export { accentShades, applyLook, contrast, skinFor, THEME_SKINS, TOKEN_NAMES, wearTokens, type AccentShades, type TokenName, type Tokens } from './lib/look.mjs';
|
|
8
9
|
export { labelPlace, planSection, type Place, type SectionPlan } from './lib/place.mjs';
|
package/src/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ export * from './lib/viewer';
|
|
|
2
2
|
export * from './lib/dialog';
|
|
3
3
|
export { addLanguage, type LanguageWords } from './lib/add-language';
|
|
4
4
|
export { installListStyles } from './lib/list-styles';
|
|
5
|
-
export
|
|
5
|
+
export { filtersPart, headPart, loadParts, partsFor, type FiltersPart, type HeadPart } from './lib/viewer-parts';
|
|
6
|
+
export type { ListViewContext, ListViewFactory, ListViewPart, OpenRowOptions } from './lib/list';
|
|
6
7
|
export type { MapPart, MapPartContext, MapPartFactory } from './lib/map-part';
|
|
7
8
|
export { accentShades, applyLook, contrast, skinFor, THEME_SKINS, TOKEN_NAMES, wearTokens, type AccentShades, type TokenName, type Tokens } from './lib/look';
|
|
8
9
|
export { labelPlace, planSection, type Place, type SectionPlan } from './lib/place';
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.planSection = exports.labelPlace = exports.wearTokens = exports.TOKEN_NAMES = exports.THEME_SKINS = exports.skinFor = exports.contrast = exports.applyLook = exports.accentShades = exports.installListStyles = exports.addLanguage = void 0;
|
|
3
|
+
exports.planSection = exports.labelPlace = exports.wearTokens = exports.TOKEN_NAMES = exports.THEME_SKINS = exports.skinFor = exports.contrast = exports.applyLook = exports.accentShades = exports.partsFor = exports.loadParts = exports.headPart = exports.filtersPart = exports.installListStyles = exports.addLanguage = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
tslib_1.__exportStar(require("./lib/viewer"), exports);
|
|
6
6
|
tslib_1.__exportStar(require("./lib/dialog"), exports);
|
|
@@ -8,6 +8,11 @@ var add_language_1 = require("./lib/add-language");
|
|
|
8
8
|
Object.defineProperty(exports, "addLanguage", { enumerable: true, get: function () { return add_language_1.addLanguage; } });
|
|
9
9
|
var list_styles_1 = require("./lib/list-styles");
|
|
10
10
|
Object.defineProperty(exports, "installListStyles", { enumerable: true, get: function () { return list_styles_1.installListStyles; } });
|
|
11
|
+
var viewer_parts_1 = require("./lib/viewer-parts");
|
|
12
|
+
Object.defineProperty(exports, "filtersPart", { enumerable: true, get: function () { return viewer_parts_1.filtersPart; } });
|
|
13
|
+
Object.defineProperty(exports, "headPart", { enumerable: true, get: function () { return viewer_parts_1.headPart; } });
|
|
14
|
+
Object.defineProperty(exports, "loadParts", { enumerable: true, get: function () { return viewer_parts_1.loadParts; } });
|
|
15
|
+
Object.defineProperty(exports, "partsFor", { enumerable: true, get: function () { return viewer_parts_1.partsFor; } });
|
|
11
16
|
var look_1 = require("./lib/look");
|
|
12
17
|
Object.defineProperty(exports, "accentShades", { enumerable: true, get: function () { return look_1.accentShades; } });
|
|
13
18
|
Object.defineProperty(exports, "applyLook", { enumerable: true, get: function () { return look_1.applyLook; } });
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/viewer/src/index.ts"],"names":[],"mappings":";;;;AAAA,uDAA6B;AAC7B,uDAA6B;AAC7B,mDAAqE;AAA5D,2GAAA,WAAW,OAAA;AACpB,iDAAsD;AAA7C,gHAAA,iBAAiB,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/viewer/src/index.ts"],"names":[],"mappings":";;;;AAAA,uDAA6B;AAC7B,uDAA6B;AAC7B,mDAAqE;AAA5D,2GAAA,WAAW,OAAA;AACpB,iDAAsD;AAA7C,gHAAA,iBAAiB,OAAA;AAC1B,mDAAiH;AAAxG,2GAAA,WAAW,OAAA;AAAE,wGAAA,QAAQ,OAAA;AAAE,yGAAA,SAAS,OAAA;AAAE,wGAAA,QAAQ,OAAA;AAGnD,mCAA8J;AAArJ,oGAAA,YAAY,OAAA;AAAE,iGAAA,SAAS,OAAA;AAAE,gGAAA,QAAQ,OAAA;AAAE,+FAAA,OAAO,OAAA;AAAE,mGAAA,WAAW,OAAA;AAAE,mGAAA,WAAW,OAAA;AAAE,kGAAA,UAAU,OAAA;AACzF,qCAAoF;AAA3E,mGAAA,UAAU,OAAA;AAAE,oGAAA,WAAW,OAAA"}
|
package/src/index.mjs
CHANGED
|
@@ -2,6 +2,7 @@ export * from './lib/viewer.mjs';
|
|
|
2
2
|
export * from './lib/dialog.mjs';
|
|
3
3
|
export { addLanguage } from './lib/add-language.mjs';
|
|
4
4
|
export { installListStyles } from './lib/list-styles.mjs';
|
|
5
|
+
export { filtersPart, headPart, loadParts, partsFor } from './lib/viewer-parts.mjs';
|
|
5
6
|
export { accentShades, applyLook, contrast, skinFor, THEME_SKINS, TOKEN_NAMES, wearTokens } from './lib/look.mjs';
|
|
6
7
|
export { labelPlace, planSection } from './lib/place.mjs';
|
|
7
8
|
//# sourceMappingURL=index.mjs.map
|
package/src/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../../../libs/viewer/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAsB,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../../../libs/viewer/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAsB,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAmC,MAAM,oBAAoB,CAAC;AAGjH,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAkD,MAAM,YAAY,CAAC;AAC9J,OAAO,EAAE,UAAU,EAAE,WAAW,EAAgC,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ActionStep, ButtonNode, Form, FormState, RunResult, Tone } from '@fieldia/core';
|
|
2
|
+
import type { IconSet } from '@fieldia/widgets';
|
|
3
|
+
import type { El } from './dom.mjs';
|
|
4
|
+
import type { ViewerLabels } from './labels.mjs';
|
|
5
|
+
/** What a button of the newer kinds needs of the viewer that draws it. */
|
|
6
|
+
export interface ButtonContext {
|
|
7
|
+
doc: Document;
|
|
8
|
+
el: El;
|
|
9
|
+
form: Form;
|
|
10
|
+
labels: ViewerLabels;
|
|
11
|
+
icons?: IconSet;
|
|
12
|
+
uid(id: string): string;
|
|
13
|
+
withIcon(name: string | undefined, text: string): (Node | string)[];
|
|
14
|
+
/** A press: one run at a time, the button busy meanwhile. */
|
|
15
|
+
press(button: HTMLElement, run: () => Promise<RunResult>): Promise<void>;
|
|
16
|
+
say(message: string, tone: Tone): void;
|
|
17
|
+
/** Its updater, run at every change of the form. */
|
|
18
|
+
watch(update: (state: FormState) => void): void;
|
|
19
|
+
cleanups: (() => void)[];
|
|
20
|
+
}
|
|
21
|
+
/** Whether a button asks for more than words and steps: its icon alone, a toggle, a menu, a look that follows the record's changes. */
|
|
22
|
+
export declare function isRichButton(node: ButtonNode): boolean;
|
|
23
|
+
/** Steps that only put back what changed: Undo's. */
|
|
24
|
+
export declare const onlyResets: (steps: readonly ActionStep[] | undefined, action?: string) => boolean;
|
|
25
|
+
/**
|
|
26
|
+
* A press that has nothing to do says so instead: Undo with nothing changed
|
|
27
|
+
* ("Nothing has changed."), never a control greyed out without a reason.
|
|
28
|
+
* True when it said so.
|
|
29
|
+
*/
|
|
30
|
+
export declare function nothingToUndo(node: ButtonNode, form: Form, say: (message: string, tone: Tone) => void, labels: ViewerLabels): boolean;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ActionStep, ButtonNode, Form, FormState, RunResult, Tone } from '@fieldia/core';
|
|
2
|
+
import type { IconSet } from '@fieldia/widgets';
|
|
3
|
+
import type { El } from './dom';
|
|
4
|
+
import type { ViewerLabels } from './labels';
|
|
5
|
+
/** What a button of the newer kinds needs of the viewer that draws it. */
|
|
6
|
+
export interface ButtonContext {
|
|
7
|
+
doc: Document;
|
|
8
|
+
el: El;
|
|
9
|
+
form: Form;
|
|
10
|
+
labels: ViewerLabels;
|
|
11
|
+
icons?: IconSet;
|
|
12
|
+
uid(id: string): string;
|
|
13
|
+
withIcon(name: string | undefined, text: string): (Node | string)[];
|
|
14
|
+
/** A press: one run at a time, the button busy meanwhile. */
|
|
15
|
+
press(button: HTMLElement, run: () => Promise<RunResult>): Promise<void>;
|
|
16
|
+
say(message: string, tone: Tone): void;
|
|
17
|
+
/** Its updater, run at every change of the form. */
|
|
18
|
+
watch(update: (state: FormState) => void): void;
|
|
19
|
+
cleanups: (() => void)[];
|
|
20
|
+
}
|
|
21
|
+
/** Whether a button asks for more than words and steps: its icon alone, a toggle, a menu, a look that follows the record's changes. */
|
|
22
|
+
export declare function isRichButton(node: ButtonNode): boolean;
|
|
23
|
+
/** Steps that only put back what changed: Undo's. */
|
|
24
|
+
export declare const onlyResets: (steps: readonly ActionStep[] | undefined, action?: string) => boolean;
|
|
25
|
+
/**
|
|
26
|
+
* A press that has nothing to do says so instead: Undo with nothing changed
|
|
27
|
+
* ("Nothing has changed."), never a control greyed out without a reason.
|
|
28
|
+
* True when it said so.
|
|
29
|
+
*/
|
|
30
|
+
export declare function nothingToUndo(node: ButtonNode, form: Form, say: (message: string, tone: Tone) => void, labels: ViewerLabels): boolean;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.onlyResets = void 0;
|
|
4
|
+
exports.isRichButton = isRichButton;
|
|
5
|
+
exports.nothingToUndo = nothingToUndo;
|
|
6
|
+
/** Whether a button asks for more than words and steps: its icon alone, a toggle, a menu, a look that follows the record's changes. */
|
|
7
|
+
function isRichButton(node) {
|
|
8
|
+
return !!(node.iconOnly || node.pressed !== undefined || node.menu?.length || node.primaryWhenChanged);
|
|
9
|
+
}
|
|
10
|
+
/** Steps that only put back what changed: Undo's. */
|
|
11
|
+
const onlyResets = (steps, action) => !!steps?.length && action === undefined && steps.every((step) => step.do === 'reset');
|
|
12
|
+
exports.onlyResets = onlyResets;
|
|
13
|
+
/**
|
|
14
|
+
* A press that has nothing to do says so instead: Undo with nothing changed
|
|
15
|
+
* ("Nothing has changed."), never a control greyed out without a reason.
|
|
16
|
+
* True when it said so.
|
|
17
|
+
*/
|
|
18
|
+
function nothingToUndo(node, form, say, labels) {
|
|
19
|
+
if (!(0, exports.onlyResets)(node.steps, node.action) || form.getState().dirty.length)
|
|
20
|
+
return false;
|
|
21
|
+
say(labels.nothingChanged, 'info');
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=button-parts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button-parts.js","sourceRoot":"","sources":["../../../../../libs/viewer/src/lib/button-parts.ts"],"names":[],"mappings":";;;AAuBA,oCAEC;AAUD,sCAIC;AAjBD,uIAAuI;AACvI,SAAgB,YAAY,CAAC,IAAgB;IAC3C,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,IAAI,CAAC,kBAAkB,CAAC,CAAC;AACzG,CAAC;AAED,qDAAqD;AAC9C,MAAM,UAAU,GAAG,CAAC,KAAwC,EAAE,MAAe,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,IAAI,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC;AAAlK,QAAA,UAAU,cAAwJ;AAE/K;;;;GAIG;AACH,SAAgB,aAAa,CAAC,IAAgB,EAAE,IAAU,EAAE,GAA0C,EAAE,MAAoB;IAC1H,IAAI,CAAC,IAAA,kBAAU,EAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACvF,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IACnC,OAAO,IAAI,CAAC;AACd,CAAC"}
|