@exsto/ds 0.0.1-rc.8 → 0.0.1-rc.9

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.
Files changed (37) hide show
  1. package/README.md +13 -0
  2. package/dist/chunks/date-range-picker-BvCOmQki.js +204 -0
  3. package/dist/chunks/date-range-picker-BvCOmQki.js.map +1 -0
  4. package/dist/chunks/input-9HRdsve1.js +169 -0
  5. package/dist/chunks/input-9HRdsve1.js.map +1 -0
  6. package/dist/chunks/{toggle-C2c5oDaE.js → toggle-B6VBlpwp.js} +4 -149
  7. package/dist/chunks/toggle-B6VBlpwp.js.map +1 -0
  8. package/dist/date-picker.js +331 -0
  9. package/dist/date-picker.js.map +1 -0
  10. package/dist/ds/src/date-picker.d.ts +9 -0
  11. package/dist/index.js +60 -188
  12. package/dist/index.js.map +1 -1
  13. package/dist/rich-text-editor.js +2 -1
  14. package/dist/rich-text-editor.js.map +1 -1
  15. package/dist/styles.css +125 -0
  16. package/dist/ui/src/components/edyn/animated-number/animated-number.d.ts +5 -5
  17. package/dist/ui/src/components/edyn/audio-player/audio-player.d.ts +3 -2
  18. package/dist/ui/src/components/edyn/date-picker/date-picker.d.ts +54 -0
  19. package/dist/ui/src/components/edyn/date-picker/date-text.d.ts +40 -0
  20. package/dist/ui/src/components/edyn/date-picker/date-text.test.d.ts +1 -0
  21. package/dist/ui/src/components/edyn/date-picker/index.d.ts +2 -0
  22. package/dist/ui/src/components/edyn/date-range-picker/date-range-picker.d.ts +5 -3
  23. package/dist/ui/src/components/edyn/initials-avatar/initials-avatar.d.ts +3 -2
  24. package/dist/ui/src/components/edyn/multi-select/multi-select.d.ts +12 -2
  25. package/dist/ui/src/components/edyn/progress-line/progress-line.d.ts +3 -3
  26. package/dist/ui/src/components/edyn/video-player/video-player.d.ts +2 -2
  27. package/dist/ui/src/components/forwarded-props.test.d.ts +8 -0
  28. package/dist/ui/src/components/ui/accordion/accordion.d.ts +9 -8
  29. package/dist/ui/src/components/ui/badge/badge.d.ts +1 -1
  30. package/dist/ui/src/components/ui/button/button.d.ts +1 -1
  31. package/dist/ui/src/components/ui/input-group/input-group.d.ts +1 -1
  32. package/dist/ui/src/components/ui/pagination/pagination.d.ts +3 -2
  33. package/dist/ui/src/components/ui/tabs/tabs.d.ts +9 -8
  34. package/dist/ui/src/lib/first-weekday.d.ts +6 -0
  35. package/dist/ui/src/lib/first-weekday.test.d.ts +1 -0
  36. package/package.json +5 -1
  37. package/dist/chunks/toggle-C2c5oDaE.js.map +0 -1
@@ -1,4 +1,5 @@
1
- import { B as cn, C as RICH_TEXT_ATTRIBUTES, E as isAllowedRichTextHref, L as PopoverTrigger, M as Popover, N as PopoverContent, O as popupItemClass, R as Button, T as RICH_TEXT_LINK_PROTOCOLS, _ as DropdownMenuTrigger, a as DropdownMenuContent, k as ScrollArea, n as toggleVariants, r as DropdownMenu, s as DropdownMenuItem, v as Input, w as RICH_TEXT_ELEMENTS, y as RICH_TEXT_BODY_CLASS } from "./chunks/toggle-C2c5oDaE.js";
1
+ import { c as Button, n as Popover, r as PopoverContent, s as PopoverTrigger, t as Input, u as cn } from "./chunks/input-9HRdsve1.js";
2
+ import { C as RICH_TEXT_ELEMENTS, D as popupItemClass, O as ScrollArea, S as RICH_TEXT_ATTRIBUTES, T as isAllowedRichTextHref, _ as DropdownMenuTrigger, a as DropdownMenuContent, n as toggleVariants, r as DropdownMenu, s as DropdownMenuItem, v as RICH_TEXT_BODY_CLASS, w as RICH_TEXT_LINK_PROTOCOLS } from "./chunks/toggle-B6VBlpwp.js";
2
3
  import { useCallback, useEffect, useId, useImperativeHandle, useMemo, useReducer, useRef, useState } from "react";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
5
  import { IconBold, IconItalic, IconLink, IconList, IconListNumbers, IconLoader2, IconSeparatorHorizontal, IconUnderline, IconVariable } from "@tabler/icons-react";
