@neuronection/assistant-ui 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +3 -0
- package/dist/ai-actions-dropdown.d.ts +3 -0
- package/dist/ai-actions-dropdown.js +1 -1
- package/dist/ai-text-transform.d.ts +44 -0
- package/dist/ai-text-transform.js +3 -0
- package/dist/ai-text-transform.js.map +1 -0
- package/dist/chunk-2PR6POP6.js +543 -0
- package/dist/chunk-2PR6POP6.js.map +1 -0
- package/dist/chunk-BKAO7BTU.js +156 -0
- package/dist/chunk-BKAO7BTU.js.map +1 -0
- package/dist/chunk-KAC2DOLH.js +362 -0
- package/dist/chunk-KAC2DOLH.js.map +1 -0
- package/dist/chunk-LWSLNCW2.js +271 -0
- package/dist/chunk-LWSLNCW2.js.map +1 -0
- package/dist/chunk-XUDCCQRN.js +253 -0
- package/dist/chunk-XUDCCQRN.js.map +1 -0
- package/dist/dictation.d.ts +64 -0
- package/dist/dictation.js +3 -0
- package/dist/dictation.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +16 -12
- package/dist/index.js.map +1 -1
- package/dist/rich-text-editor.d.ts +51 -0
- package/dist/rich-text-editor.js +3 -0
- package/dist/rich-text-editor.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/text-diff-view.d.ts +61 -0
- package/dist/text-diff-view.js +3 -0
- package/dist/text-diff-view.js.map +1 -0
- package/package.json +24 -2
- package/dist/chunk-I37SYHM7.js +0 -123
- package/dist/chunk-I37SYHM7.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/dictation/DictationButton.tsx","../src/components/dictation/useDictation.ts"],"names":["useRef","useEffect"],"mappings":"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","file":"chunk-KAC2DOLH.js","sourcesContent":["import * as React from 'react'\nimport { Loader2, Mic, Square, X } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\n\nimport type { DictationError, DictationStatus } from './useDictation'\n\nconst BAR_WEIGHTS = [0.45, 0.62, 0.8, 0.92, 1.05]\n\nexport interface DictationButtonProps {\n status: DictationStatus\n onStart: () => void\n /** Accessible name / tooltip. English default: 'Dictate'. */\n label?: string\n recordingLabel?: string\n className?: string\n}\n\nexport function DictationButton({\n status,\n onStart,\n label = 'Dictate',\n recordingLabel,\n className,\n}: DictationButtonProps) {\n return (\n <button\n type=\"button\"\n title={label}\n aria-label={label}\n aria-pressed={status === 'recording' ? true : status === 'transcribing' ? undefined : false}\n disabled={status === 'transcribing'}\n data-as=\"dictation-button\"\n className={cn(\n 'rounded p-1.5 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--as-focus-ring)]',\n status === 'recording'\n ? 'animate-pulse bg-[var(--as-danger)]/10 text-[var(--as-danger)]'\n : 'text-[var(--as-muted-fg)] hover:text-[var(--as-fg)]',\n className,\n )}\n onClick={onStart}\n >\n <Mic className=\"size-4\" aria-hidden />\n <span className=\"sr-only\">{recordingLabel ?? label}</span>\n </button>\n )\n}\n\nfunction LevelBars({\n levelRef,\n active,\n}: {\n levelRef: React.RefObject<number>\n active: boolean\n}) {\n const barsRef = React.useRef<Array<HTMLSpanElement | null>>([])\n React.useEffect(() => {\n if (!active) {\n return\n }\n let frame = requestAnimationFrame(function tick() {\n const level = Math.min(1, levelRef.current ?? 0)\n barsRef.current.forEach((bar, index) => {\n if (bar !== null) {\n const weight = BAR_WEIGHTS[index] ?? 1\n const height = Math.max(0.15, Math.min(1, level * weight))\n bar.style.transform = `scaleY(${height})`\n }\n })\n frame = requestAnimationFrame(tick)\n })\n return () => cancelAnimationFrame(frame)\n }, [active, levelRef])\n return (\n <span className=\"flex h-4 items-end gap-0.5\" aria-hidden>\n {BAR_WEIGHTS.map((_, index) => (\n <span\n key={index}\n ref={(element) => {\n barsRef.current[index] = element\n }}\n className=\"h-4 w-1 origin-bottom rounded-full bg-[var(--as-danger)] opacity-40\"\n />\n ))}\n </span>\n )\n}\n\nexport interface DictationStripLabels {\n recording?: string\n transcribing?: string\n stop?: string\n cancel?: string\n dismissError?: string\n unsupported?: string\n denied?: string\n unassigned?: string\n /** `{detail}` is interpolated with the transport error message. */\n failed?: string\n}\n\nconst DEFAULT_STRIP_LABELS: Required<DictationStripLabels> = {\n recording: 'Recording…',\n transcribing: 'Transcribing…',\n stop: 'Stop',\n cancel: 'Cancel',\n dismissError: 'Dismiss',\n unsupported: 'Speech input is not supported in this browser.',\n denied: 'Microphone access was denied.',\n unassigned: 'No speech-to-text model is assigned.',\n failed: 'Transcription failed. {detail}',\n}\n\nexport interface DictationStripProps {\n status: DictationStatus\n seconds: number\n levelRef: React.RefObject<number>\n error: DictationError | null\n labels?: Partial<DictationStripLabels>\n onStop: () => void\n onCancel: () => void\n onDismissError: () => void\n className?: string\n}\n\nexport function DictationStrip({\n status,\n seconds,\n levelRef,\n error,\n labels,\n onStop,\n onCancel,\n onDismissError,\n className,\n}: DictationStripProps) {\n const merged = { ...DEFAULT_STRIP_LABELS, ...labels }\n const formatTime = (total: number) => {\n const minutes = Math.floor(total / 60)\n const padded = String(total % 60).padStart(2, '0')\n return `${String(minutes).padStart(2, '0')}:${padded}`\n }\n const errorText =\n error === null\n ? ''\n : error.kind === 'unsupported'\n ? merged.unsupported\n : error.kind === 'denied'\n ? merged.denied\n : error.kind === 'unassigned'\n ? merged.unassigned\n : merged.failed.replace('{detail}', error.detail ?? '')\n if (error !== null) {\n return (\n <div\n data-as=\"dictation-strip\"\n className={cn(\n 'flex items-center gap-2 rounded-md border border-dashed border-[var(--as-warning)] px-2.5 py-1.5 text-xs text-[var(--as-warning)]',\n className,\n )}\n role=\"alert\"\n >\n <span className=\"min-w-0 flex-1 break-words\">{errorText}</span>\n <button\n type=\"button\"\n aria-label={merged.dismissError}\n title={merged.dismissError}\n className=\"rounded-full p-0.5 hover:opacity-70\"\n onClick={onDismissError}\n >\n <X className=\"size-3.5\" aria-hidden />\n </button>\n </div>\n )\n }\n if (status === 'idle') {\n return null\n }\n return (\n <div\n data-as=\"dictation-strip\"\n className={cn(\n 'flex items-center gap-2 rounded-md border border-[var(--as-border)] bg-[var(--as-surface)] px-2.5 py-1.5 text-xs',\n className,\n )}\n role=\"status\"\n aria-label={merged.recording}\n >\n {status === 'recording' ? (\n <>\n <span\n className=\"size-2 shrink-0 animate-pulse rounded-full bg-[var(--as-danger)]\"\n aria-hidden\n />\n <span className=\"tabular-nums font-medium text-[var(--as-fg)]\">\n {formatTime(seconds)}\n </span>\n <LevelBars levelRef={levelRef} active />\n <span className=\"min-w-0 flex-1 truncate text-[var(--as-muted-fg)]\">\n {merged.recording}\n </span>\n <button\n type=\"button\"\n aria-label={merged.cancel}\n title={merged.cancel}\n className=\"rounded p-1 text-[var(--as-muted-fg)] hover:text-[var(--as-fg)]\"\n onClick={onCancel}\n >\n <X className=\"size-3.5\" aria-hidden />\n </button>\n <button\n type=\"button\"\n title={merged.stop}\n aria-label={merged.stop}\n className=\"flex items-center gap-1 rounded bg-[var(--as-danger)] px-2 py-1 font-medium\"\n onClick={onStop}\n >\n <Square className=\"size-3\" aria-hidden />\n {merged.stop}\n </button>\n </>\n ) : (\n <>\n <Loader2\n className=\"size-3.5 shrink-0 animate-spin text-[var(--as-muted-fg)]\"\n aria-hidden\n />\n <span className=\"min-w-0 flex-1 text-[var(--as-muted-fg)]\">\n {merged.transcribing}\n </span>\n </>\n )}\n </div>\n )\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\n\nexport type DictationStatus = 'idle' | 'recording' | 'transcribing'\n\nexport interface DictationError {\n kind: 'unsupported' | 'denied' | 'unassigned' | 'failed'\n detail?: string\n}\n\nexport interface DictationResult {\n text: string\n}\n\nexport interface UseDictationOptions {\n /** App-owned transport: upload the blob, resolve with the transcript. */\n transcribe: (audio: Blob) => Promise<DictationResult>\n /** Map a transport failure to a structured error (e.g. 409 → 'unassigned'). */\n classifyError?: (error: unknown) => DictationError\n /** Called with the transcript on success. */\n onResult?: (text: string) => void\n}\n\nconst PREFERRED_MIME_TYPES = [\n 'audio/webm;codecs=opus',\n 'audio/webm',\n 'audio/ogg;codecs=opus',\n 'audio/mp4',\n]\n\nconst MAX_LEVEL = 1\nconst LEVEL_BOOST = 4\nconst LEVEL_DECAY = 0.85\n\nfunction pickMimeType(): string | null {\n if (typeof MediaRecorder === 'undefined') {\n return null\n }\n for (const mimeType of PREFERRED_MIME_TYPES) {\n if (MediaRecorder.isTypeSupported(mimeType)) {\n return mimeType\n }\n }\n return null\n}\n\nexport function useDictation(options: UseDictationOptions) {\n const [status, setStatus] = useState<DictationStatus>('idle')\n const [seconds, setSeconds] = useState(0)\n const [error, setError] = useState<DictationError | null>(null)\n\n const optionsRef = useRef(options)\n optionsRef.current = options\n\n const recorderRef = useRef<MediaRecorder | null>(null)\n const streamRef = useRef<MediaStream | null>(null)\n const chunksRef = useRef<BlobPart[]>([])\n const audioContextRef = useRef<AudioContext | null>(null)\n const rafRef = useRef<number | null>(null)\n const timerRef = useRef<number | null>(null)\n const levelRef = useRef(0)\n\n const teardown = useCallback(() => {\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current)\n rafRef.current = null\n }\n if (timerRef.current !== null) {\n window.clearInterval(timerRef.current)\n timerRef.current = null\n }\n audioContextRef.current?.close().catch(() => undefined)\n audioContextRef.current = null\n streamRef.current?.getTracks().forEach((track) => track.stop())\n streamRef.current = null\n recorderRef.current = null\n levelRef.current = 0\n }, [])\n\n const startMeter = useCallback((stream: MediaStream) => {\n if (typeof AudioContext === 'undefined') {\n return\n }\n const context = new AudioContext()\n audioContextRef.current = context\n const analyser = context.createAnalyser()\n analyser.fftSize = 512\n context.createMediaStreamSource(stream).connect(analyser)\n const buffer = new Uint8Array(analyser.fftSize)\n const tick = () => {\n analyser.getByteTimeDomainData(buffer)\n let sum = 0\n for (const value of buffer) {\n const centered = (value - 128) / 128\n sum += centered * centered\n }\n const rms = Math.sqrt(sum / buffer.length)\n levelRef.current = Math.min(\n MAX_LEVEL,\n Math.max(rms * LEVEL_BOOST, levelRef.current * LEVEL_DECAY),\n )\n rafRef.current = requestAnimationFrame(tick)\n }\n rafRef.current = requestAnimationFrame(tick)\n }, [])\n\n const start = useCallback(async () => {\n if (status !== 'idle') {\n return\n }\n setError(null)\n if (\n typeof navigator === 'undefined' ||\n !navigator.mediaDevices?.getUserMedia ||\n typeof MediaRecorder === 'undefined'\n ) {\n setError({ kind: 'unsupported' })\n return\n }\n let stream: MediaStream\n try {\n stream = await navigator.mediaDevices.getUserMedia({ audio: true })\n } catch (requestError) {\n const name = requestError instanceof DOMException ? requestError.name : ''\n setError(\n name === 'NotAllowedError' || name === 'SecurityError' || name === 'NotFoundError'\n ? { kind: 'denied' }\n : {\n kind: 'failed',\n detail:\n requestError instanceof Error\n ? requestError.message\n : String(requestError),\n },\n )\n return\n }\n const mimeType = pickMimeType()\n const recorder = new MediaRecorder(stream, mimeType ? { mimeType } : undefined)\n const chunks: BlobPart[] = []\n recorder.ondataavailable = (event) => {\n if (event.data.size > 0) {\n chunks.push(event.data)\n }\n }\n recorderRef.current = recorder\n streamRef.current = stream\n chunksRef.current = chunks\n recorder.start(250)\n setSeconds(0)\n setStatus('recording')\n startMeter(stream)\n timerRef.current = window.setInterval(() => {\n setSeconds((current) => current + 1)\n }, 1000)\n }, [startMeter, status])\n\n const cancel = useCallback(() => {\n const recorder = recorderRef.current\n if (recorder !== null && recorder.state !== 'inactive') {\n recorder.onstop = null\n recorder.stop()\n }\n teardown()\n setSeconds(0)\n setStatus('idle')\n }, [teardown])\n\n const stop = useCallback(async () => {\n const recorder = recorderRef.current\n if (recorder === null || recorder.state === 'inactive') {\n return\n }\n const mimeType = recorder.mimeType || 'audio/webm'\n const chunks = chunksRef.current\n const stopped = new Promise<void>((resolve) => {\n recorder.onstop = () => resolve()\n })\n recorder.stop()\n await stopped\n teardown()\n setSeconds(0)\n setStatus('transcribing')\n try {\n const blob = new Blob(chunks, { type: mimeType })\n const result = await optionsRef.current.transcribe(blob)\n setStatus('idle')\n optionsRef.current.onResult?.(result.text)\n } catch (transcribeError) {\n const classified =\n optionsRef.current.classifyError?.(transcribeError) ??\n ({\n kind: 'failed',\n detail:\n transcribeError instanceof Error\n ? transcribeError.message\n : String(transcribeError),\n } satisfies DictationError)\n setError(classified)\n setStatus('idle')\n }\n }, [teardown])\n\n const dismissError = useCallback(() => {\n setError(null)\n }, [])\n\n useEffect(\n () => () => {\n const recorder = recorderRef.current\n if (recorder !== null && recorder.state !== 'inactive') {\n recorder.onstop = null\n recorder.stop()\n }\n teardown()\n },\n [teardown],\n )\n\n return { status, seconds, error, levelRef, start, stop, cancel, dismissError }\n}\n"]}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { Popover, PopoverTrigger, PopoverContent } from './chunk-SIIY2EGI.js';
|
|
2
|
+
import { cn } from './chunk-BLJWR4ZV.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { ChevronDown, Sparkles, Send } from 'lucide-react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var triggerTone = "bg-[color-mix(in_srgb,var(--as-ai)_12%,transparent)] text-[var(--as-ai)]";
|
|
8
|
+
var AiActionsDropdown = React.forwardRef(function AiActionsDropdown2({
|
|
9
|
+
actions,
|
|
10
|
+
onAction,
|
|
11
|
+
onPrompt,
|
|
12
|
+
busy = false,
|
|
13
|
+
error,
|
|
14
|
+
label = "AI actions",
|
|
15
|
+
title,
|
|
16
|
+
promptLabel = "Ask something custom",
|
|
17
|
+
promptPlaceholder,
|
|
18
|
+
promptSubmitLabel = "Send",
|
|
19
|
+
disabled = false,
|
|
20
|
+
align = "end",
|
|
21
|
+
side = "bottom",
|
|
22
|
+
className,
|
|
23
|
+
panelClassName,
|
|
24
|
+
primaryAction,
|
|
25
|
+
primaryLabel,
|
|
26
|
+
moreLabel = "More AI actions"
|
|
27
|
+
}, ref) {
|
|
28
|
+
const [open, setOpen] = React.useState(false);
|
|
29
|
+
const [prompt, setPrompt] = React.useState("");
|
|
30
|
+
const sendPrompt = () => {
|
|
31
|
+
const trimmed = prompt.trim();
|
|
32
|
+
if (!trimmed || busy || !onPrompt) return;
|
|
33
|
+
onPrompt(trimmed);
|
|
34
|
+
setPrompt("");
|
|
35
|
+
};
|
|
36
|
+
const panelActions = primaryAction ? actions.filter((action) => action.id !== primaryAction.id) : actions;
|
|
37
|
+
const focusRing = "focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]";
|
|
38
|
+
const disabledState = "disabled:pointer-events-none disabled:opacity-50";
|
|
39
|
+
if (primaryAction) {
|
|
40
|
+
const busyLike = busy || disabled;
|
|
41
|
+
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
|
|
42
|
+
/* @__PURE__ */ jsxs(
|
|
43
|
+
"span",
|
|
44
|
+
{
|
|
45
|
+
"data-as": "ai-actions-split",
|
|
46
|
+
className: cn(
|
|
47
|
+
"relative inline-flex items-center rounded-full font-medium",
|
|
48
|
+
triggerTone,
|
|
49
|
+
className
|
|
50
|
+
),
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ jsxs(
|
|
53
|
+
"button",
|
|
54
|
+
{
|
|
55
|
+
ref,
|
|
56
|
+
type: "button",
|
|
57
|
+
"data-as": "ai-actions-primary",
|
|
58
|
+
"aria-label": primaryLabel,
|
|
59
|
+
disabled: busyLike,
|
|
60
|
+
onClick: () => onAction(primaryAction),
|
|
61
|
+
className: cn(
|
|
62
|
+
"inline-flex cursor-pointer items-center gap-1.5 rounded-full py-1.5 pl-3 pr-2 text-sm transition-[filter] hover:brightness-95",
|
|
63
|
+
focusRing,
|
|
64
|
+
disabledState
|
|
65
|
+
),
|
|
66
|
+
children: [
|
|
67
|
+
/* @__PURE__ */ jsx(primaryAction.icon, { className: "size-4", "aria-hidden": true }),
|
|
68
|
+
/* @__PURE__ */ jsx("span", { children: primaryLabel ?? primaryAction.label })
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
),
|
|
72
|
+
/* @__PURE__ */ jsx(
|
|
73
|
+
"span",
|
|
74
|
+
{
|
|
75
|
+
"aria-hidden": true,
|
|
76
|
+
className: cn(
|
|
77
|
+
"my-1 w-px self-stretch",
|
|
78
|
+
"bg-[color-mix(in_srgb,var(--as-ai)_25%,transparent)]"
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
),
|
|
82
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, disabled: busyLike, children: /* @__PURE__ */ jsx(
|
|
83
|
+
"button",
|
|
84
|
+
{
|
|
85
|
+
type: "button",
|
|
86
|
+
"data-as": "ai-actions-more",
|
|
87
|
+
"aria-label": moreLabel,
|
|
88
|
+
"aria-expanded": open,
|
|
89
|
+
className: cn(
|
|
90
|
+
"inline-flex cursor-pointer items-center justify-center rounded-full py-1.5 pl-1 pr-2.5 transition-[filter] hover:brightness-95",
|
|
91
|
+
focusRing,
|
|
92
|
+
disabledState
|
|
93
|
+
),
|
|
94
|
+
children: /* @__PURE__ */ jsx(
|
|
95
|
+
ChevronDown,
|
|
96
|
+
{
|
|
97
|
+
className: cn(
|
|
98
|
+
"size-4 transition-transform duration-200",
|
|
99
|
+
open && "rotate-180"
|
|
100
|
+
),
|
|
101
|
+
"aria-hidden": true
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
) })
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
),
|
|
109
|
+
/* @__PURE__ */ jsx(
|
|
110
|
+
SplitPanel,
|
|
111
|
+
{
|
|
112
|
+
...{
|
|
113
|
+
onPrompt,
|
|
114
|
+
busy,
|
|
115
|
+
error,
|
|
116
|
+
title,
|
|
117
|
+
label,
|
|
118
|
+
promptLabel,
|
|
119
|
+
promptPlaceholder,
|
|
120
|
+
promptSubmitLabel,
|
|
121
|
+
align,
|
|
122
|
+
side,
|
|
123
|
+
panelActions,
|
|
124
|
+
onAction,
|
|
125
|
+
panelClassName,
|
|
126
|
+
prompt,
|
|
127
|
+
setPrompt,
|
|
128
|
+
sendPrompt
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
] });
|
|
133
|
+
}
|
|
134
|
+
return /* @__PURE__ */ jsx(Popover, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs("span", { className: "relative inline-flex", children: [
|
|
135
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, disabled: disabled || busy, children: /* @__PURE__ */ jsx(
|
|
136
|
+
"button",
|
|
137
|
+
{
|
|
138
|
+
ref,
|
|
139
|
+
type: "button",
|
|
140
|
+
"data-as": "ai-actions-dropdown",
|
|
141
|
+
"aria-label": label,
|
|
142
|
+
"aria-expanded": open,
|
|
143
|
+
className: cn(
|
|
144
|
+
"inline-flex size-7 cursor-pointer items-center justify-center rounded-full transition-[filter] hover:brightness-95",
|
|
145
|
+
focusRing,
|
|
146
|
+
disabledState,
|
|
147
|
+
triggerTone,
|
|
148
|
+
className
|
|
149
|
+
),
|
|
150
|
+
children: /* @__PURE__ */ jsx(Sparkles, { className: "size-4", "aria-hidden": true })
|
|
151
|
+
}
|
|
152
|
+
) }),
|
|
153
|
+
/* @__PURE__ */ jsx(
|
|
154
|
+
SplitPanel,
|
|
155
|
+
{
|
|
156
|
+
...{
|
|
157
|
+
onPrompt,
|
|
158
|
+
busy,
|
|
159
|
+
error,
|
|
160
|
+
title,
|
|
161
|
+
label,
|
|
162
|
+
promptLabel,
|
|
163
|
+
promptPlaceholder,
|
|
164
|
+
promptSubmitLabel,
|
|
165
|
+
align,
|
|
166
|
+
side,
|
|
167
|
+
panelActions: actions,
|
|
168
|
+
onAction,
|
|
169
|
+
panelClassName,
|
|
170
|
+
prompt,
|
|
171
|
+
setPrompt,
|
|
172
|
+
sendPrompt
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
] }) });
|
|
177
|
+
});
|
|
178
|
+
function SplitPanel({
|
|
179
|
+
onPrompt,
|
|
180
|
+
busy,
|
|
181
|
+
error,
|
|
182
|
+
title,
|
|
183
|
+
label,
|
|
184
|
+
promptLabel,
|
|
185
|
+
promptPlaceholder,
|
|
186
|
+
promptSubmitLabel,
|
|
187
|
+
align,
|
|
188
|
+
side,
|
|
189
|
+
panelActions,
|
|
190
|
+
onAction,
|
|
191
|
+
panelClassName,
|
|
192
|
+
prompt,
|
|
193
|
+
setPrompt,
|
|
194
|
+
sendPrompt
|
|
195
|
+
}) {
|
|
196
|
+
return /* @__PURE__ */ jsx(
|
|
197
|
+
PopoverContent,
|
|
198
|
+
{
|
|
199
|
+
side,
|
|
200
|
+
align,
|
|
201
|
+
"aria-label": title ?? label,
|
|
202
|
+
className: cn("w-64 p-1.5", panelClassName),
|
|
203
|
+
children: /* @__PURE__ */ jsxs("div", { "data-as": "ai-actions-panel", role: "menu", children: [
|
|
204
|
+
title ? /* @__PURE__ */ jsx("p", { className: "px-2 pb-1 pt-1.5 text-xs font-semibold uppercase tracking-wide text-[var(--as-muted-fg)]", children: title }) : null,
|
|
205
|
+
panelActions.map((action) => /* @__PURE__ */ jsxs(
|
|
206
|
+
"button",
|
|
207
|
+
{
|
|
208
|
+
type: "button",
|
|
209
|
+
role: "menuitem",
|
|
210
|
+
disabled: busy,
|
|
211
|
+
onClick: () => onAction(action),
|
|
212
|
+
className: "flex w-full cursor-pointer items-start gap-2.5 rounded-[var(--as-radius-sm)] px-2 py-2 text-left transition-colors hover:bg-[var(--as-secondary)] disabled:pointer-events-none disabled:opacity-50",
|
|
213
|
+
children: [
|
|
214
|
+
/* @__PURE__ */ jsx(
|
|
215
|
+
action.icon,
|
|
216
|
+
{
|
|
217
|
+
className: "mt-0.5 size-4 shrink-0 text-[var(--as-ai)]",
|
|
218
|
+
"aria-hidden": true
|
|
219
|
+
}
|
|
220
|
+
),
|
|
221
|
+
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-col", children: [
|
|
222
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-[var(--as-fg)]", children: action.label }),
|
|
223
|
+
action.description ? /* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--as-muted-fg)]", children: action.description }) : null
|
|
224
|
+
] })
|
|
225
|
+
]
|
|
226
|
+
},
|
|
227
|
+
action.id
|
|
228
|
+
)),
|
|
229
|
+
onPrompt ? /* @__PURE__ */ jsxs(
|
|
230
|
+
"form",
|
|
231
|
+
{
|
|
232
|
+
className: "mt-1 flex items-center gap-1.5 border-t border-[var(--as-border)] p-1.5",
|
|
233
|
+
onSubmit: (event) => {
|
|
234
|
+
event.preventDefault();
|
|
235
|
+
sendPrompt();
|
|
236
|
+
},
|
|
237
|
+
children: [
|
|
238
|
+
/* @__PURE__ */ jsx(
|
|
239
|
+
"input",
|
|
240
|
+
{
|
|
241
|
+
type: "text",
|
|
242
|
+
"aria-label": promptLabel,
|
|
243
|
+
placeholder: promptPlaceholder ?? promptLabel,
|
|
244
|
+
value: prompt,
|
|
245
|
+
onChange: (event) => setPrompt(event.target.value),
|
|
246
|
+
className: "h-7 w-full bg-transparent text-sm outline-none placeholder:text-[var(--as-muted-fg)]"
|
|
247
|
+
}
|
|
248
|
+
),
|
|
249
|
+
/* @__PURE__ */ jsx(
|
|
250
|
+
"button",
|
|
251
|
+
{
|
|
252
|
+
type: "submit",
|
|
253
|
+
"aria-label": promptSubmitLabel,
|
|
254
|
+
disabled: busy || !prompt.trim(),
|
|
255
|
+
className: "shrink-0 cursor-pointer rounded-[var(--as-radius-sm)] bg-[var(--as-ai)] p-1 text-[var(--as-ai-fg)] transition-opacity hover:opacity-90 disabled:pointer-events-none disabled:opacity-40",
|
|
256
|
+
children: /* @__PURE__ */ jsx(Send, { className: "size-3", "aria-hidden": true })
|
|
257
|
+
}
|
|
258
|
+
)
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
) : null,
|
|
262
|
+
busy ? /* @__PURE__ */ jsx("p", { className: "px-2 pb-1.5 text-xs text-[var(--as-muted-fg)]", role: "status", children: "\u2026" }) : null,
|
|
263
|
+
error ? /* @__PURE__ */ jsx("p", { role: "alert", className: "px-2 pb-1.5 text-xs text-[var(--as-danger)]", children: error }) : null
|
|
264
|
+
] })
|
|
265
|
+
}
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export { AiActionsDropdown };
|
|
270
|
+
//# sourceMappingURL=chunk-LWSLNCW2.js.map
|
|
271
|
+
//# sourceMappingURL=chunk-LWSLNCW2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/ai-actions-dropdown/AiActionsDropdown.tsx"],"names":["AiActionsDropdown"],"mappings":"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","file":"chunk-LWSLNCW2.js","sourcesContent":["import * as React from 'react'\nimport {\n ChevronDown,\n Send,\n Sparkles,\n type LucideIcon,\n} from 'lucide-react'\nimport { cn } from '../../lib/utils'\nimport { Popover, PopoverContent, PopoverTrigger } from '../popover'\n\nexport interface AiAction {\n id: string\n label: string\n description?: string\n icon: LucideIcon\n}\n\nexport interface AiActionsDropdownProps {\n actions: AiAction[]\n onAction: (action: AiAction) => void\n onPrompt?: (prompt: string) => void\n busy?: boolean\n error?: string | null\n label?: string\n title?: string\n promptLabel?: string\n promptPlaceholder?: string\n promptSubmitLabel?: string\n disabled?: boolean\n align?: 'start' | 'center' | 'end'\n side?: 'top' | 'bottom' | 'left' | 'right'\n className?: string\n panelClassName?: string\n primaryAction?: AiAction\n primaryLabel?: string\n moreLabel?: string\n}\n\nconst triggerTone =\n 'bg-[color-mix(in_srgb,var(--as-ai)_12%,transparent)] text-[var(--as-ai)]'\n\nexport const AiActionsDropdown = React.forwardRef<\n HTMLButtonElement,\n AiActionsDropdownProps\n>(function AiActionsDropdown(\n {\n actions,\n onAction,\n onPrompt,\n busy = false,\n error,\n label = 'AI actions',\n title,\n promptLabel = 'Ask something custom',\n promptPlaceholder,\n promptSubmitLabel = 'Send',\n disabled = false,\n align = 'end',\n side = 'bottom',\n className,\n panelClassName,\n primaryAction,\n primaryLabel,\n moreLabel = 'More AI actions',\n },\n ref,\n) {\n const [open, setOpen] = React.useState(false)\n const [prompt, setPrompt] = React.useState('')\n\n const sendPrompt = () => {\n const trimmed = prompt.trim()\n if (!trimmed || busy || !onPrompt) return\n onPrompt(trimmed)\n setPrompt('')\n }\n\n const panelActions = primaryAction\n ? actions.filter((action) => action.id !== primaryAction.id)\n : actions\n\n const focusRing =\n 'focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]'\n const disabledState =\n 'disabled:pointer-events-none disabled:opacity-50'\n\n if (primaryAction) {\n const busyLike = busy || disabled\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <span\n data-as=\"ai-actions-split\"\n className={cn(\n 'relative inline-flex items-center rounded-full font-medium',\n triggerTone,\n className,\n )}\n >\n <button\n ref={ref}\n type=\"button\"\n data-as=\"ai-actions-primary\"\n aria-label={primaryLabel}\n disabled={busyLike}\n onClick={() => onAction(primaryAction)}\n className={cn(\n 'inline-flex cursor-pointer items-center gap-1.5 rounded-full py-1.5 pl-3 pr-2 text-sm transition-[filter] hover:brightness-95',\n focusRing,\n disabledState,\n )}\n >\n <primaryAction.icon className=\"size-4\" aria-hidden />\n <span>{primaryLabel ?? primaryAction.label}</span>\n </button>\n <span\n aria-hidden\n className={cn(\n 'my-1 w-px self-stretch',\n 'bg-[color-mix(in_srgb,var(--as-ai)_25%,transparent)]',\n )}\n />\n <PopoverTrigger asChild disabled={busyLike}>\n <button\n type=\"button\"\n data-as=\"ai-actions-more\"\n aria-label={moreLabel}\n aria-expanded={open}\n className={cn(\n 'inline-flex cursor-pointer items-center justify-center rounded-full py-1.5 pl-1 pr-2.5 transition-[filter] hover:brightness-95',\n focusRing,\n disabledState,\n )}\n >\n <ChevronDown\n className={cn(\n 'size-4 transition-transform duration-200',\n open && 'rotate-180',\n )}\n aria-hidden\n />\n </button>\n </PopoverTrigger>\n </span>\n <SplitPanel\n {...{\n onPrompt,\n busy,\n error,\n title,\n label,\n promptLabel,\n promptPlaceholder,\n promptSubmitLabel,\n align,\n side,\n panelActions,\n onAction,\n panelClassName,\n prompt,\n setPrompt,\n sendPrompt,\n }}\n />\n </Popover>\n )\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <span className=\"relative inline-flex\">\n <PopoverTrigger asChild disabled={disabled || busy}>\n <button\n ref={ref}\n type=\"button\"\n data-as=\"ai-actions-dropdown\"\n aria-label={label}\n aria-expanded={open}\n className={cn(\n 'inline-flex size-7 cursor-pointer items-center justify-center rounded-full transition-[filter] hover:brightness-95',\n focusRing,\n disabledState,\n triggerTone,\n className,\n )}\n >\n <Sparkles className=\"size-4\" aria-hidden />\n </button>\n </PopoverTrigger>\n <SplitPanel\n {...{\n onPrompt,\n busy,\n error,\n title,\n label,\n promptLabel,\n promptPlaceholder,\n promptSubmitLabel,\n align,\n side,\n panelActions: actions,\n onAction,\n panelClassName,\n prompt,\n setPrompt,\n sendPrompt,\n }}\n />\n </span>\n </Popover>\n )\n})\n\ntype SplitPanelProps = {\n onPrompt?: (prompt: string) => void\n busy: boolean\n error?: string | null\n title?: string\n label: string\n promptLabel: string\n promptPlaceholder?: string\n promptSubmitLabel: string\n align: 'start' | 'center' | 'end'\n side: 'top' | 'bottom' | 'left' | 'right'\n panelActions: AiAction[]\n onAction: (action: AiAction) => void\n panelClassName?: string\n prompt: string\n setPrompt: (prompt: string) => void\n sendPrompt: () => void\n}\n\nfunction SplitPanel({\n onPrompt,\n busy,\n error,\n title,\n label,\n promptLabel,\n promptPlaceholder,\n promptSubmitLabel,\n align,\n side,\n panelActions,\n onAction,\n panelClassName,\n prompt,\n setPrompt,\n sendPrompt,\n}: SplitPanelProps) {\n return (\n <PopoverContent\n side={side}\n align={align}\n aria-label={title ?? label}\n className={cn('w-64 p-1.5', panelClassName)}\n >\n <div data-as=\"ai-actions-panel\" role=\"menu\">\n {title ? (\n <p className=\"px-2 pb-1 pt-1.5 text-xs font-semibold uppercase tracking-wide text-[var(--as-muted-fg)]\">\n {title}\n </p>\n ) : null}\n {panelActions.map((action) => (\n <button\n key={action.id}\n type=\"button\"\n role=\"menuitem\"\n disabled={busy}\n onClick={() => onAction(action)}\n className=\"flex w-full cursor-pointer items-start gap-2.5 rounded-[var(--as-radius-sm)] px-2 py-2 text-left transition-colors hover:bg-[var(--as-secondary)] disabled:pointer-events-none disabled:opacity-50\"\n >\n <action.icon\n className=\"mt-0.5 size-4 shrink-0 text-[var(--as-ai)]\"\n aria-hidden\n />\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"text-sm font-medium text-[var(--as-fg)]\">\n {action.label}\n </span>\n {action.description ? (\n <span className=\"text-xs text-[var(--as-muted-fg)]\">\n {action.description}\n </span>\n ) : null}\n </span>\n </button>\n ))}\n {onPrompt ? (\n <form\n className=\"mt-1 flex items-center gap-1.5 border-t border-[var(--as-border)] p-1.5\"\n onSubmit={(event) => {\n event.preventDefault()\n sendPrompt()\n }}\n >\n <input\n type=\"text\"\n aria-label={promptLabel}\n placeholder={promptPlaceholder ?? promptLabel}\n value={prompt}\n onChange={(event) => setPrompt(event.target.value)}\n className=\"h-7 w-full bg-transparent text-sm outline-none placeholder:text-[var(--as-muted-fg)]\"\n />\n <button\n type=\"submit\"\n aria-label={promptSubmitLabel}\n disabled={busy || !prompt.trim()}\n className=\"shrink-0 cursor-pointer rounded-[var(--as-radius-sm)] bg-[var(--as-ai)] p-1 text-[var(--as-ai-fg)] transition-opacity hover:opacity-90 disabled:pointer-events-none disabled:opacity-40\"\n >\n <Send className=\"size-3\" aria-hidden />\n </button>\n </form>\n ) : null}\n {busy ? (\n <p className=\"px-2 pb-1.5 text-xs text-[var(--as-muted-fg)]\" role=\"status\">\n …\n </p>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"px-2 pb-1.5 text-xs text-[var(--as-danger)]\">\n {error}\n </p>\n ) : null}\n </div>\n </PopoverContent>\n )\n}\n\n"]}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { cn } from './chunk-BLJWR4ZV.js';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { useEditor, EditorContent } from '@tiptap/react';
|
|
4
|
+
import StarterKit from '@tiptap/starter-kit';
|
|
5
|
+
import { Redo2, Undo2, Quote, ListOrdered, List, Heading2, Code, Strikethrough, Italic, Bold } from 'lucide-react';
|
|
6
|
+
import { Markdown } from 'tiptap-markdown';
|
|
7
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
var DEFAULT_TOOLBAR = [
|
|
10
|
+
"history",
|
|
11
|
+
"heading",
|
|
12
|
+
"format",
|
|
13
|
+
"list",
|
|
14
|
+
"quote"
|
|
15
|
+
];
|
|
16
|
+
var DEFAULT_LABELS = {
|
|
17
|
+
toolbar: "Formatting",
|
|
18
|
+
bold: "Bold",
|
|
19
|
+
italic: "Italic",
|
|
20
|
+
strike: "Strikethrough",
|
|
21
|
+
code: "Code",
|
|
22
|
+
heading: "Heading",
|
|
23
|
+
bulletList: "Bulleted list",
|
|
24
|
+
orderedList: "Numbered list",
|
|
25
|
+
blockquote: "Quote",
|
|
26
|
+
undo: "Undo",
|
|
27
|
+
redo: "Redo"
|
|
28
|
+
};
|
|
29
|
+
var DEFAULT_ICONS = {
|
|
30
|
+
bold: Bold,
|
|
31
|
+
italic: Italic,
|
|
32
|
+
strike: Strikethrough,
|
|
33
|
+
code: Code,
|
|
34
|
+
heading: Heading2,
|
|
35
|
+
bulletList: List,
|
|
36
|
+
orderedList: ListOrdered,
|
|
37
|
+
blockquote: Quote,
|
|
38
|
+
undo: Undo2,
|
|
39
|
+
redo: Redo2
|
|
40
|
+
};
|
|
41
|
+
function getMarkdown(editor) {
|
|
42
|
+
const storage = editor.storage;
|
|
43
|
+
return storage.markdown?.getMarkdown?.() ?? "";
|
|
44
|
+
}
|
|
45
|
+
function applyExternalValue(editor, markdown) {
|
|
46
|
+
const hadFocus = editor.isFocused;
|
|
47
|
+
const caret = editor.state.selection.head;
|
|
48
|
+
editor.commands.setContent(markdown, { emitUpdate: false });
|
|
49
|
+
if (hadFocus) {
|
|
50
|
+
editor.commands.setTextSelection(Math.min(caret, editor.state.doc.content.size));
|
|
51
|
+
editor.commands.focus();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
var RichTextEditor = React.forwardRef(
|
|
55
|
+
function RichTextEditor2({
|
|
56
|
+
value,
|
|
57
|
+
onValueChange,
|
|
58
|
+
ariaLabel,
|
|
59
|
+
disabled = false,
|
|
60
|
+
toolbar = DEFAULT_TOOLBAR,
|
|
61
|
+
toolbarExtra,
|
|
62
|
+
extensions,
|
|
63
|
+
parseMarkdown,
|
|
64
|
+
serializeMarkdown,
|
|
65
|
+
labels,
|
|
66
|
+
icons,
|
|
67
|
+
className
|
|
68
|
+
}, ref) {
|
|
69
|
+
const mergedLabels = { ...DEFAULT_LABELS, ...labels };
|
|
70
|
+
const mergedIcons = { ...DEFAULT_ICONS, ...icons };
|
|
71
|
+
const lastEmittedRef = React.useRef(value);
|
|
72
|
+
const onValueChangeRef = React.useRef(onValueChange);
|
|
73
|
+
onValueChangeRef.current = onValueChange;
|
|
74
|
+
const hooksRef = React.useRef({ parseMarkdown, serializeMarkdown });
|
|
75
|
+
hooksRef.current = { parseMarkdown, serializeMarkdown };
|
|
76
|
+
const [, bump] = React.useReducer((count) => count + 1, 0);
|
|
77
|
+
const toDocument = React.useCallback(
|
|
78
|
+
(markdown) => parseMarkdown ? parseMarkdown(markdown) : markdown,
|
|
79
|
+
[parseMarkdown]
|
|
80
|
+
);
|
|
81
|
+
const toApp = React.useCallback(
|
|
82
|
+
(markdown) => serializeMarkdown ? serializeMarkdown(markdown) : markdown,
|
|
83
|
+
[serializeMarkdown]
|
|
84
|
+
);
|
|
85
|
+
const editor = useEditor(
|
|
86
|
+
{
|
|
87
|
+
extensions: React.useMemo(
|
|
88
|
+
() => [StarterKit, Markdown, ...extensions ?? []],
|
|
89
|
+
[extensions]
|
|
90
|
+
),
|
|
91
|
+
content: toDocument(value),
|
|
92
|
+
editable: !disabled,
|
|
93
|
+
immediatelyRender: false,
|
|
94
|
+
editorProps: {
|
|
95
|
+
attributes: {
|
|
96
|
+
"aria-label": ariaLabel,
|
|
97
|
+
class: "as-rich-text-editor__content min-h-24 w-full bg-transparent px-3 py-2 text-sm text-[var(--as-fg)] outline-none"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
onUpdate: ({ editor: current }) => {
|
|
101
|
+
const markdown = toApp(getMarkdown(current));
|
|
102
|
+
lastEmittedRef.current = markdown;
|
|
103
|
+
onValueChangeRef.current(markdown);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
const isMounted = editor !== null;
|
|
108
|
+
React.useEffect(() => {
|
|
109
|
+
if (!isMounted || editor === null) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const handler = () => bump();
|
|
113
|
+
editor.on("transaction", handler);
|
|
114
|
+
editor.on("update", handler);
|
|
115
|
+
return () => {
|
|
116
|
+
editor.off("transaction", handler);
|
|
117
|
+
editor.off("update", handler);
|
|
118
|
+
};
|
|
119
|
+
}, [editor, isMounted]);
|
|
120
|
+
React.useEffect(() => {
|
|
121
|
+
if (editor === null || editor.isDestroyed) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
editor.setEditable(!disabled);
|
|
125
|
+
}, [editor, disabled]);
|
|
126
|
+
React.useEffect(() => {
|
|
127
|
+
if (editor === null || editor.isDestroyed) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (value === lastEmittedRef.current) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const current = toApp(getMarkdown(editor));
|
|
134
|
+
if (value === current) {
|
|
135
|
+
lastEmittedRef.current = value;
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
applyExternalValue(editor, toDocument(value));
|
|
139
|
+
lastEmittedRef.current = value;
|
|
140
|
+
}, [editor, value, toApp, toDocument]);
|
|
141
|
+
const groups = toolbar === false ? [] : toolbar ?? DEFAULT_TOOLBAR;
|
|
142
|
+
const renderButton = (key, group, onClick, active) => {
|
|
143
|
+
const Icon = mergedIcons[key];
|
|
144
|
+
return /* @__PURE__ */ jsx(
|
|
145
|
+
"button",
|
|
146
|
+
{
|
|
147
|
+
type: "button",
|
|
148
|
+
"aria-label": mergedLabels[key],
|
|
149
|
+
"aria-pressed": active,
|
|
150
|
+
title: mergedLabels[key],
|
|
151
|
+
disabled,
|
|
152
|
+
className: cn(
|
|
153
|
+
"rounded p-1.5 text-[var(--as-muted-fg)] transition-colors hover:text-[var(--as-fg)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--as-focus-ring)] disabled:cursor-not-allowed disabled:opacity-50",
|
|
154
|
+
active && "bg-[var(--as-surface-active)] text-[var(--as-fg)]"
|
|
155
|
+
),
|
|
156
|
+
onClick,
|
|
157
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "size-4", "aria-hidden": true })
|
|
158
|
+
},
|
|
159
|
+
`${group}-${key}`
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
return /* @__PURE__ */ jsxs(
|
|
163
|
+
"div",
|
|
164
|
+
{
|
|
165
|
+
ref,
|
|
166
|
+
"data-as": "rich-text-editor",
|
|
167
|
+
className: cn(
|
|
168
|
+
"w-full rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-fg)] focus-within:border-[var(--as-focus-ring)]",
|
|
169
|
+
disabled && "opacity-50",
|
|
170
|
+
className
|
|
171
|
+
),
|
|
172
|
+
children: [
|
|
173
|
+
groups.length > 0 || toolbarExtra ? /* @__PURE__ */ jsxs(
|
|
174
|
+
"div",
|
|
175
|
+
{
|
|
176
|
+
role: "toolbar",
|
|
177
|
+
"aria-label": mergedLabels.toolbar,
|
|
178
|
+
className: "flex flex-wrap items-center gap-0.5 border-b border-[var(--as-border)] p-1",
|
|
179
|
+
children: [
|
|
180
|
+
groups.includes("history") ? renderButton(
|
|
181
|
+
"undo",
|
|
182
|
+
"history",
|
|
183
|
+
() => editor?.chain().focus().undo().run(),
|
|
184
|
+
false
|
|
185
|
+
) : null,
|
|
186
|
+
groups.includes("history") ? renderButton(
|
|
187
|
+
"redo",
|
|
188
|
+
"history",
|
|
189
|
+
() => editor?.chain().focus().redo().run(),
|
|
190
|
+
false
|
|
191
|
+
) : null,
|
|
192
|
+
groups.includes("heading") ? renderButton(
|
|
193
|
+
"heading",
|
|
194
|
+
"heading",
|
|
195
|
+
() => editor?.chain().focus().toggleHeading({ level: 2 }).run(),
|
|
196
|
+
editor?.isActive("heading", { level: 2 }) === true
|
|
197
|
+
) : null,
|
|
198
|
+
groups.includes("format") ? renderButton(
|
|
199
|
+
"bold",
|
|
200
|
+
"format",
|
|
201
|
+
() => editor?.chain().focus().toggleBold().run(),
|
|
202
|
+
editor?.isActive("bold") === true
|
|
203
|
+
) : null,
|
|
204
|
+
groups.includes("format") ? renderButton(
|
|
205
|
+
"italic",
|
|
206
|
+
"format",
|
|
207
|
+
() => editor?.chain().focus().toggleItalic().run(),
|
|
208
|
+
editor?.isActive("italic") === true
|
|
209
|
+
) : null,
|
|
210
|
+
groups.includes("format") ? renderButton(
|
|
211
|
+
"strike",
|
|
212
|
+
"format",
|
|
213
|
+
() => editor?.chain().focus().toggleStrike().run(),
|
|
214
|
+
editor?.isActive("strike") === true
|
|
215
|
+
) : null,
|
|
216
|
+
groups.includes("format") ? renderButton(
|
|
217
|
+
"code",
|
|
218
|
+
"format",
|
|
219
|
+
() => editor?.chain().focus().toggleCode().run(),
|
|
220
|
+
editor?.isActive("code") === true
|
|
221
|
+
) : null,
|
|
222
|
+
groups.includes("list") ? renderButton(
|
|
223
|
+
"bulletList",
|
|
224
|
+
"list",
|
|
225
|
+
() => editor?.chain().focus().toggleBulletList().run(),
|
|
226
|
+
editor?.isActive("bulletList") === true
|
|
227
|
+
) : null,
|
|
228
|
+
groups.includes("list") ? renderButton(
|
|
229
|
+
"orderedList",
|
|
230
|
+
"list",
|
|
231
|
+
() => editor?.chain().focus().toggleOrderedList().run(),
|
|
232
|
+
editor?.isActive("orderedList") === true
|
|
233
|
+
) : null,
|
|
234
|
+
groups.includes("quote") ? renderButton(
|
|
235
|
+
"blockquote",
|
|
236
|
+
"quote",
|
|
237
|
+
() => editor?.chain().focus().toggleBlockquote().run(),
|
|
238
|
+
editor?.isActive("blockquote") === true
|
|
239
|
+
) : null,
|
|
240
|
+
typeof toolbarExtra === "function" ? toolbarExtra(editor) : toolbarExtra
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
) : null,
|
|
244
|
+
/* @__PURE__ */ jsx(EditorContent, { editor })
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
export { RichTextEditor };
|
|
252
|
+
//# sourceMappingURL=chunk-XUDCCQRN.js.map
|
|
253
|
+
//# sourceMappingURL=chunk-XUDCCQRN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/rich-text-editor/RichTextEditor.tsx"],"names":["RichTextEditor"],"mappings":"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","file":"chunk-XUDCCQRN.js","sourcesContent":["import * as React from 'react'\nimport { Editor, EditorContent, useEditor, type Extensions } from '@tiptap/react'\nimport StarterKit from '@tiptap/starter-kit'\nimport {\n Bold,\n Code,\n Heading2,\n Italic,\n List,\n ListOrdered,\n Quote,\n Redo2,\n Strikethrough,\n Undo2,\n type LucideIcon,\n} from 'lucide-react'\nimport { Markdown } from 'tiptap-markdown'\n\nimport { cn } from '../../lib/utils'\n\nexport type RichTextToolbarGroup = 'history' | 'heading' | 'format' | 'list' | 'quote'\n\nconst DEFAULT_TOOLBAR: RichTextToolbarGroup[] = [\n 'history',\n 'heading',\n 'format',\n 'list',\n 'quote',\n]\n\nexport interface RichTextEditorLabels {\n toolbar?: string\n bold?: string\n italic?: string\n strike?: string\n code?: string\n heading?: string\n bulletList?: string\n orderedList?: string\n blockquote?: string\n undo?: string\n redo?: string\n}\n\nexport interface RichTextEditorIcons {\n bold?: LucideIcon\n italic?: LucideIcon\n strike?: LucideIcon\n code?: LucideIcon\n heading?: LucideIcon\n bulletList?: LucideIcon\n orderedList?: LucideIcon\n blockquote?: LucideIcon\n undo?: LucideIcon\n redo?: LucideIcon\n}\n\nconst DEFAULT_LABELS: Required<RichTextEditorLabels> = {\n toolbar: 'Formatting',\n bold: 'Bold',\n italic: 'Italic',\n strike: 'Strikethrough',\n code: 'Code',\n heading: 'Heading',\n bulletList: 'Bulleted list',\n orderedList: 'Numbered list',\n blockquote: 'Quote',\n undo: 'Undo',\n redo: 'Redo',\n}\n\nconst DEFAULT_ICONS: Required<RichTextEditorIcons> = {\n bold: Bold,\n italic: Italic,\n strike: Strikethrough,\n code: Code,\n heading: Heading2,\n bulletList: List,\n orderedList: ListOrdered,\n blockquote: Quote,\n undo: Undo2,\n redo: Redo2,\n}\n\nexport interface RichTextEditorProps {\n value: string\n onValueChange: (markdown: string) => void\n ariaLabel: string\n disabled?: boolean\n toolbar?: RichTextToolbarGroup[] | false\n /** App-owned controls at the end of the toolbar; render-prop form receives the editor. */\n toolbarExtra?: React.ReactNode | ((editor: Editor | null) => React.ReactNode)\n /** App extensions merged after the starter kit (math, tables, custom nodes…). */\n extensions?: Extensions\n /** Map incoming app-domain markdown before it reaches the document. */\n parseMarkdown?: (markdown: string) => string\n /** Map the serialized document before it is emitted / echo-compared. */\n serializeMarkdown?: (markdown: string) => string\n labels?: Partial<RichTextEditorLabels>\n icons?: Partial<RichTextEditorIcons>\n className?: string\n}\n\nfunction getMarkdown(editor: Editor): string {\n const storage = editor.storage as { markdown?: { getMarkdown?: () => string } }\n return storage.markdown?.getMarkdown?.() ?? ''\n}\n\nfunction applyExternalValue(editor: Editor, markdown: string): void {\n const hadFocus = editor.isFocused\n const caret = editor.state.selection.head\n editor.commands.setContent(markdown, { emitUpdate: false })\n if (hadFocus) {\n editor.commands.setTextSelection(Math.min(caret, editor.state.doc.content.size))\n editor.commands.focus()\n }\n}\n\nexport const RichTextEditor = React.forwardRef<HTMLDivElement, RichTextEditorProps>(\n function RichTextEditor(\n {\n value,\n onValueChange,\n ariaLabel,\n disabled = false,\n toolbar = DEFAULT_TOOLBAR,\n toolbarExtra,\n extensions,\n parseMarkdown,\n serializeMarkdown,\n labels,\n icons,\n className,\n },\n ref,\n ) {\n const mergedLabels = { ...DEFAULT_LABELS, ...labels }\n const mergedIcons = { ...DEFAULT_ICONS, ...icons }\n const lastEmittedRef = React.useRef<string>(value)\n const onValueChangeRef = React.useRef(onValueChange)\n onValueChangeRef.current = onValueChange\n const hooksRef = React.useRef({ parseMarkdown, serializeMarkdown })\n hooksRef.current = { parseMarkdown, serializeMarkdown }\n const [, bump] = React.useReducer((count: number) => count + 1, 0)\n\n const toDocument = React.useCallback(\n (markdown: string) => (parseMarkdown ? parseMarkdown(markdown) : markdown),\n [parseMarkdown],\n )\n const toApp = React.useCallback(\n (markdown: string) => (serializeMarkdown ? serializeMarkdown(markdown) : markdown),\n [serializeMarkdown],\n )\n\n const editor = useEditor(\n {\n extensions: React.useMemo(\n () => [StarterKit, Markdown, ...(extensions ?? [])],\n [extensions],\n ),\n content: toDocument(value),\n editable: !disabled,\n immediatelyRender: false,\n editorProps: {\n attributes: {\n 'aria-label': ariaLabel,\n class:\n 'as-rich-text-editor__content min-h-24 w-full bg-transparent px-3 py-2 text-sm text-[var(--as-fg)] outline-none',\n },\n },\n onUpdate: ({ editor: current }) => {\n const markdown = toApp(getMarkdown(current))\n lastEmittedRef.current = markdown\n onValueChangeRef.current(markdown)\n },\n },\n )\n\n const isMounted = editor !== null\n\n React.useEffect(() => {\n if (!isMounted || editor === null) {\n return\n }\n const handler = () => bump()\n editor.on('transaction', handler)\n editor.on('update', handler)\n return () => {\n editor.off('transaction', handler)\n editor.off('update', handler)\n }\n }, [editor, isMounted])\n\n React.useEffect(() => {\n if (editor === null || editor.isDestroyed) {\n return\n }\n editor.setEditable(!disabled)\n }, [editor, disabled])\n\n React.useEffect(() => {\n if (editor === null || editor.isDestroyed) {\n return\n }\n if (value === lastEmittedRef.current) {\n return\n }\n const current = toApp(getMarkdown(editor))\n if (value === current) {\n lastEmittedRef.current = value\n return\n }\n applyExternalValue(editor, toDocument(value))\n lastEmittedRef.current = value\n }, [editor, value, toApp, toDocument])\n\n const groups = toolbar === false ? [] : (toolbar ?? DEFAULT_TOOLBAR)\n\n const renderButton = (\n key: Exclude<keyof RichTextEditorLabels, 'toolbar'>,\n group: Exclude<RichTextToolbarGroup, 'history'> | 'history',\n onClick: () => void,\n active: boolean,\n ) => {\n const Icon = mergedIcons[key]\n return (\n <button\n key={`${group}-${key}`}\n type=\"button\"\n aria-label={mergedLabels[key]}\n aria-pressed={active}\n title={mergedLabels[key]}\n disabled={disabled}\n className={cn(\n 'rounded p-1.5 text-[var(--as-muted-fg)] transition-colors hover:text-[var(--as-fg)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--as-focus-ring)] disabled:cursor-not-allowed disabled:opacity-50',\n active && 'bg-[var(--as-surface-active)] text-[var(--as-fg)]',\n )}\n onClick={onClick}\n >\n <Icon className=\"size-4\" aria-hidden />\n </button>\n )\n }\n\n return (\n <div\n ref={ref}\n data-as=\"rich-text-editor\"\n className={cn(\n 'w-full rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-fg)] focus-within:border-[var(--as-focus-ring)]',\n disabled && 'opacity-50',\n className,\n )}\n >\n {groups.length > 0 || toolbarExtra ? (\n <div\n role=\"toolbar\"\n aria-label={mergedLabels.toolbar}\n className=\"flex flex-wrap items-center gap-0.5 border-b border-[var(--as-border)] p-1\"\n >\n {groups.includes('history')\n ? renderButton(\n 'undo',\n 'history',\n () => editor?.chain().focus().undo().run(),\n false,\n )\n : null}\n {groups.includes('history')\n ? renderButton(\n 'redo',\n 'history',\n () => editor?.chain().focus().redo().run(),\n false,\n )\n : null}\n {groups.includes('heading')\n ? renderButton(\n 'heading',\n 'heading',\n () => editor?.chain().focus().toggleHeading({ level: 2 }).run(),\n editor?.isActive('heading', { level: 2 }) === true,\n )\n : null}\n {groups.includes('format')\n ? renderButton(\n 'bold',\n 'format',\n () => editor?.chain().focus().toggleBold().run(),\n editor?.isActive('bold') === true,\n )\n : null}\n {groups.includes('format')\n ? renderButton(\n 'italic',\n 'format',\n () => editor?.chain().focus().toggleItalic().run(),\n editor?.isActive('italic') === true,\n )\n : null}\n {groups.includes('format')\n ? renderButton(\n 'strike',\n 'format',\n () => editor?.chain().focus().toggleStrike().run(),\n editor?.isActive('strike') === true,\n )\n : null}\n {groups.includes('format')\n ? renderButton(\n 'code',\n 'format',\n () => editor?.chain().focus().toggleCode().run(),\n editor?.isActive('code') === true,\n )\n : null}\n {groups.includes('list')\n ? renderButton(\n 'bulletList',\n 'list',\n () => editor?.chain().focus().toggleBulletList().run(),\n editor?.isActive('bulletList') === true,\n )\n : null}\n {groups.includes('list')\n ? renderButton(\n 'orderedList',\n 'list',\n () => editor?.chain().focus().toggleOrderedList().run(),\n editor?.isActive('orderedList') === true,\n )\n : null}\n {groups.includes('quote')\n ? renderButton(\n 'blockquote',\n 'quote',\n () => editor?.chain().focus().toggleBlockquote().run(),\n editor?.isActive('blockquote') === true,\n )\n : null}\n {typeof toolbarExtra === 'function' ? toolbarExtra(editor) : toolbarExtra}\n </div>\n ) : null}\n <EditorContent editor={editor} />\n </div>\n )\n },\n)\n"]}
|