@@ -1 +1 @@
1
- {"version":3,"file":"rich-text-editor.js","names":[],"sources":["../../ui/src/components/edyn/rich-text-editor/serialize.ts","../../ui/src/components/edyn/rich-text-editor/extensions.ts","../../ui/src/components/edyn/rich-text-editor/mention-list.tsx","../../ui/src/components/edyn/rich-text-editor/sync.ts","../../ui/src/components/edyn/rich-text-editor/toolbar.tsx","../../ui/src/components/edyn/rich-text-editor/types.ts","../../ui/src/components/edyn/rich-text-editor/rich-text-editor.tsx"],"sourcesContent":["import { type DOMOutputSpec, DOMSerializer, type Node as TProseNode } from '@tiptap/pm/model';\nimport type { IRichTextMention } from './types';\n\nexport type TMentionToText = NonNullable<IRichTextMention['toText']>;\n\n// A serializer can only return elements, so a mention leaves as one and is unwrapped to its text below.\nconst MENTION_MARK = 'data-rich-text-mention';\n\nexport const defaultMentionToText: TMentionToText = (item) => `@${item.id}`;\n\n/**\n * The document as HTML. Not `editor.getHTML()`: that would write a mention as its chip element, and\n * the HTML must carry the plain text the app chose (`@person@example.test`) and nothing else.\n */\nexport const serializeDocument = (doc: TProseNode, toText: TMentionToText): string => {\n const schema = doc.type.schema;\n const nodes = {\n ...DOMSerializer.nodesFromSchema(schema),\n mention: (node: TProseNode): DOMOutputSpec => [\n 'span',\n { [MENTION_MARK]: '' },\n toText({ id: String(node.attrs.id ?? ''), label: String(node.attrs.label ?? '') }),\n ],\n };\n const serializer = new DOMSerializer(nodes, DOMSerializer.marksFromSchema(schema));\n const container = document.createElement('div');\n container.appendChild(serializer.serializeFragment(doc.content));\n for (const element of Array.from(container.querySelectorAll(`[${MENTION_MARK}]`))) {\n element.replaceWith(document.createTextNode(element.textContent ?? ''));\n }\n return container.innerHTML;\n};\n\n/** No text and no mention. A document of blank paragraphs, spaces and line breaks is empty too. */\nexport const isDocumentEmpty = (doc: TProseNode): boolean => {\n if (doc.textContent.trim() !== '') {\n return false;\n }\n let hasMention = false;\n doc.descendants((node) => {\n if (node.type.name === 'mention') {\n hasMention = true;\n }\n return !hasMention;\n });\n return !hasMention;\n};\n\n/** Characters the HTML text will have: a mention counts as the text it is written as. */\nexport const countCharacters = (doc: TProseNode, toText: TMentionToText): number => {\n let total = 0;\n doc.descendants((node) => {\n if (node.isText) {\n total += node.text?.length ?? 0;\n } else if (node.type.name === 'mention') {\n total += toText({ id: String(node.attrs.id ?? ''), label: String(node.attrs.label ?? '') }).length;\n } else if (node.type.name === 'hardBreak') {\n total += 1;\n }\n return true;\n });\n return total;\n};\n","import { isAllowedRichTextHref } from '@edyn/ui/components/edyn/rich-text-content/allow-list';\nimport { Extension, mergeAttributes } from '@tiptap/core';\nimport { Bold } from '@tiptap/extension-bold';\nimport { Document } from '@tiptap/extension-document';\nimport { HardBreak } from '@tiptap/extension-hard-break';\nimport { HorizontalRule } from '@tiptap/extension-horizontal-rule';\nimport { Italic } from '@tiptap/extension-italic';\nimport { Link } from '@tiptap/extension-link';\nimport { BulletList, ListItem, OrderedList } from '@tiptap/extension-list';\nimport { Mention } from '@tiptap/extension-mention';\nimport { Paragraph } from '@tiptap/extension-paragraph';\nimport { Text } from '@tiptap/extension-text';\nimport { Underline } from '@tiptap/extension-underline';\nimport { UndoRedo } from '@tiptap/extensions';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport type { SuggestionKeyDownProps, SuggestionProps } from '@tiptap/suggestion';\nimport { countCharacters, type TMentionToText } from './serialize';\nimport type { IRichTextMentionItem } from './types';\n\n/** What the editor needs from the component while it runs. Held in a ref, so the extensions are built once. */\nexport interface IEditorHost {\n mentionEnabled: () => boolean;\n maxLength: () => number | undefined;\n toText: () => TMentionToText;\n onSuggestion: (props: SuggestionProps<IRichTextMentionItem, IRichTextMentionItem> | null) => void;\n onSuggestionKey: (props: SuggestionKeyDownProps) => boolean;\n}\n\nconst MENTION_CHIP_CLASS = 'rounded-sm bg-primary/10 px-1 py-0.5 font-medium text-primary';\n\nconst limitKey = new PluginKey('richTextMaxLength');\n\n/** Refuses an edit that would take the text over the limit (a paste included) and lets one that shortens it through. */\nconst maxLengthExtension = (host: IEditorHost) =>\n Extension.create({\n name: 'maxLength',\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: limitKey,\n filterTransaction: (tr, state) => {\n const limit = host.maxLength();\n if (!tr.docChanged || limit === undefined) {\n return true;\n }\n const next = countCharacters(tr.doc, host.toText());\n return next <= limit || next <= countCharacters(state.doc, host.toText());\n },\n }),\n ];\n },\n });\n\n/**\n * The editor's whole schema: paragraph, line break, bold, italic, underline, bullet and numbered lists, link, and the\n * mention chip. Whatever else arrives (a paste, `value`) is not in the schema, so ProseMirror drops the markup and keeps\n * the text.\n */\nexport const buildExtensions = (host: IEditorHost) => [\n Document,\n Paragraph,\n Text,\n HardBreak,\n Bold,\n Italic,\n Underline,\n BulletList,\n // A list is numbered from 1; the `start` it would otherwise keep is an attribute outside the allow-list.\n OrderedList.extend({\n addAttributes() {\n return {};\n },\n }),\n ListItem,\n HorizontalRule,\n Link.extend({\n addAttributes() {\n return {\n href: {\n default: null,\n parseHTML: (element) => element.getAttribute('href'),\n renderHTML: (attributes) => (attributes.href ? { href: attributes.href } : {}),\n },\n };\n },\n }).configure({\n openOnClick: false,\n autolink: true,\n linkOnPaste: true,\n defaultProtocol: 'https',\n protocols: ['mailto'],\n isAllowedUri: (url) => isAllowedRichTextHref(url),\n HTMLAttributes: { rel: null, target: null, class: null },\n }),\n UndoRedo,\n maxLengthExtension(host),\n Mention.extend({\n addAttributes() {\n return {\n id: {\n default: null,\n parseHTML: (element) => element.getAttribute('data-id'),\n renderHTML: (attributes) => (attributes.id ? { 'data-id': attributes.id } : {}),\n },\n label: {\n default: null,\n parseHTML: (element) => element.getAttribute('data-label'),\n renderHTML: (attributes) => (attributes.label ? { 'data-label': attributes.label } : {}),\n },\n };\n },\n }).configure({\n HTMLAttributes: { class: MENTION_CHIP_CLASS },\n renderText: ({ node }) => `@${node.attrs.label ?? node.attrs.id}`,\n renderHTML: ({ options, node }) => ['span', mergeAttributes(options.HTMLAttributes), `@${node.attrs.label ?? node.attrs.id}`],\n suggestion: {\n char: '@',\n allow: () => host.mentionEnabled(),\n items: () => [],\n command: ({ editor, range, props }) => {\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n { type: 'mention', attrs: { id: props.id, label: props.label } },\n { type: 'text', text: ' ' },\n ])\n .run();\n },\n render: () => ({\n onStart: (props) => host.onSuggestion(props),\n onUpdate: (props) => host.onSuggestion(props),\n onKeyDown: (props) => host.onSuggestionKey(props),\n onExit: () => host.onSuggestion(null),\n }),\n },\n }),\n];\n","import { Popover, PopoverContent } from '@edyn/ui/components/ui/popover';\nimport { ScrollArea } from '@edyn/ui/components/ui/scroll-area';\nimport { popupItemClass } from '@edyn/ui/lib/popup-list';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { IconLoader2 } from '@tabler/icons-react';\nimport { type RefObject, useCallback, useEffect, useRef, useState } from 'react';\nimport type { IRichTextLabels, IRichTextMention, IRichTextMentionItem, IRichTextMentionPage } from './types';\n\ninterface IListState {\n status: 'loading' | 'ready' | 'error';\n items: IRichTextMentionItem[];\n page: number;\n hasMore: boolean;\n more: boolean;\n active: number;\n}\n\nconst FIRST: IListState = { status: 'loading', items: [], page: 1, hasMore: false, more: false, active: 0 };\n\nconst toPage = (result: IRichTextMentionItem[] | IRichTextMentionPage): IRichTextMentionPage =>\n Array.isArray(result) ? { items: result, hasMore: false } : result;\n\nexport interface IMentionListProps {\n query: string;\n /** Where the @ was typed. */\n rect: (() => DOMRect | null) | null;\n config: IRichTextMention;\n labels: IRichTextLabels;\n listId: string;\n onPick: (item: IRichTextMentionItem) => void;\n /** The editor keeps focus, so the list is driven by its keys: the editor calls this one. */\n keyHandler: RefObject<((event: KeyboardEvent) => boolean) | null>;\n /** The id of the option the editor should name as `aria-activedescendant`. */\n onActiveChange: (optionId: string | undefined) => void;\n}\n\nconst optionId = (listId: string, index: number): string => `${listId}-${index}`;\n\n/** The list that opens under the caret when the writer types @. */\nexport const MentionList = ({ query, rect, config, labels, listId, onPick, keyHandler, onActiveChange }: IMentionListProps) => {\n const [state, setState] = useState<IListState>(FIRST);\n const refSearch = useRef(config.search);\n refSearch.current = config.search;\n const refFirst = useRef(true);\n const refController = useRef<AbortController | null>(null);\n const refViewport = useRef<HTMLDivElement | null>(null);\n const debounce = config.debounce ?? 250;\n\n useEffect(() => {\n const controller = new AbortController();\n refController.current = controller;\n setState((previous) => ({ ...previous, status: 'loading', page: 1, more: false }));\n const timer = setTimeout(\n async () => {\n try {\n const page = toPage(await refSearch.current(query, { page: 1, signal: controller.signal }));\n if (controller.signal.aborted) {\n return;\n }\n setState({ status: 'ready', items: page.items, page: 1, hasMore: page.hasMore === true, more: false, active: 0 });\n } catch {\n if (!controller.signal.aborted) {\n setState((previous) => ({ ...previous, status: 'error', items: [], hasMore: false }));\n }\n }\n },\n refFirst.current ? 0 : debounce,\n );\n refFirst.current = false;\n return () => {\n clearTimeout(timer);\n controller.abort();\n };\n }, [query, debounce]);\n\n const loadMore = () => {\n const controller = refController.current;\n if (!controller || state.status !== 'ready' || !state.hasMore || state.more) {\n return;\n }\n const next = state.page + 1;\n setState((previous) => ({ ...previous, more: true }));\n refSearch\n .current(query, { page: next, signal: controller.signal })\n .then((result) => {\n if (controller.signal.aborted) {\n return;\n }\n const page = toPage(result);\n setState((previous) => ({\n ...previous,\n items: [...previous.items, ...page.items.filter((item) => !previous.items.some((known) => known.id === item.id))],\n page: next,\n hasMore: page.hasMore === true,\n more: false,\n }));\n })\n .catch(() => {\n if (!controller.signal.aborted) {\n setState((previous) => ({ ...previous, more: false, hasMore: false }));\n }\n });\n };\n const refLoadMore = useRef(loadMore);\n refLoadMore.current = loadMore;\n\n const activeItem = state.items[state.active];\n\n useEffect(() => {\n onActiveChange(activeItem ? optionId(listId, state.active) : undefined);\n }, [activeItem, listId, onActiveChange, state.active]);\n\n useEffect(() => {\n document.getElementById(optionId(listId, state.active))?.scrollIntoView({ block: 'nearest' });\n }, [listId, state.active]);\n\n const watchSentinel = useCallback((node: HTMLDivElement | null) => {\n if (!node) {\n return;\n }\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n refLoadMore.current();\n }\n },\n { root: refViewport.current },\n );\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n useEffect(() => {\n keyHandler.current = (event) => {\n const count = state.items.length;\n if (event.key === 'Escape') {\n event.stopPropagation();\n return false;\n }\n if (count === 0) {\n return false;\n }\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n const step = event.key === 'ArrowDown' ? 1 : -1;\n const next = (state.active + step + count) % count;\n if (step === 1 && state.active === count - 1) {\n refLoadMore.current();\n }\n setState((previous) => ({ ...previous, active: next }));\n return true;\n }\n if ((event.key === 'Enter' || event.key === 'Tab') && activeItem) {\n onPick(activeItem);\n return true;\n }\n return false;\n };\n return () => {\n keyHandler.current = null;\n };\n }, [activeItem, keyHandler, onPick, state.active, state.items.length]);\n\n const anchor = { getBoundingClientRect: () => rect?.() ?? new DOMRect(0, 0, 0, 0) };\n const announcement =\n state.status === 'loading'\n ? labels.mentionSearching\n : state.status === 'error'\n ? labels.mentionError\n : state.items.length === 0\n ? labels.mentionEmpty\n : labels.mentionResults.replace('{count}', String(state.items.length));\n\n return (\n <Popover open onOpenChange={() => undefined}>\n <PopoverContent\n anchor={anchor}\n align=\"start\"\n side=\"bottom\"\n sideOffset={6}\n initialFocus={false}\n finalFocus={false}\n data-slot=\"rich-text-mention-popup\"\n className=\"w-72 gap-0 p-1\"\n >\n <ScrollArea className=\"max-h-60\" viewportRef={refViewport}>\n <div\n role=\"listbox\"\n id={listId}\n aria-label={labels.mentionList}\n className={cn('flex flex-col gap-px', state.items.length === 0 && 'hidden')}\n >\n {state.items.map((item, index) => (\n // biome-ignore lint/a11y/useKeyWithClickEvents: the editor keeps focus and drives the list with its own keys\n // biome-ignore lint/a11y/useFocusableInteractive: options are named by aria-activedescendant on the editor, never focused\n <div\n key={item.id}\n id={optionId(listId, index)}\n role=\"option\"\n aria-selected={index === state.active}\n data-slot=\"rich-text-mention-option\"\n data-highlighted={index === state.active ? '' : undefined}\n className={cn(popupItemClass('base-ui'), 'h-auto min-h-8 flex-col items-start gap-0')}\n onMouseDown={(event) => event.preventDefault()}\n onMouseMove={() => setState((previous) => (previous.active === index ? previous : { ...previous, active: index }))}\n onClick={() => onPick(item)}\n >\n <span className=\"truncate\">{item.label}</span>\n {item.secondary ? <span className=\"truncate text-xs text-foreground/70\">{item.secondary}</span> : null}\n </div>\n ))}\n </div>\n {state.status === 'loading' && state.items.length === 0 ? (\n <div className=\"flex items-center gap-2 px-2 py-1.5 text-sm text-muted-foreground\">\n <IconLoader2 className=\"size-4 animate-spin motion-reduce:animate-none\" aria-hidden />\n {labels.mentionSearching}\n </div>\n ) : null}\n {state.status === 'ready' && state.items.length === 0 ? (\n <div className=\"px-2 py-1.5 text-sm text-muted-foreground\">{labels.mentionEmpty}</div>\n ) : null}\n {state.status === 'error' ? <div className=\"px-2 py-1.5 text-sm text-destructive\">{labels.mentionError}</div> : null}\n {state.hasMore ? (\n <div key={state.items.length} ref={watchSentinel} className=\"flex items-center gap-2 px-2 py-1.5 text-xs text-muted-foreground\">\n {state.more ? labels.mentionLoadingMore : null}\n </div>\n ) : null}\n </ScrollArea>\n <div role=\"status\" className=\"sr-only\">\n {announcement}\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n","import type { Editor } from '@tiptap/core';\nimport { TextSelection } from '@tiptap/pm/state';\n\n/**\n * Whether commands may be called on the editor. TipTap builds an editor during the render, mounts its view later, and\n * destroys one that has not been mounted within a moment (useEditor then makes a new one), so an effect can be handed an\n * editor that is not there yet or no longer is. `isDestroyed` is true for both: it reads true until the view exists. A\n * destroyed editor has no command manager, so `editor.commands` throws on it.\n */\nexport const isLive = (editor: Editor): boolean => editor.isInitialized && !editor.isDestroyed;\n\n/**\n * Brings the editor to a value the parent passed in, if it is one the editor did not just report itself.\n * `known` is the last HTML the editor and the parent agree on (the starting value, then whatever the editor emitted or was\n * given). The caret stays where it was, kept inside the new content, so a value changed from outside while the writer is\n * typing does not throw the caret to the start.\n */\nexport const syncValue = (editor: Editor, value: string | undefined, known: { current: string | undefined }): void => {\n if (!isLive(editor) || value === undefined || value === known.current) {\n return;\n }\n known.current = value;\n const { from, to } = editor.state.selection;\n editor.commands.setContent(value, { emitUpdate: false });\n editor.commands.command(({ tr }) => {\n const size = tr.doc.content.size;\n tr.setSelection(TextSelection.between(tr.doc.resolve(Math.min(from, size)), tr.doc.resolve(Math.min(to, size))));\n return true;\n });\n};\n\n/** Sets whether the editor can be edited without telling the app something changed (TipTap emits an update by default). */\nexport const syncEditable = (editor: Editor, editable: boolean): void => {\n if (isLive(editor) && editor.isEditable !== editable) {\n editor.setEditable(editable, false);\n }\n};\n","import { Toolbar as ToolbarPrimitive } from '@base-ui/react/toolbar';\nimport { isAllowedRichTextHref } from '@edyn/ui/components/edyn/rich-text-content/allow-list';\nimport { Button } from '@edyn/ui/components/ui/button';\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@edyn/ui/components/ui/dropdown-menu';\nimport { Input } from '@edyn/ui/components/ui/input';\nimport { Popover, PopoverContent, PopoverTrigger } from '@edyn/ui/components/ui/popover';\nimport { toggleVariants } from '@edyn/ui/components/ui/toggle';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { IconBold, IconItalic, IconLink, IconList, IconListNumbers, IconSeparatorHorizontal, IconUnderline, IconVariable } from '@tabler/icons-react';\nimport type { Editor } from '@tiptap/core';\nimport { useEditorState } from '@tiptap/react';\nimport { type FormEvent, type ReactNode, type RefObject, useEffect, useState } from 'react';\nimport type { IRichTextField, IRichTextLabels } from './types';\n\nconst BUTTON_CLASS = cn(toggleVariants({ variant: 'default', size: 'sm' }), 'size-7 px-0');\n\n/** A typed address becomes a link: \"name@example.test\" a mailto, \"example.test\" an https address. */\nexport const normalizeHref = (raw: string): string => {\n const value = raw.trim();\n if (value === '' || /^[a-z][a-z0-9+.-]*:/i.test(value)) {\n return value;\n }\n return /^[^\\s@/]+@[^\\s@/]+\\.[^\\s@/]+$/.test(value) ? `mailto:${value}` : `https://${value}`;\n};\n\ninterface IToolbarButtonProps {\n label: string;\n pressed?: boolean;\n disabled?: boolean;\n onClick?: () => void;\n children: ReactNode;\n}\n\nconst ToolbarButton = ({ label, pressed, disabled, onClick, children }: IToolbarButtonProps) => (\n <ToolbarPrimitive.Button\n type=\"button\"\n aria-label={label}\n title={label}\n aria-pressed={pressed}\n data-pressed={pressed ? '' : undefined}\n disabled={disabled}\n className={BUTTON_CLASS}\n onMouseDown={(event) => event.preventDefault()}\n onClick={onClick}\n >\n {children}\n </ToolbarPrimitive.Button>\n);\n\n/** Where the writer's selection was when the link box opened: moving focus into the box must not lose it. */\nexport interface ILinkRange {\n from: number;\n to: number;\n}\n\nconst hrefAt = (editor: Editor, range: ILinkRange): string => {\n const { doc } = editor.state;\n const marks = range.from < range.to ? (doc.nodeAt(range.from)?.marks ?? []) : doc.resolve(range.from).marks();\n return String(marks.find((mark) => mark.type.name === 'link')?.attrs.href ?? '');\n};\n\ninterface ILinkControlProps {\n range: RefObject<ILinkRange | null>;\n editor: Editor;\n labels: IRichTextLabels;\n active: boolean;\n disabled: boolean;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nconst LinkControl = ({ range, editor, labels, active, disabled, open, onOpenChange }: ILinkControlProps) => {\n const [address, setAddress] = useState('');\n const [invalid, setInvalid] = useState(false);\n\n useEffect(() => {\n if (open) {\n setAddress(range.current ? hrefAt(editor, range.current) : '');\n setInvalid(false);\n }\n }, [editor, open, range]);\n\n const apply = (event: FormEvent) => {\n event.preventDefault();\n event.stopPropagation();\n const href = normalizeHref(address);\n if (!isAllowedRichTextHref(href)) {\n setInvalid(true);\n return;\n }\n const saved = range.current ?? { from: editor.state.selection.from, to: editor.state.selection.to };\n const chain = editor.chain().focus().setTextSelection(saved);\n if (saved.from === saved.to && !hrefAt(editor, saved)) {\n chain.insertContent({ type: 'text', text: href, marks: [{ type: 'link', attrs: { href } }] }).run();\n } else {\n chain.extendMarkRange('link').setLink({ href }).run();\n }\n onOpenChange(false);\n };\n\n const remove = () => {\n const saved = range.current ?? { from: editor.state.selection.from, to: editor.state.selection.to };\n editor.chain().focus().setTextSelection(saved).extendMarkRange('link').unsetLink().run();\n onOpenChange(false);\n };\n\n return (\n <Popover open={open} onOpenChange={onOpenChange}>\n <PopoverTrigger\n render={\n <ToolbarPrimitive.Button\n type=\"button\"\n aria-label={labels.link}\n title={labels.link}\n aria-pressed={active}\n data-pressed={active ? '' : undefined}\n disabled={disabled}\n className={BUTTON_CLASS}\n />\n }\n >\n <IconLink aria-hidden />\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-80\">\n <form className=\"flex flex-col gap-2\" onSubmit={apply}>\n <Input\n type=\"text\"\n inputMode=\"url\"\n aria-label={labels.linkAddress}\n aria-invalid={invalid || undefined}\n value={address}\n onChange={(event) => {\n setAddress(event.target.value);\n setInvalid(false);\n }}\n />\n {invalid ? <p className=\"text-xs text-destructive\">{labels.linkInvalid}</p> : null}\n <div className=\"flex justify-end gap-2\">\n {active ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n {labels.linkRemove}\n </Button>\n ) : null}\n <Button type=\"submit\" size=\"sm\">\n {labels.linkApply}\n </Button>\n </div>\n </form>\n </PopoverContent>\n </Popover>\n );\n};\n\nexport interface IRichTextToolbarProps {\n linkRange: RefObject<ILinkRange | null>;\n editor: Editor;\n labels: IRichTextLabels;\n fields: IRichTextField[] | undefined;\n disabled: boolean;\n linkOpen: boolean;\n onLinkOpenChange: (open: boolean) => void;\n}\n\nexport const RichTextToolbar = ({ linkRange, editor, labels, fields, disabled, linkOpen, onLinkOpenChange }: IRichTextToolbarProps) => {\n const state = useEditorState({\n editor,\n selector: ({ editor: current }) => ({\n bold: current.isActive('bold'),\n italic: current.isActive('italic'),\n underline: current.isActive('underline'),\n bullets: current.isActive('bulletList'),\n numbers: current.isActive('orderedList'),\n link: current.isActive('link'),\n }),\n });\n\n return (\n <ToolbarPrimitive.Root\n data-slot=\"rich-text-toolbar\"\n aria-label={labels.toolbar}\n className=\"flex flex-wrap items-center gap-0.5 border-b border-input p-1\"\n >\n <ToolbarButton label={labels.bold} pressed={state.bold} disabled={disabled} onClick={() => editor.chain().focus().toggleBold().run()}>\n <IconBold aria-hidden />\n </ToolbarButton>\n <ToolbarButton label={labels.italic} pressed={state.italic} disabled={disabled} onClick={() => editor.chain().focus().toggleItalic().run()}>\n <IconItalic aria-hidden />\n </ToolbarButton>\n <ToolbarButton\n label={labels.underline}\n pressed={state.underline}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n >\n <IconUnderline aria-hidden />\n </ToolbarButton>\n <ToolbarPrimitive.Separator className=\"mx-1 h-4 w-px bg-border\" />\n <ToolbarButton\n label={labels.bulletList}\n pressed={state.bullets}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBulletList().run()}\n >\n <IconList aria-hidden />\n </ToolbarButton>\n <ToolbarButton\n label={labels.numberedList}\n pressed={state.numbers}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleOrderedList().run()}\n >\n <IconListNumbers aria-hidden />\n </ToolbarButton>\n <LinkControl\n range={linkRange}\n editor={editor}\n labels={labels}\n active={state.link}\n disabled={disabled}\n open={linkOpen}\n onOpenChange={onLinkOpenChange}\n />\n <ToolbarButton label={labels.horizontalRule} disabled={disabled} onClick={() => editor.chain().focus().setHorizontalRule().run()}>\n <IconSeparatorHorizontal aria-hidden />\n </ToolbarButton>\n {fields && fields.length > 0 ? (\n <>\n <ToolbarPrimitive.Separator className=\"mx-1 h-4 w-px bg-border\" />\n <DropdownMenu>\n <DropdownMenuTrigger\n render={\n <ToolbarPrimitive.Button\n type=\"button\"\n aria-label={labels.insertField}\n title={labels.insertField}\n disabled={disabled}\n className={BUTTON_CLASS}\n />\n }\n >\n <IconVariable aria-hidden />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-56\">\n {fields.map((field) => (\n <DropdownMenuItem\n key={field.id}\n onClick={() =>\n editor\n .chain()\n .focus()\n .insertContent({ type: 'text', text: `{{${field.id}}}` })\n .run()\n }\n >\n {field.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n </>\n ) : null}\n </ToolbarPrimitive.Root>\n );\n};\n","/** One person (or anything else) the app offers when the writer types @. */\nexport interface IRichTextMentionItem {\n /** What the HTML carries. By default the value is written as `@${id}`, so an email address works as an id. */\n id: string;\n /** What the chip shows while the text is being edited. */\n label: string;\n /** A second, muted line in the list (a role, an email address). */\n secondary?: string;\n}\n\n/** A page of results. Return a plain array instead when there is only ever one page. */\nexport interface IRichTextMentionPage {\n items: IRichTextMentionItem[];\n /** True when asking for `page + 1` would return more. The list loads it when it is scrolled to the end. */\n hasMore?: boolean;\n}\n\nexport interface IRichTextMentionSearchOptions {\n /** 1-based. */\n page: number;\n /** Aborted when the writer types on or closes the list: pass it to `fetch` so a stale search stops. */\n signal: AbortSignal;\n}\n\nexport type TRichTextMentionSearch = (\n query: string,\n options: IRichTextMentionSearchOptions,\n) => Promise<IRichTextMentionItem[] | IRichTextMentionPage>;\n\nexport interface IRichTextMention {\n /** Asked for the first page when the writer types @ and again for every change of the text after it, debounced. */\n search: TRichTextMentionSearch;\n /**\n * How a mention is written into the HTML. The chip exists only while editing; the HTML carries this text\n * and no element. Default: `@${item.id}`.\n */\n toText?: (item: Pick<IRichTextMentionItem, 'id' | 'label'>) => string;\n /** Milliseconds to wait after the last keystroke before searching. Default 250. */\n debounce?: number;\n}\n\n/** A field of a template (a mail merge token). Inserted as the plain text `{{id}}`. */\nexport interface IRichTextField {\n id: string;\n label: string;\n}\n\n/** What a ref to the editor can do, for a button outside it (a merge tag, say). */\nexport interface IRichTextEditorHandle {\n /** Writes plain text at the caret (over the selection), and puts focus back in the editor. */\n insertText: (text: string) => void;\n focus: () => void;\n}\n\n/** Every string the editor shows, so an app can translate them. */\nexport interface IRichTextLabels {\n toolbar: string;\n bold: string;\n italic: string;\n underline: string;\n bulletList: string;\n numberedList: string;\n link: string;\n horizontalRule: string;\n insertField: string;\n linkAddress: string;\n linkApply: string;\n linkRemove: string;\n linkInvalid: string;\n mentionList: string;\n mentionSearching: string;\n mentionEmpty: string;\n mentionError: string;\n mentionLoadingMore: string;\n /** Announced as the list changes. `{count}` is replaced. */\n mentionResults: string;\n}\n\nexport const DEFAULT_RICH_TEXT_LABELS: IRichTextLabels = {\n toolbar: 'Formatting',\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n bulletList: 'Bulleted list',\n numberedList: 'Numbered list',\n link: 'Link',\n horizontalRule: 'Horizontal line',\n insertField: 'Insert a field',\n linkAddress: 'Link address',\n linkApply: 'Apply',\n linkRemove: 'Remove link',\n linkInvalid: 'Enter an http, https or mailto address.',\n mentionList: 'Mentions',\n mentionSearching: 'Searching...',\n mentionEmpty: 'No matches',\n mentionError: 'The search failed',\n mentionLoadingMore: 'Loading more...',\n mentionResults: '{count} results',\n};\n","import { RICH_TEXT_BODY_CLASS } from '@edyn/ui/components/edyn/rich-text-content/rich-text-content';\nimport { ScrollArea } from '@edyn/ui/components/ui/scroll-area';\nimport { cn } from '@edyn/ui/lib/utils';\nimport type { Editor } from '@tiptap/core';\nimport { EditorContent, useEditor, useEditorState } from '@tiptap/react';\nimport type { SuggestionProps } from '@tiptap/suggestion';\nimport {\n type ComponentPropsWithoutRef,\n type Ref,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useReducer,\n useRef,\n useState,\n} from 'react';\nimport { buildExtensions, type IEditorHost } from './extensions';\nimport { MentionList } from './mention-list';\nimport { defaultMentionToText, isDocumentEmpty, serializeDocument } from './serialize';\nimport { isLive, syncEditable, syncValue } from './sync';\nimport { type ILinkRange, RichTextToolbar } from './toolbar';\nimport {\n DEFAULT_RICH_TEXT_LABELS,\n type IRichTextEditorHandle,\n type IRichTextField,\n type IRichTextLabels,\n type IRichTextMention,\n type IRichTextMentionItem,\n} from './types';\n\nconst LINE = 1.5;\n\ninterface ISuggestionState {\n query: string;\n rect: (() => DOMRect | null) | null;\n command: (item: IRichTextMentionItem) => void;\n}\n\nexport interface IRichTextEditorProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'defaultValue' | 'onChange' | 'id'> {\n /** The HTML, when the parent owns it. Pass back what `onChange` gave. An empty editor is `\"\"`. */\n value?: string;\n /** The HTML to start from when the editor owns its own value. */\n defaultValue?: string;\n /** Called with the HTML after every edit. Only the elements in `RICH_TEXT_ELEMENTS` can appear, and `\"\"` when there is no text. */\n onChange?: (html: string) => void;\n placeholder?: string;\n disabled?: boolean;\n /** Shows the content and keeps it selectable and copyable, with no toolbar. */\n readOnly?: boolean;\n /** Draws the error border and sets `aria-invalid`. The message is the form's to draw: point `aria-describedby` at it. */\n invalid?: boolean;\n /**\n * Lines the box is tall when empty.\n * @default 6\n */\n minRows?: number;\n /**\n * Lines it grows to before it scrolls inside.\n * @default 20\n */\n maxRows?: number;\n /** The most characters of text (a mention counts as the text it is written as). An edit past it is refused. Off by default. */\n maxLength?: number;\n /** Turns @ into a search the app answers. Without it, @ is an ordinary character. */\n mention?: IRichTextMention;\n /** Adds an \"Insert a field\" menu that writes `{{id}}` at the caret. */\n fields?: IRichTextField[];\n /**\n * Whether the formatting toolbar shows.\n * @default true\n */\n toolbar?: boolean;\n /** Replaces any of the strings the editor shows (the defaults are English). */\n labels?: Partial<IRichTextLabels>;\n /** On the editable element, so a form can name it. */\n id?: string;\n autoFocus?: boolean;\n /** Called with the files when the writer pastes only files (a screenshot). Without it, such a paste does nothing. */\n onPasteFiles?: (files: File[]) => void;\n /** Gives `insertText` and `focus`, for buttons outside the editor. */\n ref?: Ref<IRichTextEditorHandle>;\n}\n\n/**\n * A small rich-text field: paragraphs, bold, italic, underline, bulleted and numbered lists and links, with optional\n * @mentions the app answers asynchronously. The value is HTML in and out, and only the elements in `RICH_TEXT_ELEMENTS`\n * can come out (no class, no style), whatever is pasted. A mention is a chip while editing and plain text in the HTML.\n * The server should still sanitise: this is a convenience for the writer, not a security boundary.\n */\nexport const RichTextEditor = ({\n value,\n defaultValue = '',\n onChange,\n placeholder,\n disabled = false,\n readOnly = false,\n invalid = false,\n minRows = 6,\n maxRows = 20,\n maxLength,\n mention,\n fields,\n toolbar = true,\n labels,\n id,\n autoFocus = false,\n onPasteFiles,\n ref,\n className,\n 'aria-invalid': ariaInvalid,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n ...props\n}: IRichTextEditorProps) => {\n const isInvalid = invalid || ariaInvalid === true || ariaInvalid === 'true';\n const text = useMemo(() => ({ ...DEFAULT_RICH_TEXT_LABELS, ...labels }), [labels]);\n const listId = useId();\n const [suggestion, setSuggestion] = useState<ISuggestionState | null>(null);\n const [activeOption, setActiveOption] = useState<string | undefined>(undefined);\n const [linkOpen, setLinkOpen] = useState(false);\n const refLinkRange = useRef<ILinkRange | null>(null);\n const refKeys = useRef<((event: KeyboardEvent) => boolean) | null>(null);\n // What the editor and the parent agree on. It starts as the value the editor is built from, so a controlled value\n // that has not changed asks for nothing at mount.\n const refKnown = useRef<string | undefined>(value ?? defaultValue);\n const refPending = useRef<Array<(live: Editor) => void>>([]);\n const [, wake] = useReducer((count: number) => count + 1, 0);\n const editable = !disabled && !readOnly;\n const showToolbar = toolbar && !readOnly;\n\n const latest = useRef({ mention, maxLength, onChange, onPasteFiles, toolbar: showToolbar });\n latest.current = { mention, maxLength, onChange, onPasteFiles, toolbar: showToolbar };\n\n const host = useMemo<IEditorHost>(\n () => ({\n mentionEnabled: () => latest.current.mention !== undefined,\n maxLength: () => latest.current.maxLength,\n toText: () => latest.current.mention?.toText ?? defaultMentionToText,\n onSuggestion: (props: SuggestionProps<IRichTextMentionItem, IRichTextMentionItem> | null) => {\n if (props === null) {\n setActiveOption(undefined);\n }\n setSuggestion(props === null ? null : { query: props.query, rect: props.clientRect ?? null, command: props.command });\n },\n onSuggestionKey: ({ event }) => refKeys.current?.(event) ?? false,\n }),\n [],\n );\n const extensions = useMemo(() => buildExtensions(host), [host]);\n\n const emit = useCallback(\n (current: Editor): string => {\n const html = isDocumentEmpty(current.state.doc) ? '' : serializeDocument(current.state.doc, host.toText());\n refKnown.current = html;\n return html;\n },\n [host],\n );\n\n const attributes = useMemo(() => {\n const entries: Record<string, string | undefined> = {\n role: 'textbox',\n 'aria-multiline': 'true',\n 'aria-autocomplete': mention ? 'list' : undefined,\n 'aria-controls': suggestion ? listId : undefined,\n 'aria-activedescendant': suggestion ? activeOption : undefined,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': isInvalid ? 'true' : undefined,\n 'aria-readonly': readOnly ? 'true' : undefined,\n 'aria-disabled': disabled ? 'true' : undefined,\n 'aria-placeholder': placeholder,\n tabindex: readOnly && !disabled ? '0' : undefined,\n id,\n 'data-slot': 'rich-text-editor-content',\n class: cn(RICH_TEXT_BODY_CLASS, 'min-h-(--rich-text-min) px-2.5 py-2 outline-none'),\n };\n return Object.fromEntries(Object.entries(entries).filter((entry): entry is [string, string] => entry[1] !== undefined));\n }, [activeOption, ariaDescribedBy, ariaLabel, ariaLabelledBy, disabled, id, isInvalid, listId, mention, placeholder, readOnly, suggestion]);\n\n const editor = useEditor({\n extensions,\n content: value ?? defaultValue,\n editable,\n autofocus: autoFocus ? 'end' : false,\n editorProps: {\n attributes,\n handlePaste: (_view, event) => {\n const data = event.clipboardData;\n const onlyFiles = data !== null && data.files.length > 0 && data.getData('text/plain') === '' && data.getData('text/html') === '';\n if (!onlyFiles || !latest.current.onPasteFiles) {\n return false;\n }\n latest.current.onPasteFiles(Array.from(data.files));\n return true;\n },\n handleKeyDown: (view, event) => {\n if ((event.metaKey || event.ctrlKey) && !event.altKey && !event.shiftKey && event.key.toLowerCase() === 'k' && latest.current.toolbar) {\n event.preventDefault();\n refLinkRange.current = { from: view.state.selection.from, to: view.state.selection.to };\n setLinkOpen(true);\n return true;\n }\n return false;\n },\n },\n onBlur: () => {\n setSuggestion(null);\n setActiveOption(undefined);\n },\n onUpdate: ({ editor: current }) => {\n latest.current.onChange?.(emit(current));\n },\n });\n\n // useEditor can replace the editor (it destroys one that was not mounted in time, and in development a second render\n // makes a second), so readiness is read off the editor in hand: wake up when this one finishes initialising.\n const ready = isLive(editor);\n useEffect(() => {\n editor.on('create', wake);\n wake();\n return () => {\n editor.off('create', wake);\n };\n }, [editor]);\n\n const whenLive = useCallback(\n (action: (live: Editor) => void) => {\n if (isLive(editor)) {\n action(editor);\n } else {\n refPending.current.push(action);\n }\n },\n [editor],\n );\n\n useImperativeHandle(\n ref,\n () => ({\n insertText: (text) => {\n whenLive((live) => {\n live.chain().focus().insertContent({ type: 'text', text }).run();\n });\n },\n focus: () => {\n whenLive((live) => {\n live.commands.focus();\n });\n },\n }),\n [whenLive],\n );\n\n useEffect(() => {\n if (!ready || !isLive(editor)) {\n return;\n }\n for (const action of refPending.current.splice(0)) {\n action(editor);\n }\n }, [editor, ready]);\n\n useEffect(() => {\n if (ready) {\n syncEditable(editor, editable);\n }\n }, [editable, editor, ready]);\n\n useEffect(() => {\n if (ready) {\n syncValue(editor, value, refKnown);\n }\n }, [editor, ready, value]);\n\n const empty = useEditorState({ editor, selector: ({ editor: current }) => isDocumentEmpty(current.state.doc) });\n\n const pick = useCallback(\n (item: IRichTextMentionItem) => {\n suggestion?.command(item);\n },\n [suggestion],\n );\n\n return (\n <div\n data-slot=\"rich-text-editor\"\n data-invalid={isInvalid ? '' : undefined}\n data-disabled={disabled ? '' : undefined}\n data-readonly={readOnly ? '' : undefined}\n className={cn(\n 'flex w-full min-w-0 flex-col rounded-lg border border-input bg-transparent text-base transition-colors focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/50 data-disabled:pointer-events-none data-disabled:cursor-not-allowed data-disabled:bg-input/50 data-disabled:opacity-50 data-invalid:border-destructive data-invalid:ring-3 data-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:data-disabled:bg-input/80 dark:data-invalid:ring-destructive/40',\n className,\n )}\n {...props}\n >\n {showToolbar ? (\n <RichTextToolbar\n editor={editor}\n labels={text}\n fields={fields}\n disabled={disabled}\n linkOpen={linkOpen}\n linkRange={refLinkRange}\n onLinkOpenChange={(next) => {\n if (next && !linkOpen) {\n refLinkRange.current = { from: editor.state.selection.from, to: editor.state.selection.to };\n }\n setLinkOpen(next);\n }}\n />\n ) : null}\n <ScrollArea\n className=\"relative\"\n style={{ maxHeight: `${maxRows * LINE + 1}rem`, ['--rich-text-min' as string]: `${minRows * LINE + 1}rem` }}\n focusable={false}\n >\n {empty && placeholder ? (\n <p aria-hidden className=\"pointer-events-none absolute start-2.5 top-2 text-muted-foreground\">\n {placeholder}\n </p>\n ) : null}\n <EditorContent editor={editor} />\n </ScrollArea>\n {suggestion && mention ? (\n <MentionList\n query={suggestion.query}\n rect={suggestion.rect}\n config={mention}\n labels={text}\n listId={listId}\n onPick={pick}\n keyHandler={refKeys}\n onActiveChange={setActiveOption}\n />\n ) : null}\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"rich-text-editor.js","names":[],"sources":["../../ui/src/components/edyn/rich-text-editor/serialize.ts","../../ui/src/components/edyn/rich-text-editor/extensions.ts","../../ui/src/components/edyn/rich-text-editor/mention-list.tsx","../../ui/src/components/edyn/rich-text-editor/sync.ts","../../ui/src/components/edyn/rich-text-editor/toolbar.tsx","../../ui/src/components/edyn/rich-text-editor/types.ts","../../ui/src/components/edyn/rich-text-editor/rich-text-editor.tsx"],"sourcesContent":["import { type DOMOutputSpec, DOMSerializer, type Node as TProseNode } from '@tiptap/pm/model';\nimport type { IRichTextMention } from './types';\n\nexport type TMentionToText = NonNullable<IRichTextMention['toText']>;\n\n// A serializer can only return elements, so a mention leaves as one and is unwrapped to its text below.\nconst MENTION_MARK = 'data-rich-text-mention';\n\nexport const defaultMentionToText: TMentionToText = (item) => `@${item.id}`;\n\n/**\n * The document as HTML. Not `editor.getHTML()`: that would write a mention as its chip element, and\n * the HTML must carry the plain text the app chose (`@person@example.test`) and nothing else.\n */\nexport const serializeDocument = (doc: TProseNode, toText: TMentionToText): string => {\n const schema = doc.type.schema;\n const nodes = {\n ...DOMSerializer.nodesFromSchema(schema),\n mention: (node: TProseNode): DOMOutputSpec => [\n 'span',\n { [MENTION_MARK]: '' },\n toText({ id: String(node.attrs.id ?? ''), label: String(node.attrs.label ?? '') }),\n ],\n };\n const serializer = new DOMSerializer(nodes, DOMSerializer.marksFromSchema(schema));\n const container = document.createElement('div');\n container.appendChild(serializer.serializeFragment(doc.content));\n for (const element of Array.from(container.querySelectorAll(`[${MENTION_MARK}]`))) {\n element.replaceWith(document.createTextNode(element.textContent ?? ''));\n }\n return container.innerHTML;\n};\n\n/** No text and no mention. A document of blank paragraphs, spaces and line breaks is empty too. */\nexport const isDocumentEmpty = (doc: TProseNode): boolean => {\n if (doc.textContent.trim() !== '') {\n return false;\n }\n let hasMention = false;\n doc.descendants((node) => {\n if (node.type.name === 'mention') {\n hasMention = true;\n }\n return !hasMention;\n });\n return !hasMention;\n};\n\n/** Characters the HTML text will have: a mention counts as the text it is written as. */\nexport const countCharacters = (doc: TProseNode, toText: TMentionToText): number => {\n let total = 0;\n doc.descendants((node) => {\n if (node.isText) {\n total += node.text?.length ?? 0;\n } else if (node.type.name === 'mention') {\n total += toText({ id: String(node.attrs.id ?? ''), label: String(node.attrs.label ?? '') }).length;\n } else if (node.type.name === 'hardBreak') {\n total += 1;\n }\n return true;\n });\n return total;\n};\n","import { isAllowedRichTextHref } from '@edyn/ui/components/edyn/rich-text-content/allow-list';\nimport { Extension, mergeAttributes } from '@tiptap/core';\nimport { Bold } from '@tiptap/extension-bold';\nimport { Document } from '@tiptap/extension-document';\nimport { HardBreak } from '@tiptap/extension-hard-break';\nimport { HorizontalRule } from '@tiptap/extension-horizontal-rule';\nimport { Italic } from '@tiptap/extension-italic';\nimport { Link } from '@tiptap/extension-link';\nimport { BulletList, ListItem, OrderedList } from '@tiptap/extension-list';\nimport { Mention } from '@tiptap/extension-mention';\nimport { Paragraph } from '@tiptap/extension-paragraph';\nimport { Text } from '@tiptap/extension-text';\nimport { Underline } from '@tiptap/extension-underline';\nimport { UndoRedo } from '@tiptap/extensions';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport type { SuggestionKeyDownProps, SuggestionProps } from '@tiptap/suggestion';\nimport { countCharacters, type TMentionToText } from './serialize';\nimport type { IRichTextMentionItem } from './types';\n\n/** What the editor needs from the component while it runs. Held in a ref, so the extensions are built once. */\nexport interface IEditorHost {\n mentionEnabled: () => boolean;\n maxLength: () => number | undefined;\n toText: () => TMentionToText;\n onSuggestion: (props: SuggestionProps<IRichTextMentionItem, IRichTextMentionItem> | null) => void;\n onSuggestionKey: (props: SuggestionKeyDownProps) => boolean;\n}\n\nconst MENTION_CHIP_CLASS = 'rounded-sm bg-primary/10 px-1 py-0.5 font-medium text-primary';\n\nconst limitKey = new PluginKey('richTextMaxLength');\n\n/** Refuses an edit that would take the text over the limit (a paste included) and lets one that shortens it through. */\nconst maxLengthExtension = (host: IEditorHost) =>\n Extension.create({\n name: 'maxLength',\n addProseMirrorPlugins() {\n return [\n new Plugin({\n key: limitKey,\n filterTransaction: (tr, state) => {\n const limit = host.maxLength();\n if (!tr.docChanged || limit === undefined) {\n return true;\n }\n const next = countCharacters(tr.doc, host.toText());\n return next <= limit || next <= countCharacters(state.doc, host.toText());\n },\n }),\n ];\n },\n });\n\n/**\n * The editor's whole schema: paragraph, line break, bold, italic, underline, bullet and numbered lists, link, and the\n * mention chip. Whatever else arrives (a paste, `value`) is not in the schema, so ProseMirror drops the markup and keeps\n * the text.\n */\nexport const buildExtensions = (host: IEditorHost) => [\n Document,\n Paragraph,\n Text,\n HardBreak,\n Bold,\n Italic,\n Underline,\n BulletList,\n // A list is numbered from 1; the `start` it would otherwise keep is an attribute outside the allow-list.\n OrderedList.extend({\n addAttributes() {\n return {};\n },\n }),\n ListItem,\n HorizontalRule,\n Link.extend({\n addAttributes() {\n return {\n href: {\n default: null,\n parseHTML: (element) => element.getAttribute('href'),\n renderHTML: (attributes) => (attributes.href ? { href: attributes.href } : {}),\n },\n };\n },\n }).configure({\n openOnClick: false,\n autolink: true,\n linkOnPaste: true,\n defaultProtocol: 'https',\n protocols: ['mailto'],\n isAllowedUri: (url) => isAllowedRichTextHref(url),\n HTMLAttributes: { rel: null, target: null, class: null },\n }),\n UndoRedo,\n maxLengthExtension(host),\n Mention.extend({\n addAttributes() {\n return {\n id: {\n default: null,\n parseHTML: (element) => element.getAttribute('data-id'),\n renderHTML: (attributes) => (attributes.id ? { 'data-id': attributes.id } : {}),\n },\n label: {\n default: null,\n parseHTML: (element) => element.getAttribute('data-label'),\n renderHTML: (attributes) => (attributes.label ? { 'data-label': attributes.label } : {}),\n },\n };\n },\n }).configure({\n HTMLAttributes: { class: MENTION_CHIP_CLASS },\n renderText: ({ node }) => `@${node.attrs.label ?? node.attrs.id}`,\n renderHTML: ({ options, node }) => ['span', mergeAttributes(options.HTMLAttributes), `@${node.attrs.label ?? node.attrs.id}`],\n suggestion: {\n char: '@',\n allow: () => host.mentionEnabled(),\n items: () => [],\n command: ({ editor, range, props }) => {\n editor\n .chain()\n .focus()\n .insertContentAt(range, [\n { type: 'mention', attrs: { id: props.id, label: props.label } },\n { type: 'text', text: ' ' },\n ])\n .run();\n },\n render: () => ({\n onStart: (props) => host.onSuggestion(props),\n onUpdate: (props) => host.onSuggestion(props),\n onKeyDown: (props) => host.onSuggestionKey(props),\n onExit: () => host.onSuggestion(null),\n }),\n },\n }),\n];\n","import { Popover, PopoverContent } from '@edyn/ui/components/ui/popover';\nimport { ScrollArea } from '@edyn/ui/components/ui/scroll-area';\nimport { popupItemClass } from '@edyn/ui/lib/popup-list';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { IconLoader2 } from '@tabler/icons-react';\nimport { type RefObject, useCallback, useEffect, useRef, useState } from 'react';\nimport type { IRichTextLabels, IRichTextMention, IRichTextMentionItem, IRichTextMentionPage } from './types';\n\ninterface IListState {\n status: 'loading' | 'ready' | 'error';\n items: IRichTextMentionItem[];\n page: number;\n hasMore: boolean;\n more: boolean;\n active: number;\n}\n\nconst FIRST: IListState = { status: 'loading', items: [], page: 1, hasMore: false, more: false, active: 0 };\n\nconst toPage = (result: IRichTextMentionItem[] | IRichTextMentionPage): IRichTextMentionPage =>\n Array.isArray(result) ? { items: result, hasMore: false } : result;\n\nexport interface IMentionListProps {\n query: string;\n /** Where the @ was typed. */\n rect: (() => DOMRect | null) | null;\n config: IRichTextMention;\n labels: IRichTextLabels;\n listId: string;\n onPick: (item: IRichTextMentionItem) => void;\n /** The editor keeps focus, so the list is driven by its keys: the editor calls this one. */\n keyHandler: RefObject<((event: KeyboardEvent) => boolean) | null>;\n /** The id of the option the editor should name as `aria-activedescendant`. */\n onActiveChange: (optionId: string | undefined) => void;\n}\n\nconst optionId = (listId: string, index: number): string => `${listId}-${index}`;\n\n/** The list that opens under the caret when the writer types @. */\nexport const MentionList = ({ query, rect, config, labels, listId, onPick, keyHandler, onActiveChange }: IMentionListProps) => {\n const [state, setState] = useState<IListState>(FIRST);\n const refSearch = useRef(config.search);\n refSearch.current = config.search;\n const refFirst = useRef(true);\n const refController = useRef<AbortController | null>(null);\n const refViewport = useRef<HTMLDivElement | null>(null);\n const debounce = config.debounce ?? 250;\n\n useEffect(() => {\n const controller = new AbortController();\n refController.current = controller;\n setState((previous) => ({ ...previous, status: 'loading', page: 1, more: false }));\n const timer = setTimeout(\n async () => {\n try {\n const page = toPage(await refSearch.current(query, { page: 1, signal: controller.signal }));\n if (controller.signal.aborted) {\n return;\n }\n setState({ status: 'ready', items: page.items, page: 1, hasMore: page.hasMore === true, more: false, active: 0 });\n } catch {\n if (!controller.signal.aborted) {\n setState((previous) => ({ ...previous, status: 'error', items: [], hasMore: false }));\n }\n }\n },\n refFirst.current ? 0 : debounce,\n );\n refFirst.current = false;\n return () => {\n clearTimeout(timer);\n controller.abort();\n };\n }, [query, debounce]);\n\n const loadMore = () => {\n const controller = refController.current;\n if (!controller || state.status !== 'ready' || !state.hasMore || state.more) {\n return;\n }\n const next = state.page + 1;\n setState((previous) => ({ ...previous, more: true }));\n refSearch\n .current(query, { page: next, signal: controller.signal })\n .then((result) => {\n if (controller.signal.aborted) {\n return;\n }\n const page = toPage(result);\n setState((previous) => ({\n ...previous,\n items: [...previous.items, ...page.items.filter((item) => !previous.items.some((known) => known.id === item.id))],\n page: next,\n hasMore: page.hasMore === true,\n more: false,\n }));\n })\n .catch(() => {\n if (!controller.signal.aborted) {\n setState((previous) => ({ ...previous, more: false, hasMore: false }));\n }\n });\n };\n const refLoadMore = useRef(loadMore);\n refLoadMore.current = loadMore;\n\n const activeItem = state.items[state.active];\n\n useEffect(() => {\n onActiveChange(activeItem ? optionId(listId, state.active) : undefined);\n }, [activeItem, listId, onActiveChange, state.active]);\n\n useEffect(() => {\n document.getElementById(optionId(listId, state.active))?.scrollIntoView({ block: 'nearest' });\n }, [listId, state.active]);\n\n const watchSentinel = useCallback((node: HTMLDivElement | null) => {\n if (!node) {\n return;\n }\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n refLoadMore.current();\n }\n },\n { root: refViewport.current },\n );\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n useEffect(() => {\n keyHandler.current = (event) => {\n const count = state.items.length;\n if (event.key === 'Escape') {\n event.stopPropagation();\n return false;\n }\n if (count === 0) {\n return false;\n }\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n const step = event.key === 'ArrowDown' ? 1 : -1;\n const next = (state.active + step + count) % count;\n if (step === 1 && state.active === count - 1) {\n refLoadMore.current();\n }\n setState((previous) => ({ ...previous, active: next }));\n return true;\n }\n if ((event.key === 'Enter' || event.key === 'Tab') && activeItem) {\n onPick(activeItem);\n return true;\n }\n return false;\n };\n return () => {\n keyHandler.current = null;\n };\n }, [activeItem, keyHandler, onPick, state.active, state.items.length]);\n\n const anchor = { getBoundingClientRect: () => rect?.() ?? new DOMRect(0, 0, 0, 0) };\n const announcement =\n state.status === 'loading'\n ? labels.mentionSearching\n : state.status === 'error'\n ? labels.mentionError\n : state.items.length === 0\n ? labels.mentionEmpty\n : labels.mentionResults.replace('{count}', String(state.items.length));\n\n return (\n <Popover open onOpenChange={() => undefined}>\n <PopoverContent\n anchor={anchor}\n align=\"start\"\n side=\"bottom\"\n sideOffset={6}\n initialFocus={false}\n finalFocus={false}\n data-slot=\"rich-text-mention-popup\"\n className=\"w-72 gap-0 p-1\"\n >\n <ScrollArea className=\"max-h-60\" viewportRef={refViewport}>\n <div\n role=\"listbox\"\n id={listId}\n aria-label={labels.mentionList}\n className={cn('flex flex-col gap-px', state.items.length === 0 && 'hidden')}\n >\n {state.items.map((item, index) => (\n // biome-ignore lint/a11y/useKeyWithClickEvents: the editor keeps focus and drives the list with its own keys\n // biome-ignore lint/a11y/useFocusableInteractive: options are named by aria-activedescendant on the editor, never focused\n <div\n key={item.id}\n id={optionId(listId, index)}\n role=\"option\"\n aria-selected={index === state.active}\n data-slot=\"rich-text-mention-option\"\n data-highlighted={index === state.active ? '' : undefined}\n className={cn(popupItemClass('base-ui'), 'h-auto min-h-8 flex-col items-start gap-0')}\n onMouseDown={(event) => event.preventDefault()}\n onMouseMove={() => setState((previous) => (previous.active === index ? previous : { ...previous, active: index }))}\n onClick={() => onPick(item)}\n >\n <span className=\"truncate\">{item.label}</span>\n {item.secondary ? <span className=\"truncate text-xs text-foreground/70\">{item.secondary}</span> : null}\n </div>\n ))}\n </div>\n {state.status === 'loading' && state.items.length === 0 ? (\n <div className=\"flex items-center gap-2 px-2 py-1.5 text-sm text-muted-foreground\">\n <IconLoader2 className=\"size-4 animate-spin motion-reduce:animate-none\" aria-hidden />\n {labels.mentionSearching}\n </div>\n ) : null}\n {state.status === 'ready' && state.items.length === 0 ? (\n <div className=\"px-2 py-1.5 text-sm text-muted-foreground\">{labels.mentionEmpty}</div>\n ) : null}\n {state.status === 'error' ? <div className=\"px-2 py-1.5 text-sm text-destructive\">{labels.mentionError}</div> : null}\n {state.hasMore ? (\n <div key={state.items.length} ref={watchSentinel} className=\"flex items-center gap-2 px-2 py-1.5 text-xs text-muted-foreground\">\n {state.more ? labels.mentionLoadingMore : null}\n </div>\n ) : null}\n </ScrollArea>\n <div role=\"status\" className=\"sr-only\">\n {announcement}\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n","import type { Editor } from '@tiptap/core';\nimport { TextSelection } from '@tiptap/pm/state';\n\n/**\n * Whether commands may be called on the editor. TipTap builds an editor during the render, mounts its view later, and\n * destroys one that has not been mounted within a moment (useEditor then makes a new one), so an effect can be handed an\n * editor that is not there yet or no longer is. `isDestroyed` is true for both: it reads true until the view exists. A\n * destroyed editor has no command manager, so `editor.commands` throws on it.\n */\nexport const isLive = (editor: Editor): boolean => editor.isInitialized && !editor.isDestroyed;\n\n/**\n * Brings the editor to a value the parent passed in, if it is one the editor did not just report itself.\n * `known` is the last HTML the editor and the parent agree on (the starting value, then whatever the editor emitted or was\n * given). The caret stays where it was, kept inside the new content, so a value changed from outside while the writer is\n * typing does not throw the caret to the start.\n */\nexport const syncValue = (editor: Editor, value: string | undefined, known: { current: string | undefined }): void => {\n if (!isLive(editor) || value === undefined || value === known.current) {\n return;\n }\n known.current = value;\n const { from, to } = editor.state.selection;\n editor.commands.setContent(value, { emitUpdate: false });\n editor.commands.command(({ tr }) => {\n const size = tr.doc.content.size;\n tr.setSelection(TextSelection.between(tr.doc.resolve(Math.min(from, size)), tr.doc.resolve(Math.min(to, size))));\n return true;\n });\n};\n\n/** Sets whether the editor can be edited without telling the app something changed (TipTap emits an update by default). */\nexport const syncEditable = (editor: Editor, editable: boolean): void => {\n if (isLive(editor) && editor.isEditable !== editable) {\n editor.setEditable(editable, false);\n }\n};\n","import { Toolbar as ToolbarPrimitive } from '@base-ui/react/toolbar';\nimport { isAllowedRichTextHref } from '@edyn/ui/components/edyn/rich-text-content/allow-list';\nimport { Button } from '@edyn/ui/components/ui/button';\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@edyn/ui/components/ui/dropdown-menu';\nimport { Input } from '@edyn/ui/components/ui/input';\nimport { Popover, PopoverContent, PopoverTrigger } from '@edyn/ui/components/ui/popover';\nimport { toggleVariants } from '@edyn/ui/components/ui/toggle';\nimport { cn } from '@edyn/ui/lib/utils';\nimport { IconBold, IconItalic, IconLink, IconList, IconListNumbers, IconSeparatorHorizontal, IconUnderline, IconVariable } from '@tabler/icons-react';\nimport type { Editor } from '@tiptap/core';\nimport { useEditorState } from '@tiptap/react';\nimport { type FormEvent, type ReactNode, type RefObject, useEffect, useState } from 'react';\nimport type { IRichTextField, IRichTextLabels } from './types';\n\nconst BUTTON_CLASS = cn(toggleVariants({ variant: 'default', size: 'sm' }), 'size-7 px-0');\n\n/** A typed address becomes a link: \"name@example.test\" a mailto, \"example.test\" an https address. */\nexport const normalizeHref = (raw: string): string => {\n const value = raw.trim();\n if (value === '' || /^[a-z][a-z0-9+.-]*:/i.test(value)) {\n return value;\n }\n return /^[^\\s@/]+@[^\\s@/]+\\.[^\\s@/]+$/.test(value) ? `mailto:${value}` : `https://${value}`;\n};\n\ninterface IToolbarButtonProps {\n label: string;\n pressed?: boolean;\n disabled?: boolean;\n onClick?: () => void;\n children: ReactNode;\n}\n\nconst ToolbarButton = ({ label, pressed, disabled, onClick, children }: IToolbarButtonProps) => (\n <ToolbarPrimitive.Button\n type=\"button\"\n aria-label={label}\n title={label}\n aria-pressed={pressed}\n data-pressed={pressed ? '' : undefined}\n disabled={disabled}\n className={BUTTON_CLASS}\n onMouseDown={(event) => event.preventDefault()}\n onClick={onClick}\n >\n {children}\n </ToolbarPrimitive.Button>\n);\n\n/** Where the writer's selection was when the link box opened: moving focus into the box must not lose it. */\nexport interface ILinkRange {\n from: number;\n to: number;\n}\n\nconst hrefAt = (editor: Editor, range: ILinkRange): string => {\n const { doc } = editor.state;\n const marks = range.from < range.to ? (doc.nodeAt(range.from)?.marks ?? []) : doc.resolve(range.from).marks();\n return String(marks.find((mark) => mark.type.name === 'link')?.attrs.href ?? '');\n};\n\ninterface ILinkControlProps {\n range: RefObject<ILinkRange | null>;\n editor: Editor;\n labels: IRichTextLabels;\n active: boolean;\n disabled: boolean;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nconst LinkControl = ({ range, editor, labels, active, disabled, open, onOpenChange }: ILinkControlProps) => {\n const [address, setAddress] = useState('');\n const [invalid, setInvalid] = useState(false);\n\n useEffect(() => {\n if (open) {\n setAddress(range.current ? hrefAt(editor, range.current) : '');\n setInvalid(false);\n }\n }, [editor, open, range]);\n\n const apply = (event: FormEvent) => {\n event.preventDefault();\n event.stopPropagation();\n const href = normalizeHref(address);\n if (!isAllowedRichTextHref(href)) {\n setInvalid(true);\n return;\n }\n const saved = range.current ?? { from: editor.state.selection.from, to: editor.state.selection.to };\n const chain = editor.chain().focus().setTextSelection(saved);\n if (saved.from === saved.to && !hrefAt(editor, saved)) {\n chain.insertContent({ type: 'text', text: href, marks: [{ type: 'link', attrs: { href } }] }).run();\n } else {\n chain.extendMarkRange('link').setLink({ href }).run();\n }\n onOpenChange(false);\n };\n\n const remove = () => {\n const saved = range.current ?? { from: editor.state.selection.from, to: editor.state.selection.to };\n editor.chain().focus().setTextSelection(saved).extendMarkRange('link').unsetLink().run();\n onOpenChange(false);\n };\n\n return (\n <Popover open={open} onOpenChange={onOpenChange}>\n <PopoverTrigger\n render={\n <ToolbarPrimitive.Button\n type=\"button\"\n aria-label={labels.link}\n title={labels.link}\n aria-pressed={active}\n data-pressed={active ? '' : undefined}\n disabled={disabled}\n className={BUTTON_CLASS}\n />\n }\n >\n <IconLink aria-hidden />\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-80\">\n <form className=\"flex flex-col gap-2\" onSubmit={apply}>\n <Input\n type=\"text\"\n inputMode=\"url\"\n aria-label={labels.linkAddress}\n aria-invalid={invalid || undefined}\n value={address}\n onChange={(event) => {\n setAddress(event.target.value);\n setInvalid(false);\n }}\n />\n {invalid ? <p className=\"text-xs text-destructive\">{labels.linkInvalid}</p> : null}\n <div className=\"flex justify-end gap-2\">\n {active ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={remove}>\n {labels.linkRemove}\n </Button>\n ) : null}\n <Button type=\"submit\" size=\"sm\">\n {labels.linkApply}\n </Button>\n </div>\n </form>\n </PopoverContent>\n </Popover>\n );\n};\n\nexport interface IRichTextToolbarProps {\n linkRange: RefObject<ILinkRange | null>;\n editor: Editor;\n labels: IRichTextLabels;\n fields: IRichTextField[] | undefined;\n disabled: boolean;\n linkOpen: boolean;\n onLinkOpenChange: (open: boolean) => void;\n}\n\nexport const RichTextToolbar = ({ linkRange, editor, labels, fields, disabled, linkOpen, onLinkOpenChange }: IRichTextToolbarProps) => {\n const state = useEditorState({\n editor,\n selector: ({ editor: current }) => ({\n bold: current.isActive('bold'),\n italic: current.isActive('italic'),\n underline: current.isActive('underline'),\n bullets: current.isActive('bulletList'),\n numbers: current.isActive('orderedList'),\n link: current.isActive('link'),\n }),\n });\n\n return (\n <ToolbarPrimitive.Root\n data-slot=\"rich-text-toolbar\"\n aria-label={labels.toolbar}\n className=\"flex flex-wrap items-center gap-0.5 border-b border-input p-1\"\n >\n <ToolbarButton label={labels.bold} pressed={state.bold} disabled={disabled} onClick={() => editor.chain().focus().toggleBold().run()}>\n <IconBold aria-hidden />\n </ToolbarButton>\n <ToolbarButton label={labels.italic} pressed={state.italic} disabled={disabled} onClick={() => editor.chain().focus().toggleItalic().run()}>\n <IconItalic aria-hidden />\n </ToolbarButton>\n <ToolbarButton\n label={labels.underline}\n pressed={state.underline}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleUnderline().run()}\n >\n <IconUnderline aria-hidden />\n </ToolbarButton>\n <ToolbarPrimitive.Separator className=\"mx-1 h-4 w-px bg-border\" />\n <ToolbarButton\n label={labels.bulletList}\n pressed={state.bullets}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleBulletList().run()}\n >\n <IconList aria-hidden />\n </ToolbarButton>\n <ToolbarButton\n label={labels.numberedList}\n pressed={state.numbers}\n disabled={disabled}\n onClick={() => editor.chain().focus().toggleOrderedList().run()}\n >\n <IconListNumbers aria-hidden />\n </ToolbarButton>\n <LinkControl\n range={linkRange}\n editor={editor}\n labels={labels}\n active={state.link}\n disabled={disabled}\n open={linkOpen}\n onOpenChange={onLinkOpenChange}\n />\n <ToolbarButton label={labels.horizontalRule} disabled={disabled} onClick={() => editor.chain().focus().setHorizontalRule().run()}>\n <IconSeparatorHorizontal aria-hidden />\n </ToolbarButton>\n {fields && fields.length > 0 ? (\n <>\n <ToolbarPrimitive.Separator className=\"mx-1 h-4 w-px bg-border\" />\n <DropdownMenu>\n <DropdownMenuTrigger\n render={\n <ToolbarPrimitive.Button\n type=\"button\"\n aria-label={labels.insertField}\n title={labels.insertField}\n disabled={disabled}\n className={BUTTON_CLASS}\n />\n }\n >\n <IconVariable aria-hidden />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-56\">\n {fields.map((field) => (\n <DropdownMenuItem\n key={field.id}\n onClick={() =>\n editor\n .chain()\n .focus()\n .insertContent({ type: 'text', text: `{{${field.id}}}` })\n .run()\n }\n >\n {field.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n </>\n ) : null}\n </ToolbarPrimitive.Root>\n );\n};\n","/** One person (or anything else) the app offers when the writer types @. */\nexport interface IRichTextMentionItem {\n /** What the HTML carries. By default the value is written as `@${id}`, so an email address works as an id. */\n id: string;\n /** What the chip shows while the text is being edited. */\n label: string;\n /** A second, muted line in the list (a role, an email address). */\n secondary?: string;\n}\n\n/** A page of results. Return a plain array instead when there is only ever one page. */\nexport interface IRichTextMentionPage {\n items: IRichTextMentionItem[];\n /** True when asking for `page + 1` would return more. The list loads it when it is scrolled to the end. */\n hasMore?: boolean;\n}\n\nexport interface IRichTextMentionSearchOptions {\n /** 1-based. */\n page: number;\n /** Aborted when the writer types on or closes the list: pass it to `fetch` so a stale search stops. */\n signal: AbortSignal;\n}\n\nexport type TRichTextMentionSearch = (\n query: string,\n options: IRichTextMentionSearchOptions,\n) => Promise<IRichTextMentionItem[] | IRichTextMentionPage>;\n\nexport interface IRichTextMention {\n /** Asked for the first page when the writer types @ and again for every change of the text after it, debounced. */\n search: TRichTextMentionSearch;\n /**\n * How a mention is written into the HTML. The chip exists only while editing; the HTML carries this text\n * and no element. Default: `@${item.id}`.\n */\n toText?: (item: Pick<IRichTextMentionItem, 'id' | 'label'>) => string;\n /** Milliseconds to wait after the last keystroke before searching. Default 250. */\n debounce?: number;\n}\n\n/** A field of a template (a mail merge token). Inserted as the plain text `{{id}}`. */\nexport interface IRichTextField {\n id: string;\n label: string;\n}\n\n/** What a ref to the editor can do, for a button outside it (a merge tag, say). */\nexport interface IRichTextEditorHandle {\n /** Writes plain text at the caret (over the selection), and puts focus back in the editor. */\n insertText: (text: string) => void;\n focus: () => void;\n}\n\n/** Every string the editor shows, so an app can translate them. */\nexport interface IRichTextLabels {\n toolbar: string;\n bold: string;\n italic: string;\n underline: string;\n bulletList: string;\n numberedList: string;\n link: string;\n horizontalRule: string;\n insertField: string;\n linkAddress: string;\n linkApply: string;\n linkRemove: string;\n linkInvalid: string;\n mentionList: string;\n mentionSearching: string;\n mentionEmpty: string;\n mentionError: string;\n mentionLoadingMore: string;\n /** Announced as the list changes. `{count}` is replaced. */\n mentionResults: string;\n}\n\nexport const DEFAULT_RICH_TEXT_LABELS: IRichTextLabels = {\n toolbar: 'Formatting',\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n bulletList: 'Bulleted list',\n numberedList: 'Numbered list',\n link: 'Link',\n horizontalRule: 'Horizontal line',\n insertField: 'Insert a field',\n linkAddress: 'Link address',\n linkApply: 'Apply',\n linkRemove: 'Remove link',\n linkInvalid: 'Enter an http, https or mailto address.',\n mentionList: 'Mentions',\n mentionSearching: 'Searching...',\n mentionEmpty: 'No matches',\n mentionError: 'The search failed',\n mentionLoadingMore: 'Loading more...',\n mentionResults: '{count} results',\n};\n","import { RICH_TEXT_BODY_CLASS } from '@edyn/ui/components/edyn/rich-text-content/rich-text-content';\nimport { ScrollArea } from '@edyn/ui/components/ui/scroll-area';\nimport { cn } from '@edyn/ui/lib/utils';\nimport type { Editor } from '@tiptap/core';\nimport { EditorContent, useEditor, useEditorState } from '@tiptap/react';\nimport type { SuggestionProps } from '@tiptap/suggestion';\nimport {\n type ComponentPropsWithoutRef,\n type Ref,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useReducer,\n useRef,\n useState,\n} from 'react';\nimport { buildExtensions, type IEditorHost } from './extensions';\nimport { MentionList } from './mention-list';\nimport { defaultMentionToText, isDocumentEmpty, serializeDocument } from './serialize';\nimport { isLive, syncEditable, syncValue } from './sync';\nimport { type ILinkRange, RichTextToolbar } from './toolbar';\nimport {\n DEFAULT_RICH_TEXT_LABELS,\n type IRichTextEditorHandle,\n type IRichTextField,\n type IRichTextLabels,\n type IRichTextMention,\n type IRichTextMentionItem,\n} from './types';\n\nconst LINE = 1.5;\n\ninterface ISuggestionState {\n query: string;\n rect: (() => DOMRect | null) | null;\n command: (item: IRichTextMentionItem) => void;\n}\n\nexport interface IRichTextEditorProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'defaultValue' | 'onChange' | 'id'> {\n /** The HTML, when the parent owns it. Pass back what `onChange` gave. An empty editor is `\"\"`. */\n value?: string;\n /** The HTML to start from when the editor owns its own value. */\n defaultValue?: string;\n /** Called with the HTML after every edit. Only the elements in `RICH_TEXT_ELEMENTS` can appear, and `\"\"` when there is no text. */\n onChange?: (html: string) => void;\n placeholder?: string;\n disabled?: boolean;\n /** Shows the content and keeps it selectable and copyable, with no toolbar. */\n readOnly?: boolean;\n /** Draws the error border and sets `aria-invalid`. The message is the form's to draw: point `aria-describedby` at it. */\n invalid?: boolean;\n /**\n * Lines the box is tall when empty.\n * @default 6\n */\n minRows?: number;\n /**\n * Lines it grows to before it scrolls inside.\n * @default 20\n */\n maxRows?: number;\n /** The most characters of text (a mention counts as the text it is written as). An edit past it is refused. Off by default. */\n maxLength?: number;\n /** Turns @ into a search the app answers. Without it, @ is an ordinary character. */\n mention?: IRichTextMention;\n /** Adds an \"Insert a field\" menu that writes `{{id}}` at the caret. */\n fields?: IRichTextField[];\n /**\n * Whether the formatting toolbar shows.\n * @default true\n */\n toolbar?: boolean;\n /** Replaces any of the strings the editor shows (the defaults are English). */\n labels?: Partial<IRichTextLabels>;\n /** On the editable element, so a form can name it. */\n id?: string;\n autoFocus?: boolean;\n /** Called with the files when the writer pastes only files (a screenshot). Without it, such a paste does nothing. */\n onPasteFiles?: (files: File[]) => void;\n /** Gives `insertText` and `focus`, for buttons outside the editor. */\n ref?: Ref<IRichTextEditorHandle>;\n}\n\n/**\n * A small rich-text field: paragraphs, bold, italic, underline, bulleted and numbered lists and links, with optional\n * @mentions the app answers asynchronously. The value is HTML in and out, and only the elements in `RICH_TEXT_ELEMENTS`\n * can come out (no class, no style), whatever is pasted. A mention is a chip while editing and plain text in the HTML.\n * The server should still sanitise: this is a convenience for the writer, not a security boundary.\n */\nexport const RichTextEditor = ({\n value,\n defaultValue = '',\n onChange,\n placeholder,\n disabled = false,\n readOnly = false,\n invalid = false,\n minRows = 6,\n maxRows = 20,\n maxLength,\n mention,\n fields,\n toolbar = true,\n labels,\n id,\n autoFocus = false,\n onPasteFiles,\n ref,\n className,\n 'aria-invalid': ariaInvalid,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n ...props\n}: IRichTextEditorProps) => {\n const isInvalid = invalid || ariaInvalid === true || ariaInvalid === 'true';\n const text = useMemo(() => ({ ...DEFAULT_RICH_TEXT_LABELS, ...labels }), [labels]);\n const listId = useId();\n const [suggestion, setSuggestion] = useState<ISuggestionState | null>(null);\n const [activeOption, setActiveOption] = useState<string | undefined>(undefined);\n const [linkOpen, setLinkOpen] = useState(false);\n const refLinkRange = useRef<ILinkRange | null>(null);\n const refKeys = useRef<((event: KeyboardEvent) => boolean) | null>(null);\n // What the editor and the parent agree on. It starts as the value the editor is built from, so a controlled value\n // that has not changed asks for nothing at mount.\n const refKnown = useRef<string | undefined>(value ?? defaultValue);\n const refPending = useRef<Array<(live: Editor) => void>>([]);\n const [, wake] = useReducer((count: number) => count + 1, 0);\n const editable = !disabled && !readOnly;\n const showToolbar = toolbar && !readOnly;\n\n const latest = useRef({ mention, maxLength, onChange, onPasteFiles, toolbar: showToolbar });\n latest.current = { mention, maxLength, onChange, onPasteFiles, toolbar: showToolbar };\n\n const host = useMemo<IEditorHost>(\n () => ({\n mentionEnabled: () => latest.current.mention !== undefined,\n maxLength: () => latest.current.maxLength,\n toText: () => latest.current.mention?.toText ?? defaultMentionToText,\n onSuggestion: (props: SuggestionProps<IRichTextMentionItem, IRichTextMentionItem> | null) => {\n if (props === null) {\n setActiveOption(undefined);\n }\n setSuggestion(props === null ? null : { query: props.query, rect: props.clientRect ?? null, command: props.command });\n },\n onSuggestionKey: ({ event }) => refKeys.current?.(event) ?? false,\n }),\n [],\n );\n const extensions = useMemo(() => buildExtensions(host), [host]);\n\n const emit = useCallback(\n (current: Editor): string => {\n const html = isDocumentEmpty(current.state.doc) ? '' : serializeDocument(current.state.doc, host.toText());\n refKnown.current = html;\n return html;\n },\n [host],\n );\n\n const attributes = useMemo(() => {\n const entries: Record<string, string | undefined> = {\n role: 'textbox',\n 'aria-multiline': 'true',\n 'aria-autocomplete': mention ? 'list' : undefined,\n 'aria-controls': suggestion ? listId : undefined,\n 'aria-activedescendant': suggestion ? activeOption : undefined,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': isInvalid ? 'true' : undefined,\n 'aria-readonly': readOnly ? 'true' : undefined,\n 'aria-disabled': disabled ? 'true' : undefined,\n 'aria-placeholder': placeholder,\n tabindex: readOnly && !disabled ? '0' : undefined,\n id,\n 'data-slot': 'rich-text-editor-content',\n class: cn(RICH_TEXT_BODY_CLASS, 'min-h-(--rich-text-min) px-2.5 py-2 outline-none'),\n };\n return Object.fromEntries(Object.entries(entries).filter((entry): entry is [string, string] => entry[1] !== undefined));\n }, [activeOption, ariaDescribedBy, ariaLabel, ariaLabelledBy, disabled, id, isInvalid, listId, mention, placeholder, readOnly, suggestion]);\n\n const editor = useEditor({\n extensions,\n content: value ?? defaultValue,\n editable,\n autofocus: autoFocus ? 'end' : false,\n editorProps: {\n attributes,\n handlePaste: (_view, event) => {\n const data = event.clipboardData;\n const onlyFiles = data !== null && data.files.length > 0 && data.getData('text/plain') === '' && data.getData('text/html') === '';\n if (!onlyFiles || !latest.current.onPasteFiles) {\n return false;\n }\n latest.current.onPasteFiles(Array.from(data.files));\n return true;\n },\n handleKeyDown: (view, event) => {\n if ((event.metaKey || event.ctrlKey) && !event.altKey && !event.shiftKey && event.key.toLowerCase() === 'k' && latest.current.toolbar) {\n event.preventDefault();\n refLinkRange.current = { from: view.state.selection.from, to: view.state.selection.to };\n setLinkOpen(true);\n return true;\n }\n return false;\n },\n },\n onBlur: () => {\n setSuggestion(null);\n setActiveOption(undefined);\n },\n onUpdate: ({ editor: current }) => {\n latest.current.onChange?.(emit(current));\n },\n });\n\n // useEditor can replace the editor (it destroys one that was not mounted in time, and in development a second render\n // makes a second), so readiness is read off the editor in hand: wake up when this one finishes initialising.\n const ready = isLive(editor);\n useEffect(() => {\n editor.on('create', wake);\n wake();\n return () => {\n editor.off('create', wake);\n };\n }, [editor]);\n\n const whenLive = useCallback(\n (action: (live: Editor) => void) => {\n if (isLive(editor)) {\n action(editor);\n } else {\n refPending.current.push(action);\n }\n },\n [editor],\n );\n\n useImperativeHandle(\n ref,\n () => ({\n insertText: (text) => {\n whenLive((live) => {\n live.chain().focus().insertContent({ type: 'text', text }).run();\n });\n },\n focus: () => {\n whenLive((live) => {\n live.commands.focus();\n });\n },\n }),\n [whenLive],\n );\n\n useEffect(() => {\n if (!ready || !isLive(editor)) {\n return;\n }\n for (const action of refPending.current.splice(0)) {\n action(editor);\n }\n }, [editor, ready]);\n\n useEffect(() => {\n if (ready) {\n syncEditable(editor, editable);\n }\n }, [editable, editor, ready]);\n\n useEffect(() => {\n if (ready) {\n syncValue(editor, value, refKnown);\n }\n }, [editor, ready, value]);\n\n const empty = useEditorState({ editor, selector: ({ editor: current }) => isDocumentEmpty(current.state.doc) });\n\n const pick = useCallback(\n (item: IRichTextMentionItem) => {\n suggestion?.command(item);\n },\n [suggestion],\n );\n\n return (\n <div\n data-slot=\"rich-text-editor\"\n data-invalid={isInvalid ? '' : undefined}\n data-disabled={disabled ? '' : undefined}\n data-readonly={readOnly ? '' : undefined}\n className={cn(\n 'flex w-full min-w-0 flex-col rounded-lg border border-input bg-transparent text-base transition-colors focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/50 data-disabled:pointer-events-none data-disabled:cursor-not-allowed data-disabled:bg-input/50 data-disabled:opacity-50 data-invalid:border-destructive data-invalid:ring-3 data-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:data-disabled:bg-input/80 dark:data-invalid:ring-destructive/40',\n className,\n )}\n {...props}\n >\n {showToolbar ? (\n <RichTextToolbar\n editor={editor}\n labels={text}\n fields={fields}\n disabled={disabled}\n linkOpen={linkOpen}\n linkRange={refLinkRange}\n onLinkOpenChange={(next) => {\n if (next && !linkOpen) {\n refLinkRange.current = { from: editor.state.selection.from, to: editor.state.selection.to };\n }\n setLinkOpen(next);\n }}\n />\n ) : null}\n <ScrollArea\n className=\"relative\"\n style={{ maxHeight: `${maxRows * LINE + 1}rem`, ['--rich-text-min' as string]: `${minRows * LINE + 1}rem` }}\n focusable={false}\n >\n {empty && placeholder ? (\n <p aria-hidden className=\"pointer-events-none absolute start-2.5 top-2 text-muted-foreground\">\n {placeholder}\n </p>\n ) : null}\n <EditorContent editor={editor} />\n </ScrollArea>\n {suggestion && mention ? (\n <MentionList\n query={suggestion.query}\n rect={suggestion.rect}\n config={mention}\n labels={text}\n listId={listId}\n onPick={pick}\n keyHandler={refKeys}\n onActiveChange={setActiveOption}\n />\n ) : null}\n </div>\n );\n};\n"],"mappings":"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"}
package/dist/styles.css CHANGED
@@ -535,6 +535,10 @@
535
535
  top: 0;
536
536
  }
537
537
 
538
+ .top-0\.5 {
539
+ top: calc(var(--spacing) * .5);
540
+ }
541
+
538
542
  .top-1\.5 {
539
543
  top: calc(var(--spacing) * 1.5);
540
544
  }
@@ -583,6 +587,10 @@
583
587
  right: 0;
584
588
  }
585
589
 
590
+ .right-0\.5 {
591
+ right: calc(var(--spacing) * .5);
592
+ }
593
+
586
594
  .right-1 {
587
595
  right: var(--spacing);
588
596
  }
@@ -2310,6 +2318,10 @@
2310
2318
  padding-right: calc(var(--spacing) * 8);
2311
2319
  }
2312
2320
 
2321
+ .pr-9 {
2322
+ padding-right: calc(var(--spacing) * 9);
2323
+ }
2324
+
2313
2325
  .pb-2 {
2314
2326
  padding-bottom: calc(var(--spacing) * 2);
2315
2327
  }
@@ -2696,6 +2708,11 @@
2696
2708
  outline-width: 1px;
2697
2709
  }
2698
2710
 
2711
+ .blur {
2712
+ --tw-blur: blur(8px);
2713
+ filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
2714
+ }
2715
+
2699
2716
  .filter {
2700
2717
  filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
2701
2718
  }
@@ -4059,6 +4076,10 @@
4059
4076
  cursor: not-allowed;
4060
4077
  }
4061
4078
 
4079
+ .disabled\:border-transparent:disabled {
4080
+ border-color: #0000;
4081
+ }
4082
+
4062
4083
  .disabled\:bg-input\/50:disabled {
4063
4084
  background-color: var(--input);
4064
4085
  }
@@ -4069,14 +4090,38 @@
4069
4090
  }
4070
4091
  }
4071
4092
 
4093
+ .disabled\:bg-muted:disabled {
4094
+ background-color: var(--muted);
4095
+ }
4096
+
4072
4097
  .disabled\:bg-transparent:disabled {
4073
4098
  background-color: #0000;
4074
4099
  }
4075
4100
 
4101
+ .disabled\:text-foreground\/60:disabled {
4102
+ color: var(--foreground);
4103
+ }
4104
+
4105
+ @supports (color: color-mix(in lab, red, red)) {
4106
+ .disabled\:text-foreground\/60:disabled {
4107
+ color: color-mix(in oklab, var(--foreground) 60%, transparent);
4108
+ }
4109
+ }
4110
+
4076
4111
  .disabled\:opacity-50:disabled {
4077
4112
  opacity: .5;
4078
4113
  }
4079
4114
 
4115
+ .disabled\:shadow-none:disabled {
4116
+ --tw-shadow: 0 0 #0000;
4117
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
4118
+ }
4119
+
4120
+ .disabled\:focus-visible\:ring-0:disabled:focus-visible {
4121
+ --tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
4122
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
4123
+ }
4124
+
4080
4125
  :where([data-orientation="horizontal"]) .in-data-\[orientation\=horizontal\]\:w-px {
4081
4126
  width: 1px;
4082
4127
  }
@@ -4413,10 +4458,38 @@
4413
4458
  pointer-events: none;
4414
4459
  }
4415
4460
 
4461
+ .aria-disabled\:border-transparent[aria-disabled="true"] {
4462
+ border-color: #0000;
4463
+ }
4464
+
4465
+ .aria-disabled\:bg-muted[aria-disabled="true"] {
4466
+ background-color: var(--muted);
4467
+ }
4468
+
4469
+ .aria-disabled\:text-foreground\/60[aria-disabled="true"] {
4470
+ color: var(--foreground);
4471
+ }
4472
+
4473
+ @supports (color: color-mix(in lab, red, red)) {
4474
+ .aria-disabled\:text-foreground\/60[aria-disabled="true"] {
4475
+ color: color-mix(in oklab, var(--foreground) 60%, transparent);
4476
+ }
4477
+ }
4478
+
4416
4479
  .aria-disabled\:opacity-50[aria-disabled="true"] {
4417
4480
  opacity: .5;
4418
4481
  }
4419
4482
 
4483
+ .aria-disabled\:shadow-none[aria-disabled="true"] {
4484
+ --tw-shadow: 0 0 #0000;
4485
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
4486
+ }
4487
+
4488
+ .aria-disabled\:focus-visible\:ring-0[aria-disabled="true"]:focus-visible {
4489
+ --tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
4490
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
4491
+ }
4492
+
4420
4493
  .aria-expanded\:bg-muted[aria-expanded="true"] {
4421
4494
  background-color: var(--muted);
4422
4495
  }
@@ -5824,6 +5897,10 @@
5824
5897
  }
5825
5898
  }
5826
5899
 
5900
+ .dark\:disabled\:border-transparent:is(.dark *):disabled {
5901
+ border-color: #0000;
5902
+ }
5903
+
5827
5904
  .dark\:disabled\:bg-input\/80:is(.dark *):disabled {
5828
5905
  background-color: var(--input);
5829
5906
  }
@@ -5834,6 +5911,10 @@
5834
5911
  }
5835
5912
  }
5836
5913
 
5914
+ .dark\:disabled\:bg-muted:is(.dark *):disabled {
5915
+ background-color: var(--muted);
5916
+ }
5917
+
5837
5918
  .dark\:disabled\:bg-transparent:is(.dark *):disabled {
5838
5919
  background-color: #0000;
5839
5920
  }
@@ -5878,6 +5959,14 @@
5878
5959
  }
5879
5960
  }
5880
5961
 
5962
+ .dark\:aria-disabled\:border-transparent:is(.dark *)[aria-disabled="true"] {
5963
+ border-color: #0000;
5964
+ }
5965
+
5966
+ .dark\:aria-disabled\:bg-muted:is(.dark *)[aria-disabled="true"] {
5967
+ background-color: var(--muted);
5968
+ }
5969
+
5881
5970
  .dark\:aria-invalid\:border-destructive\/50:is(.dark *)[aria-invalid="true"] {
5882
5971
  border-color: var(--destructive);
5883
5972
  }
@@ -6163,6 +6252,10 @@
6163
6252
  cursor: not-allowed;
6164
6253
  }
6165
6254
 
6255
+ .data-disabled\:border-transparent:where([data-disabled="true"]), .data-disabled\:border-transparent:where([data-disabled]:not([data-disabled="false"])) {
6256
+ border-color: #0000;
6257
+ }
6258
+
6166
6259
  .data-disabled\:bg-input\/50:where([data-disabled="true"]), .data-disabled\:bg-input\/50:where([data-disabled]:not([data-disabled="false"])) {
6167
6260
  background-color: var(--input);
6168
6261
  }
@@ -6173,10 +6266,38 @@
6173
6266
  }
6174
6267
  }
6175
6268
 
6269
+ .data-disabled\:bg-muted:where([data-disabled="true"]), .data-disabled\:bg-muted:where([data-disabled]:not([data-disabled="false"])) {
6270
+ background-color: var(--muted);
6271
+ }
6272
+
6273
+ .data-disabled\:text-foreground\/60:where([data-disabled="true"]), .data-disabled\:text-foreground\/60:where([data-disabled]:not([data-disabled="false"])) {
6274
+ color: var(--foreground);
6275
+ }
6276
+
6277
+ @supports (color: color-mix(in lab, red, red)) {
6278
+ .data-disabled\:text-foreground\/60:where([data-disabled="true"]), .data-disabled\:text-foreground\/60:where([data-disabled]:not([data-disabled="false"])) {
6279
+ color: color-mix(in oklab, var(--foreground) 60%, transparent);
6280
+ }
6281
+ }
6282
+
6176
6283
  .data-disabled\:opacity-50:where([data-disabled="true"]), .data-disabled\:opacity-50:where([data-disabled]:not([data-disabled="false"])) {
6177
6284
  opacity: .5;
6178
6285
  }
6179
6286
 
6287
+ .data-disabled\:shadow-none:where([data-disabled="true"]), .data-disabled\:shadow-none:where([data-disabled]:not([data-disabled="false"])) {
6288
+ --tw-shadow: 0 0 #0000;
6289
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
6290
+ }
6291
+
6292
+ :is(.data-disabled\:focus-visible\:ring-0:where([data-disabled="true"]), .data-disabled\:focus-visible\:ring-0:where([data-disabled]:not([data-disabled="false"]))):focus-visible {
6293
+ --tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
6294
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
6295
+ }
6296
+
6297
+ .dark\:data-disabled\:border-transparent:is(.dark *):where([data-disabled="true"]), .dark\:data-disabled\:border-transparent:is(.dark *):where([data-disabled]:not([data-disabled="false"])) {
6298
+ border-color: #0000;
6299
+ }
6300
+
6180
6301
  .dark\:data-disabled\:bg-input\/80:is(.dark *):where([data-disabled="true"]), .dark\:data-disabled\:bg-input\/80:is(.dark *):where([data-disabled]:not([data-disabled="false"])) {
6181
6302
  background-color: var(--input);
6182
6303
  }
@@ -6187,6 +6308,10 @@
6187
6308
  }
6188
6309
  }
6189
6310
 
6311
+ .dark\:data-disabled\:bg-muted:is(.dark *):where([data-disabled="true"]), .dark\:data-disabled\:bg-muted:is(.dark *):where([data-disabled]:not([data-disabled="false"])) {
6312
+ background-color: var(--muted);
6313
+ }
6314
+
6190
6315
  .data-active\:bg-background:where([data-state="active"]), .data-active\:bg-background:where([data-active]:not([data-active="false"])) {
6191
6316
  background-color: var(--background);
6192
6317
  }
@@ -1,4 +1,4 @@
1
- import { RefObject } from 'react';
1
+ import { ComponentPropsWithoutRef, RefObject } from 'react';
2
2
  /** Thousands separated, rounded to a whole number: the default way a count reads. */
3
3
  export declare const formatCount: (value: number) => string;
4
4
  /**
@@ -7,7 +7,7 @@ export declare const formatCount: (value: number) => string;
7
7
  * been on screen.
8
8
  */
9
9
  export declare const useAnimatedValues: (targets: number[], element: RefObject<Element | null>) => number[];
10
- export interface IAnimatedNumberProps {
10
+ export interface IAnimatedNumberProps extends Omit<ComponentPropsWithoutRef<'span'>, 'children' | 'className'> {
11
11
  value: number;
12
12
  /** What it shows while it moves and once there (formatCount by default; a percentage formatter for shares). */
13
13
  format?: (value: number) => string;
@@ -18,8 +18,8 @@ export interface IAnimatedNumberProps {
18
18
  * and where it lands, in tabular figures, so nothing beside it moves while the digits
19
19
  * change. Assistive technology reads only the final value.
20
20
  */
21
- export declare const AnimatedNumber: ({ value, format, className }: IAnimatedNumberProps) => import('react').JSX.Element;
22
- export interface INumberTextProps {
21
+ export declare const AnimatedNumber: ({ value, format, className, ...props }: IAnimatedNumberProps) => import('react').JSX.Element;
22
+ export interface INumberTextProps extends Omit<ComponentPropsWithoutRef<'span'>, 'children' | 'className'> {
23
23
  element?: RefObject<HTMLSpanElement | null>;
24
24
  shown: number;
25
25
  value: number;
@@ -27,4 +27,4 @@ export interface INumberTextProps {
27
27
  className?: string;
28
28
  }
29
29
  /** The text of a moving number: what it shows now, held at its widest, with the final value for assistive technology. */
30
- export declare const NumberText: ({ element, shown, value, format, className }: INumberTextProps) => import('react').JSX.Element;
30
+ export declare const NumberText: ({ element, shown, value, format, className, ...props }: INumberTextProps) => import('react').JSX.Element;
@@ -1,5 +1,6 @@
1
1
  import { TCssLength } from '../../../lib/utils';
2
- export interface IAudioPlayerProps {
2
+ import { ComponentPropsWithoutRef } from 'react';
3
+ export interface IAudioPlayerProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'className' | 'onPlay' | 'onPause' | 'onEnded' | 'onTimeUpdate' | 'role'> {
3
4
  /** Audio source URL. */
4
5
  src?: string;
5
6
  /** Start muted. The volume control still works from here. */
@@ -26,4 +27,4 @@ export interface IAudioPlayerProps {
26
27
  * time, a seekable timeline, and volume. Four elements in one rounded row, per
27
28
  * the design-system anatomy.
28
29
  */
29
- export declare const AudioPlayer: ({ src, muted, loop, disabled, width, className, "aria-label": ariaLabel, onPlay, onPause, onEnded, onTimeUpdate, }: IAudioPlayerProps) => import('react').JSX.Element;
30
+ export declare const AudioPlayer: ({ src, muted, loop, disabled, width, className, "aria-label": ariaLabel, style, onPlay, onPause, onEnded, onTimeUpdate, ...props }: IAudioPlayerProps) => import('react').JSX.Element;