@open-mercato/ui 0.6.5-develop.5048.1.fd82f4ae17 → 0.6.5-develop.5099.1.85c0aff78c
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/.turbo/turbo-build.log +1 -1
- package/dist/backend/CrudForm.js +7 -57
- package/dist/backend/CrudForm.js.map +3 -3
- package/dist/backend/detail/InlineEditors.js +2 -51
- package/dist/backend/detail/InlineEditors.js.map +3 -3
- package/dist/backend/inputs/MarkdownField.js +20 -0
- package/dist/backend/inputs/MarkdownField.js.map +7 -0
- package/dist/backend/inputs/MdxEditorImpl.js +98 -0
- package/dist/backend/inputs/MdxEditorImpl.js.map +7 -0
- package/dist/backend/inputs/SwitchableMarkdownInput.js +6 -38
- package/dist/backend/inputs/SwitchableMarkdownInput.js.map +2 -2
- package/dist/backend/markdown/markdownToPlainText.js +29 -0
- package/dist/backend/markdown/markdownToPlainText.js.map +2 -2
- package/dist/types/css.d.js +1 -0
- package/dist/types/css.d.js.map +7 -0
- package/package.json +4 -3
- package/src/backend/CrudForm.tsx +3 -67
- package/src/backend/__tests__/CrudForm.custom-fields.test.tsx +0 -1
- package/src/backend/__tests__/CrudForm.datetime.test.tsx +0 -1
- package/src/backend/__tests__/CrudForm.defaults.test.tsx +0 -1
- package/src/backend/__tests__/CrudForm.dotPath.test.tsx +0 -1
- package/src/backend/__tests__/CrudForm.doubleSubmit.test.tsx +0 -1
- package/src/backend/__tests__/CrudForm.navigation.test.tsx +0 -1
- package/src/backend/__tests__/CrudForm.optimisticLock.test.tsx +0 -1
- package/src/backend/__tests__/CrudForm.render.test.tsx +0 -1
- package/src/backend/__tests__/CrudForm.sortable.test.tsx +0 -1
- package/src/backend/__tests__/CrudForm.transformData.test.tsx +0 -1
- package/src/backend/__tests__/CrudForm.unsavedNavigation.test.tsx +0 -1
- package/src/backend/__tests__/CrudForm.validation.test.tsx +0 -1
- package/src/backend/__tests__/CustomDataSection.test.tsx +0 -1
- package/src/backend/__tests__/lazy-heavy-libraries.test.ts +16 -3
- package/src/backend/detail/InlineEditors.tsx +14 -76
- package/src/backend/inputs/MarkdownField.tsx +34 -0
- package/src/backend/inputs/MdxEditorImpl.tsx +113 -0
- package/src/backend/inputs/SwitchableMarkdownInput.tsx +5 -54
- package/src/backend/markdown/__tests__/markdownToPlainText.test.ts +13 -0
- package/src/backend/markdown/markdownToPlainText.ts +41 -0
- package/src/types/css.d.ts +5 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import dynamic from "next/dynamic";
|
|
5
4
|
import { FileCode, Loader2, Mail, Pencil, Phone, X } from "lucide-react";
|
|
6
5
|
import { PhoneNumberField } from "@open-mercato/ui/backend/inputs/PhoneNumberField";
|
|
7
6
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
@@ -17,7 +16,6 @@ import { DatePicker } from "@open-mercato/ui/primitives/date-picker";
|
|
|
17
16
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
18
17
|
import { cn } from "@open-mercato/shared/lib/utils";
|
|
19
18
|
import { format } from "date-fns/format";
|
|
20
|
-
import { LoadingMessage } from "./LoadingMessage.js";
|
|
21
19
|
import { mapCrudServerErrorToFormErrors } from "../utils/serverErrors.js";
|
|
22
20
|
import { MarkdownPreview } from "../markdown/index.js";
|
|
23
21
|
function resolveInlineErrorMessage(err, fallbackMessage) {
|
|
@@ -343,23 +341,6 @@ function InlineTextEditor({
|
|
|
343
341
|
] }) });
|
|
344
342
|
}
|
|
345
343
|
const isTestEnv = typeof process !== "undefined" && (process.env.NODE_ENV === "test" || typeof process.env.JEST_WORKER_ID !== "undefined");
|
|
346
|
-
function MarkdownEditorFallback() {
|
|
347
|
-
const t = useT();
|
|
348
|
-
return /* @__PURE__ */ jsx(LoadingMessage, { label: t("ui.detail.inline.editorLoading", "Loading editor\u2026"), className: "min-h-[200px] justify-center" });
|
|
349
|
-
}
|
|
350
|
-
const MarkdownEditorTestStub = ({ value, onChange }) => /* @__PURE__ */ jsx(
|
|
351
|
-
Textarea,
|
|
352
|
-
{
|
|
353
|
-
"data-testid": "markdown-editor",
|
|
354
|
-
rows: 8,
|
|
355
|
-
value: value ?? "",
|
|
356
|
-
onChange: (event) => onChange?.(event.target.value)
|
|
357
|
-
}
|
|
358
|
-
);
|
|
359
|
-
const MarkdownEditorComponent = isTestEnv ? MarkdownEditorTestStub : dynamic(() => import("@uiw/react-md-editor"), {
|
|
360
|
-
ssr: false,
|
|
361
|
-
loading: () => /* @__PURE__ */ jsx(MarkdownEditorFallback, {})
|
|
362
|
-
});
|
|
363
344
|
let markdownPluginsPromise = null;
|
|
364
345
|
async function loadMarkdownPlugins() {
|
|
365
346
|
if (isTestEnv) return [];
|
|
@@ -388,7 +369,6 @@ function InlineMultilineEditor({
|
|
|
388
369
|
const [saving, setSaving] = React.useState(false);
|
|
389
370
|
const [isMarkdownEnabled, setIsMarkdownEnabled] = React.useState(true);
|
|
390
371
|
const textareaRef = React.useRef(null);
|
|
391
|
-
const markdownEditorRef = React.useRef(null);
|
|
392
372
|
const [markdownPlugins, setMarkdownPlugins] = React.useState([]);
|
|
393
373
|
const fallbackError = React.useMemo(
|
|
394
374
|
() => t("ui.detail.inline.error", "Failed to save value."),
|
|
@@ -415,14 +395,6 @@ function InlineMultilineEditor({
|
|
|
415
395
|
}, [adjustTextareaSize, draft, isMarkdownEnabled]);
|
|
416
396
|
React.useEffect(() => {
|
|
417
397
|
if (!editing) return;
|
|
418
|
-
if (isMarkdownEnabled) {
|
|
419
|
-
const element2 = markdownEditorRef.current?.querySelector("textarea");
|
|
420
|
-
if (!element2) return;
|
|
421
|
-
window.requestAnimationFrame(() => {
|
|
422
|
-
element2.focus();
|
|
423
|
-
});
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
426
398
|
const element = textareaRef.current;
|
|
427
399
|
if (!element) return;
|
|
428
400
|
window.requestAnimationFrame(() => {
|
|
@@ -536,32 +508,11 @@ function InlineMultilineEditor({
|
|
|
536
508
|
}
|
|
537
509
|
},
|
|
538
510
|
children: [
|
|
539
|
-
|
|
540
|
-
"div",
|
|
541
|
-
{
|
|
542
|
-
ref: markdownEditorRef,
|
|
543
|
-
className: cn(
|
|
544
|
-
"w-full rounded-md border border-muted-foreground/30 bg-background p-2",
|
|
545
|
-
saving ? "pointer-events-none opacity-75" : null
|
|
546
|
-
),
|
|
547
|
-
children: /* @__PURE__ */ jsx("div", { "data-color-mode": "light", className: "w-full", children: /* @__PURE__ */ jsx(
|
|
548
|
-
MarkdownEditorComponent,
|
|
549
|
-
{
|
|
550
|
-
value: draft,
|
|
551
|
-
height: 220,
|
|
552
|
-
onChange: (nextValue) => {
|
|
553
|
-
if (error) setError(null);
|
|
554
|
-
setDraft(typeof nextValue === "string" ? nextValue : "");
|
|
555
|
-
},
|
|
556
|
-
previewOptions: { remarkPlugins: markdownPlugins }
|
|
557
|
-
}
|
|
558
|
-
) })
|
|
559
|
-
}
|
|
560
|
-
) : /* @__PURE__ */ jsx(
|
|
511
|
+
/* @__PURE__ */ jsx(
|
|
561
512
|
Textarea,
|
|
562
513
|
{
|
|
563
514
|
ref: textareaRef,
|
|
564
|
-
rows: 3,
|
|
515
|
+
rows: isMarkdownEnabled ? 8 : 3,
|
|
565
516
|
className: "w-full resize-none overflow-hidden rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
566
517
|
placeholder,
|
|
567
518
|
value: draft,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/detail/InlineEditors.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport dynamic from 'next/dynamic'\nimport { FileCode, Loader2, Mail, Pencil, Phone, X } from 'lucide-react'\nimport type { PluggableList } from 'unified'\nimport { PhoneNumberField } from '@open-mercato/ui/backend/inputs/PhoneNumberField'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { DatePicker } from '@open-mercato/ui/primitives/date-picker'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { format } from 'date-fns/format'\nimport { LoadingMessage } from './LoadingMessage'\nimport { mapCrudServerErrorToFormErrors } from '../utils/serverErrors'\nimport { MarkdownPreview } from '../markdown'\n\nfunction resolveInlineErrorMessage(err: unknown, fallbackMessage: string): string {\n const { message, fieldErrors } = mapCrudServerErrorToFormErrors(err)\n const firstFieldError = fieldErrors\n ? Object.values(fieldErrors).find((text) => typeof text === 'string' && text.trim().length)\n : null\n if (typeof firstFieldError === 'string' && firstFieldError.trim().length) {\n return firstFieldError.trim()\n }\n if (typeof message === 'string' && message.trim().length) {\n return message.trim()\n }\n if (err instanceof Error && typeof err.message === 'string' && err.message.trim().length) {\n return err.message.trim()\n }\n if (typeof err === 'string' && err.trim().length) {\n return err.trim()\n }\n return fallbackMessage\n}\n\ntype EditorVariant = 'default' | 'muted' | 'plain'\n\nexport type InlineFieldType = 'text' | 'email' | 'tel' | 'url'\n\nconst ALLOWED_INLINE_URL_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:'])\n\nexport function resolveSafeInlineUrlHref(value: string): string | null {\n const trimmed = value.trim()\n if (!trimmed.length) return null\n try {\n const parsed = new URL(trimmed)\n return ALLOWED_INLINE_URL_PROTOCOLS.has(parsed.protocol) ? trimmed : null\n } catch {\n return null\n }\n}\n\nexport type InlineTextEditorProps = {\n label: string\n value: string | null | undefined\n placeholder?: string\n emptyLabel: string\n onSave: (value: string | null) => Promise<void>\n type?: InlineFieldType\n inputType?: React.HTMLInputTypeAttribute\n validator?: (value: string) => string | null\n variant?: EditorVariant\n activateOnClick?: boolean\n containerClassName?: string\n triggerClassName?: string\n hideLabel?: boolean\n renderDisplay?: (params: { value: string | null | undefined; emptyLabel: string; type: InlineFieldType }) => React.ReactNode\n onEditingChange?: (editing: boolean) => void\n renderActions?: React.ReactNode\n saveLabel?: string\n recordId?: string\n onDraftChange?: (draft: string) => void\n renderBelowInput?: (params: {\n draft: string\n resolvedType: InlineFieldType\n error: string | null\n saving: boolean\n }) => React.ReactNode\n}\n\nexport function InlineTextEditor({\n label,\n value,\n placeholder,\n emptyLabel,\n onSave,\n type = 'text',\n inputType,\n validator,\n variant = 'default',\n activateOnClick = false,\n containerClassName,\n triggerClassName,\n hideLabel = false,\n renderDisplay,\n onEditingChange,\n renderActions,\n saveLabel,\n onDraftChange,\n renderBelowInput,\n}: InlineTextEditorProps) {\n const t = useT()\n const [editing, setEditing] = React.useState(false)\n const [draft, setDraft] = React.useState(value ?? '')\n const [error, setError] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n const computedSaveLabel = saveLabel ?? t('ui.detail.inline.saveShortcut', 'Save \u2318\u23CE / Ctrl+Enter')\n const fallbackError = React.useMemo(\n () => t('ui.detail.inline.error', 'Failed to save value.'),\n [t],\n )\n const resolvedType = React.useMemo<InlineFieldType>(() => {\n if (type && typeof type === 'string') return type\n if (inputType && typeof inputType === 'string') {\n const normalized = inputType.toLowerCase()\n if (normalized === 'email' || normalized === 'tel' || normalized === 'url') {\n return normalized as InlineFieldType\n }\n }\n return 'text'\n }, [inputType, type])\n\n React.useEffect(() => {\n if (!editing) setDraft(value ?? '')\n }, [editing, value])\n\n React.useEffect(() => {\n if (onDraftChange) onDraftChange(draft)\n }, [draft, onDraftChange])\n\n const containerClasses = cn(\n 'group overflow-hidden',\n variant === 'muted'\n ? 'relative rounded border bg-muted/30 p-3'\n : variant === 'plain'\n ? 'relative flex items-center gap-3 rounded-none border-0 p-0'\n : 'rounded-lg border p-4',\n activateOnClick && !editing ? 'cursor-pointer' : null,\n containerClassName ?? null,\n )\n const readOnlyWrapperClasses = cn(\n 'flex-1 min-w-0',\n activateOnClick && !editing ? 'cursor-pointer' : null,\n variant === 'plain' ? 'flex items-center gap-2' : null,\n )\n const triggerClasses = cn(\n 'shrink-0 transition-opacity duration-150',\n editing\n ? 'opacity-100'\n : 'opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100',\n variant === 'muted' ? 'h-8 w-8' : null,\n triggerClassName ?? null,\n )\n const triggerSize = variant === 'plain' ? 'icon' : 'sm'\n\n const setEditingSafe = React.useCallback(\n (next: boolean) => {\n setEditing(next)\n if (onEditingChange) onEditingChange(next)\n },\n [onEditingChange],\n )\n\n const handleActivate = React.useCallback(() => {\n if (!editing) setEditingSafe(true)\n }, [editing, setEditingSafe])\n\n const handleInteractiveClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (!activateOnClick || editing) return\n const target = event.target as HTMLElement\n const interactiveElement = target.closest('button, input, select, textarea, a, [role=\"link\"]')\n if (interactiveElement) {\n if (interactiveElement.tagName.toLowerCase() === 'a') {\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n return\n }\n event.preventDefault()\n // let the link click toggle edit mode instead of navigating away\n } else {\n return\n }\n }\n handleActivate()\n },\n [activateOnClick, editing, handleActivate],\n )\n\n const handleContainerKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!activateOnClick || editing) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handleActivate()\n }\n },\n [activateOnClick, editing, handleActivate],\n )\n\n const handleSave = React.useCallback(async () => {\n const trimmed = draft.trim()\n if (validator) {\n const validationError = validator(trimmed)\n if (validationError) {\n setError(validationError)\n return\n }\n }\n setError(null)\n setSaving(true)\n try {\n await onSave(trimmed.length ? trimmed : null)\n setEditingSafe(false)\n } catch (err) {\n setError(resolveInlineErrorMessage(err, fallbackError))\n } finally {\n setSaving(false)\n }\n }, [draft, fallbackError, onSave, setEditingSafe, validator])\n\n const interactiveProps: React.HTMLAttributes<HTMLDivElement> =\n activateOnClick && !editing\n ? {\n role: 'button' as const,\n tabIndex: 0,\n onKeyDown: handleContainerKeyDown,\n }\n : {}\n\n const displayContent = React.useMemo(() => {\n if (renderDisplay) {\n return renderDisplay({ value, emptyLabel, type: resolvedType })\n }\n const baseValue = value && typeof value === 'string' ? value : ''\n const anchorClass =\n variant === 'plain'\n ? 'inline-flex max-w-full min-w-0 items-center gap-2 text-xl font-semibold leading-tight text-primary hover:text-primary/90 hover:underline'\n : 'flex max-w-full min-w-0 items-center gap-2 text-sm text-primary hover:text-primary/90 hover:underline'\n const textClass = variant === 'plain' ? 'text-2xl font-semibold leading-tight' : 'text-sm break-words'\n if (resolvedType === 'email') {\n if (!baseValue.length) {\n return (\n <p className={variant === 'plain' ? 'text-base text-muted-foreground' : 'text-sm text-muted-foreground'}>\n {emptyLabel}\n </p>\n )\n }\n return (\n <a className={anchorClass} href={`mailto:${baseValue}`}>\n <Mail aria-hidden className={variant === 'plain' ? 'h-5 w-5' : 'h-4 w-4'} />\n <span className=\"truncate min-w-0\">{baseValue}</span>\n </a>\n )\n }\n if (!baseValue.length) {\n return (\n <p className={variant === 'plain' ? 'text-base text-muted-foreground' : 'text-sm text-muted-foreground'}>\n {emptyLabel}\n </p>\n )\n }\n if (resolvedType === 'tel') {\n const sanitizedValue = baseValue.replace(/[^+\\d]/g, '')\n const hrefValue = sanitizedValue.length ? sanitizedValue : baseValue\n return (\n <a className={anchorClass} href={`tel:${hrefValue}`}>\n <Phone aria-hidden className={variant === 'plain' ? 'h-5 w-5' : 'h-4 w-4'} />\n <span className=\"truncate\">{baseValue}</span>\n </a>\n )\n }\n if (resolvedType === 'url') {\n const safeHref = resolveSafeInlineUrlHref(baseValue)\n if (!safeHref) {\n return <p className={textClass}>{baseValue}</p>\n }\n return (\n <a className={textClass} href={safeHref} target=\"_blank\" rel=\"noopener noreferrer\">\n {baseValue}\n </a>\n )\n }\n return <p className={textClass}>{baseValue}</p>\n }, [emptyLabel, renderDisplay, resolvedType, value, variant])\n\n const editingContainerClass = variant === 'plain' ? 'mt-0 w-full max-w-sm space-y-3' : 'mt-2 space-y-3'\n\n return (\n <div className={containerClasses} onClick={handleInteractiveClick}>\n <div className=\"flex items-start justify-between gap-2 min-w-0\">\n <div className={readOnlyWrapperClasses} {...interactiveProps}>\n {hideLabel ? null : <p className=\"text-xs uppercase tracking-wide text-muted-foreground\">{label}</p>}\n {editing ? (\n <form\n className={editingContainerClass}\n onSubmit={(event) => {\n event.preventDefault()\n if (!saving) void handleSave()\n }}\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n setEditingSafe(false)\n setError(null)\n return\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (!saving) void handleSave()\n }\n }}\n >\n {(() => {\n const lowerType = (inputType ?? resolvedType ?? '').toLowerCase()\n const isDate = lowerType === 'date'\n const isDateTime = lowerType === 'datetime-local' || lowerType === 'datetime'\n if (resolvedType === 'tel') {\n return (\n <PhoneNumberField\n value={draft.length ? draft : undefined}\n onValueChange={(next) => {\n if (error) setError(null)\n setDraft(next ?? '')\n }}\n placeholder={placeholder}\n autoFocus\n disabled={saving}\n minDigits={7}\n />\n )\n }\n if (isDate || isDateTime) {\n let parsed: Date | null = null\n if (draft && draft.length) {\n const candidate = new Date(draft)\n if (!Number.isNaN(candidate.getTime())) parsed = candidate\n }\n return (\n <DatePicker\n value={parsed}\n onChange={(date) => {\n if (error) setError(null)\n const formatted = !date\n ? ''\n : isDateTime\n ? format(date, \"yyyy-MM-dd'T'HH:mm\")\n : format(date, 'yyyy-MM-dd')\n setDraft(formatted)\n setSaving(true)\n ;(async () => {\n try {\n await onSave(formatted.length ? formatted : null)\n setEditingSafe(false)\n } catch (err) {\n setError(resolveInlineErrorMessage(err, fallbackError))\n } finally {\n setSaving(false)\n }\n })()\n }}\n withTime={isDateTime}\n footer=\"apply-cancel\"\n placeholder={placeholder}\n disabled={saving}\n />\n )\n }\n return (\n <input\n className=\"w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n value={draft}\n onChange={(event) => {\n if (error) setError(null)\n setDraft(event.target.value)\n }}\n placeholder={placeholder}\n type={inputType ?? resolvedType}\n autoFocus\n />\n )\n })()}\n {error ? <p className=\"text-xs text-destructive\">{error}</p> : null}\n {renderBelowInput ? renderBelowInput({ draft, resolvedType, error, saving }) : null}\n {(() => {\n const lowerType = (inputType ?? resolvedType ?? '').toLowerCase()\n const isDateLike = lowerType === 'date' || lowerType === 'datetime-local' || lowerType === 'datetime'\n if (isDateLike) return null\n return (\n <div className=\"flex items-center gap-2\">\n <Button type=\"submit\" size=\"sm\" disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {computedSaveLabel}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => setEditingSafe(false)} disabled={saving}>\n {t('ui.detail.inline.cancel', 'Cancel')}\n </Button>\n </div>\n )\n })()}\n </form>\n ) : (\n <div className={variant === 'plain' ? '' : 'mt-1'}>{displayContent}</div>\n )}\n </div>\n {renderActions ? <div className=\"flex items-center gap-2\">{renderActions}</div> : null}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size={triggerSize}\n className={triggerClasses}\n onClick={(event) => {\n event.stopPropagation()\n const next = !editing\n setEditingSafe(next)\n }}\n >\n {editing ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n </Button>\n </div>\n </div>\n )\n}\n\nexport type InlineMultilineEditorProps = {\n label: string\n value: string | null | undefined\n placeholder?: string\n emptyLabel: string\n onSave: (value: string | null) => Promise<void>\n validator?: (value: string) => string | null\n variant?: EditorVariant\n activateOnClick?: boolean\n containerClassName?: string\n triggerClassName?: string\n renderDisplay?: (params: { value: string | null | undefined; emptyLabel: string }) => React.ReactNode\n}\n\ntype UiMarkdownEditorProps = {\n value?: string\n height?: number\n onChange?: (value?: string) => void\n previewOptions?: { remarkPlugins?: unknown[] }\n}\n\nconst isTestEnv =\n typeof process !== 'undefined' &&\n (process.env.NODE_ENV === 'test' || typeof process.env.JEST_WORKER_ID !== 'undefined')\n\nfunction MarkdownEditorFallback() {\n const t = useT()\n return (\n <LoadingMessage label={t('ui.detail.inline.editorLoading', 'Loading editor\u2026')} className=\"min-h-[200px] justify-center\" />\n )\n}\n\nconst MarkdownEditorTestStub: React.ComponentType<UiMarkdownEditorProps> = ({ value, onChange }) => (\n <Textarea\n data-testid=\"markdown-editor\"\n rows={8}\n value={value ?? ''}\n onChange={(event) => onChange?.(event.target.value)}\n />\n)\n\nconst MarkdownEditorComponent: React.ComponentType<UiMarkdownEditorProps> = isTestEnv\n ? MarkdownEditorTestStub\n : (dynamic(() => import('@uiw/react-md-editor'), {\n ssr: false,\n loading: () => <MarkdownEditorFallback />,\n }) as unknown as React.ComponentType<UiMarkdownEditorProps>)\n\nlet markdownPluginsPromise: Promise<PluggableList> | null = null\n\nasync function loadMarkdownPlugins(): Promise<PluggableList> {\n if (isTestEnv) return []\n if (!markdownPluginsPromise) {\n markdownPluginsPromise = import('remark-gfm')\n .then((mod) => [mod.default ?? mod] as PluggableList)\n .catch(() => [])\n }\n return markdownPluginsPromise\n}\n\nexport function InlineMultilineEditor({\n label,\n value,\n placeholder,\n emptyLabel,\n onSave,\n validator,\n variant = 'default',\n activateOnClick = true,\n containerClassName,\n triggerClassName,\n renderDisplay,\n}: InlineMultilineEditorProps) {\n const t = useT()\n const [editing, setEditing] = React.useState(false)\n const [draft, setDraft] = React.useState(value ?? '')\n const [error, setError] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n const [isMarkdownEnabled, setIsMarkdownEnabled] = React.useState(true)\n const textareaRef = React.useRef<HTMLTextAreaElement | null>(null)\n const markdownEditorRef = React.useRef<HTMLDivElement | null>(null)\n const [markdownPlugins, setMarkdownPlugins] = React.useState<PluggableList>([])\n const fallbackError = React.useMemo(\n () => t('ui.detail.inline.error', 'Failed to save value.'),\n [t],\n )\n React.useEffect(() => {\n if (isTestEnv) return\n let mounted = true\n void loadMarkdownPlugins().then((plugins) => {\n if (!mounted) return\n setMarkdownPlugins(plugins)\n })\n return () => {\n mounted = false\n }\n }, [])\n\n const adjustTextareaSize = React.useCallback((element: HTMLTextAreaElement | null) => {\n if (!element) return\n element.style.height = 'auto'\n element.style.height = `${element.scrollHeight}px`\n }, [])\n\n React.useEffect(() => {\n adjustTextareaSize(textareaRef.current)\n }, [adjustTextareaSize, draft, isMarkdownEnabled])\n\n React.useEffect(() => {\n if (!editing) return\n if (isMarkdownEnabled) {\n const element = markdownEditorRef.current?.querySelector('textarea')\n if (!element) return\n window.requestAnimationFrame(() => {\n element.focus()\n })\n return\n }\n const element = textareaRef.current\n if (!element) return\n window.requestAnimationFrame(() => {\n adjustTextareaSize(element)\n element.focus()\n })\n }, [adjustTextareaSize, editing, isMarkdownEnabled])\n\n const handleMarkdownToggle = React.useCallback(() => {\n setIsMarkdownEnabled((prev) => !prev)\n }, [])\n\n React.useEffect(() => {\n if (!editing) {\n setDraft(value ?? '')\n setError(null)\n }\n }, [editing, value])\n\n const handleActivate = React.useCallback(() => {\n if (!editing) setEditing(true)\n }, [editing])\n\n const handleInteractiveClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (!activateOnClick || editing) return\n const target = event.target as HTMLElement\n const interactiveElement = target.closest('button, input, select, textarea, a, [role=\"link\"]')\n if (interactiveElement) {\n if (interactiveElement.tagName.toLowerCase() === 'a') {\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n return\n }\n event.preventDefault()\n // Links should not block activation; let the click toggle edit mode\n } else {\n return\n }\n }\n handleActivate()\n },\n [activateOnClick, editing, handleActivate],\n )\n\n const handleContainerKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!activateOnClick || editing) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handleActivate()\n }\n },\n [activateOnClick, editing, handleActivate],\n )\n\n const adjustError = React.useCallback(\n (nextValue: string) => {\n if (!validator) return null\n const trimmed = nextValue.trim()\n return validator(trimmed)\n },\n [validator],\n )\n\n const containerClasses = cn(\n 'group rounded-lg border p-4',\n variant === 'muted' ? 'bg-muted/30' : null,\n activateOnClick && !editing ? 'cursor-pointer' : null,\n containerClassName ?? null,\n )\n const triggerClasses = cn(\n 'transition-opacity duration-150',\n editing\n ? 'opacity-100'\n : 'opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100',\n triggerClassName ?? null,\n )\n\n const handleSave = React.useCallback(async () => {\n const trimmed = draft.trim()\n const validationError = adjustError(draft)\n if (validationError) {\n setError(validationError)\n return\n }\n setSaving(true)\n try {\n await onSave(trimmed.length ? trimmed : null)\n setEditing(false)\n } catch (err) {\n setError(resolveInlineErrorMessage(err, fallbackError))\n } finally {\n setSaving(false)\n }\n }, [adjustError, draft, fallbackError, onSave])\n\n return (\n <div className={containerClasses} onClick={handleInteractiveClick}>\n <div className=\"flex items-start justify-between gap-2\">\n <div\n className={cn('flex-1 min-w-0', activateOnClick && !editing ? 'cursor-pointer' : null)}\n {...(activateOnClick && !editing\n ? { role: 'button' as const, tabIndex: 0, onKeyDown: handleContainerKeyDown }\n : {})}\n >\n <p className=\"text-xs uppercase tracking-wide text-muted-foreground\">{label}</p>\n {editing ? (\n <form\n className=\"mt-2 space-y-3\"\n onSubmit={(event) => {\n event.preventDefault()\n if (!saving) void handleSave()\n }}\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n setEditing(false)\n setError(null)\n return\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (!saving) void handleSave()\n }\n }}\n >\n {isMarkdownEnabled ? (\n <div\n ref={markdownEditorRef}\n className={cn(\n 'w-full rounded-md border border-muted-foreground/30 bg-background p-2',\n saving ? 'pointer-events-none opacity-75' : null,\n )}\n >\n <div data-color-mode=\"light\" className=\"w-full\">\n <MarkdownEditorComponent\n value={draft}\n height={220}\n onChange={(nextValue) => {\n if (error) setError(null)\n setDraft(typeof nextValue === 'string' ? nextValue : '')\n }}\n previewOptions={{ remarkPlugins: markdownPlugins }}\n />\n </div>\n </div>\n ) : (\n <Textarea\n ref={textareaRef}\n rows={3}\n className=\"w-full resize-none overflow-hidden rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n placeholder={placeholder}\n value={draft}\n onChange={(event) => {\n if (error) setError(null)\n setDraft(event.target.value)\n }}\n onInput={(event) => adjustTextareaSize(event.currentTarget)}\n autoFocus\n disabled={saving}\n />\n )}\n {error ? <p className=\"text-xs text-destructive\">{error}</p> : null}\n <div className=\"flex items-center gap-2\">\n <Button type=\"submit\" size=\"sm\" disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {t('ui.detail.inline.saveShortcut', 'Save \u2318\u23CE / Ctrl+Enter')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => setEditing(false)} disabled={saving}>\n {t('ui.detail.inline.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={handleMarkdownToggle}\n aria-pressed={isMarkdownEnabled}\n title={\n isMarkdownEnabled\n ? t('ui.detail.inline.markdownDisable', 'Disable Markdown')\n : t('ui.detail.inline.markdownEnable', 'Enable Markdown')\n }\n aria-label={\n isMarkdownEnabled\n ? t('ui.detail.inline.markdownDisable', 'Disable Markdown')\n : t('ui.detail.inline.markdownEnable', 'Enable Markdown')\n }\n className={cn('h-8 w-8', isMarkdownEnabled ? 'text-primary' : undefined)}\n disabled={saving}\n >\n <FileCode className=\"h-4 w-4\" aria-hidden />\n <span className=\"sr-only\">\n {isMarkdownEnabled\n ? t('ui.detail.inline.markdownDisable', 'Disable Markdown')\n : t('ui.detail.inline.markdownEnable', 'Enable Markdown')}\n </span>\n </Button>\n </div>\n </form>\n ) : (\n <div\n className={cn(\n 'mt-1 text-sm break-words',\n renderDisplay ? null : 'whitespace-pre-wrap',\n activateOnClick && !editing ? 'cursor-pointer' : null,\n )}\n >\n {renderDisplay ? (\n renderDisplay({ value, emptyLabel })\n ) : value && value.length ? (\n <MarkdownPreview\n remarkPlugins={markdownPlugins}\n className=\"prose prose-sm max-w-none text-foreground [&>*]:my-2 [&>*:last-child]:mb-0 [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5\"\n >\n {value}\n </MarkdownPreview>\n ) : (\n <span className=\"text-muted-foreground\">{emptyLabel}</span>\n )}\n </div>\n )}\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={triggerClasses}\n onClick={(event) => {\n event.stopPropagation()\n setEditing((state) => !state)\n }}\n >\n {editing ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n </Button>\n </div>\n </div>\n )\n}\n\nexport type InlineSelectOption = { value: string; label: string; description?: string }\n\nexport type InlineSelectEditorProps = {\n label: string\n value: string | null | undefined\n emptyLabel: string\n options: InlineSelectOption[]\n onSave: (value: string | null) => Promise<void>\n variant?: EditorVariant\n activateOnClick?: boolean\n containerClassName?: string\n triggerClassName?: string\n hideLabel?: boolean\n renderEditor?: (params: { value: string; onChange: (next: string) => void }) => React.ReactNode\n renderDisplay?: (params: { value: string | null | undefined; emptyLabel: string }) => React.ReactNode\n}\n\nexport function InlineSelectEditor({\n label,\n value,\n emptyLabel,\n options,\n onSave,\n variant = 'default',\n activateOnClick = false,\n containerClassName,\n triggerClassName,\n hideLabel = false,\n renderEditor,\n renderDisplay,\n}: InlineSelectEditorProps) {\n const t = useT()\n const [editing, setEditing] = React.useState(false)\n const [draft, setDraft] = React.useState<string>(value ?? '')\n const [saving, setSaving] = React.useState(false)\n\n React.useEffect(() => {\n if (!editing) setDraft(value ?? '')\n }, [editing, value])\n\n const containerClasses = cn(\n 'group',\n variant === 'muted'\n ? 'relative rounded border bg-muted/30 p-3'\n : variant === 'plain'\n ? 'relative flex flex-col gap-1 rounded-none border-0 p-0'\n : 'rounded-lg border bg-card p-4',\n activateOnClick && !editing ? 'cursor-pointer' : null,\n containerClassName ?? null,\n )\n const triggerClasses = cn(\n 'shrink-0 transition-opacity duration-150',\n editing\n ? 'opacity-100'\n : 'opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100',\n variant === 'muted' ? 'h-8 w-8' : null,\n triggerClassName ?? null,\n )\n\n const handleSave = React.useCallback(async () => {\n setSaving(true)\n try {\n await onSave(draft.length ? draft : null)\n setEditing(false)\n } catch (err) {\n const message = err instanceof Error ? err.message : t('ui.detail.inline.error', 'Failed to save value.')\n console.error(message, err)\n } finally {\n setSaving(false)\n }\n }, [draft, onSave, t])\n\n const selected = options.find((option) => option.value === value)\n\n const interactiveProps: React.HTMLAttributes<HTMLDivElement> =\n activateOnClick && !editing\n ? {\n role: 'button' as const,\n tabIndex: 0,\n onClick: () => setEditing(true),\n onKeyDown: (event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n setEditing(true)\n }\n },\n }\n : {}\n\n return (\n <div className={containerClasses}>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\" {...interactiveProps}>\n {hideLabel ? null : <p className=\"text-xs uppercase tracking-wide text-muted-foreground\">{label}</p>}\n {editing ? (\n <div className={variant === 'plain' ? 'space-y-2 pt-1' : 'mt-2 space-y-2'}>\n {renderEditor ? (\n renderEditor({ value: draft, onChange: setDraft })\n ) : (\n <Select\n value={draft || undefined}\n onValueChange={(next) => setDraft(next ?? '')}\n >\n <SelectTrigger>\n <SelectValue placeholder={t('ui.detail.inline.select.placeholder', 'Not set')} />\n </SelectTrigger>\n <SelectContent>\n {options.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" size=\"sm\" onClick={() => void handleSave()} disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {t('ui.detail.inline.saveShortcut', 'Save \u2318\u23CE / Ctrl+Enter')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => setEditing(false)} disabled={saving}>\n {t('ui.detail.inline.cancel', 'Cancel')}\n </Button>\n </div>\n </div>\n ) : (\n <div className={variant === 'plain' ? 'flex items-center gap-2' : 'mt-1 text-sm'}>\n {renderDisplay ? (\n renderDisplay({ value, emptyLabel })\n ) : selected ? (\n <div className=\"space-y-0.5\">\n <p className=\"font-medium leading-tight\">{selected.label}</p>\n {selected.description ? (\n <p className=\"text-xs text-muted-foreground\">{selected.description}</p>\n ) : null}\n </div>\n ) : (\n <span className=\"text-muted-foreground\">{emptyLabel}</span>\n )}\n </div>\n )}\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size={variant === 'plain' ? 'icon' : 'sm'}\n className={triggerClasses}\n onClick={(event) => {\n event.stopPropagation()\n setEditing((state) => !state)\n }}\n >\n {editing ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n </Button>\n </div>\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": [
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { FileCode, Loader2, Mail, Pencil, Phone, X } from 'lucide-react'\nimport type { PluggableList } from 'unified'\nimport { PhoneNumberField } from '@open-mercato/ui/backend/inputs/PhoneNumberField'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { DatePicker } from '@open-mercato/ui/primitives/date-picker'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { format } from 'date-fns/format'\nimport { LoadingMessage } from './LoadingMessage'\nimport { mapCrudServerErrorToFormErrors } from '../utils/serverErrors'\nimport { MarkdownPreview } from '../markdown'\n\nfunction resolveInlineErrorMessage(err: unknown, fallbackMessage: string): string {\n const { message, fieldErrors } = mapCrudServerErrorToFormErrors(err)\n const firstFieldError = fieldErrors\n ? Object.values(fieldErrors).find((text) => typeof text === 'string' && text.trim().length)\n : null\n if (typeof firstFieldError === 'string' && firstFieldError.trim().length) {\n return firstFieldError.trim()\n }\n if (typeof message === 'string' && message.trim().length) {\n return message.trim()\n }\n if (err instanceof Error && typeof err.message === 'string' && err.message.trim().length) {\n return err.message.trim()\n }\n if (typeof err === 'string' && err.trim().length) {\n return err.trim()\n }\n return fallbackMessage\n}\n\ntype EditorVariant = 'default' | 'muted' | 'plain'\n\nexport type InlineFieldType = 'text' | 'email' | 'tel' | 'url'\n\nconst ALLOWED_INLINE_URL_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:'])\n\nexport function resolveSafeInlineUrlHref(value: string): string | null {\n const trimmed = value.trim()\n if (!trimmed.length) return null\n try {\n const parsed = new URL(trimmed)\n return ALLOWED_INLINE_URL_PROTOCOLS.has(parsed.protocol) ? trimmed : null\n } catch {\n return null\n }\n}\n\nexport type InlineTextEditorProps = {\n label: string\n value: string | null | undefined\n placeholder?: string\n emptyLabel: string\n onSave: (value: string | null) => Promise<void>\n type?: InlineFieldType\n inputType?: React.HTMLInputTypeAttribute\n validator?: (value: string) => string | null\n variant?: EditorVariant\n activateOnClick?: boolean\n containerClassName?: string\n triggerClassName?: string\n hideLabel?: boolean\n renderDisplay?: (params: { value: string | null | undefined; emptyLabel: string; type: InlineFieldType }) => React.ReactNode\n onEditingChange?: (editing: boolean) => void\n renderActions?: React.ReactNode\n saveLabel?: string\n recordId?: string\n onDraftChange?: (draft: string) => void\n renderBelowInput?: (params: {\n draft: string\n resolvedType: InlineFieldType\n error: string | null\n saving: boolean\n }) => React.ReactNode\n}\n\nexport function InlineTextEditor({\n label,\n value,\n placeholder,\n emptyLabel,\n onSave,\n type = 'text',\n inputType,\n validator,\n variant = 'default',\n activateOnClick = false,\n containerClassName,\n triggerClassName,\n hideLabel = false,\n renderDisplay,\n onEditingChange,\n renderActions,\n saveLabel,\n onDraftChange,\n renderBelowInput,\n}: InlineTextEditorProps) {\n const t = useT()\n const [editing, setEditing] = React.useState(false)\n const [draft, setDraft] = React.useState(value ?? '')\n const [error, setError] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n const computedSaveLabel = saveLabel ?? t('ui.detail.inline.saveShortcut', 'Save \u2318\u23CE / Ctrl+Enter')\n const fallbackError = React.useMemo(\n () => t('ui.detail.inline.error', 'Failed to save value.'),\n [t],\n )\n const resolvedType = React.useMemo<InlineFieldType>(() => {\n if (type && typeof type === 'string') return type\n if (inputType && typeof inputType === 'string') {\n const normalized = inputType.toLowerCase()\n if (normalized === 'email' || normalized === 'tel' || normalized === 'url') {\n return normalized as InlineFieldType\n }\n }\n return 'text'\n }, [inputType, type])\n\n React.useEffect(() => {\n if (!editing) setDraft(value ?? '')\n }, [editing, value])\n\n React.useEffect(() => {\n if (onDraftChange) onDraftChange(draft)\n }, [draft, onDraftChange])\n\n const containerClasses = cn(\n 'group overflow-hidden',\n variant === 'muted'\n ? 'relative rounded border bg-muted/30 p-3'\n : variant === 'plain'\n ? 'relative flex items-center gap-3 rounded-none border-0 p-0'\n : 'rounded-lg border p-4',\n activateOnClick && !editing ? 'cursor-pointer' : null,\n containerClassName ?? null,\n )\n const readOnlyWrapperClasses = cn(\n 'flex-1 min-w-0',\n activateOnClick && !editing ? 'cursor-pointer' : null,\n variant === 'plain' ? 'flex items-center gap-2' : null,\n )\n const triggerClasses = cn(\n 'shrink-0 transition-opacity duration-150',\n editing\n ? 'opacity-100'\n : 'opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100',\n variant === 'muted' ? 'h-8 w-8' : null,\n triggerClassName ?? null,\n )\n const triggerSize = variant === 'plain' ? 'icon' : 'sm'\n\n const setEditingSafe = React.useCallback(\n (next: boolean) => {\n setEditing(next)\n if (onEditingChange) onEditingChange(next)\n },\n [onEditingChange],\n )\n\n const handleActivate = React.useCallback(() => {\n if (!editing) setEditingSafe(true)\n }, [editing, setEditingSafe])\n\n const handleInteractiveClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (!activateOnClick || editing) return\n const target = event.target as HTMLElement\n const interactiveElement = target.closest('button, input, select, textarea, a, [role=\"link\"]')\n if (interactiveElement) {\n if (interactiveElement.tagName.toLowerCase() === 'a') {\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n return\n }\n event.preventDefault()\n // let the link click toggle edit mode instead of navigating away\n } else {\n return\n }\n }\n handleActivate()\n },\n [activateOnClick, editing, handleActivate],\n )\n\n const handleContainerKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!activateOnClick || editing) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handleActivate()\n }\n },\n [activateOnClick, editing, handleActivate],\n )\n\n const handleSave = React.useCallback(async () => {\n const trimmed = draft.trim()\n if (validator) {\n const validationError = validator(trimmed)\n if (validationError) {\n setError(validationError)\n return\n }\n }\n setError(null)\n setSaving(true)\n try {\n await onSave(trimmed.length ? trimmed : null)\n setEditingSafe(false)\n } catch (err) {\n setError(resolveInlineErrorMessage(err, fallbackError))\n } finally {\n setSaving(false)\n }\n }, [draft, fallbackError, onSave, setEditingSafe, validator])\n\n const interactiveProps: React.HTMLAttributes<HTMLDivElement> =\n activateOnClick && !editing\n ? {\n role: 'button' as const,\n tabIndex: 0,\n onKeyDown: handleContainerKeyDown,\n }\n : {}\n\n const displayContent = React.useMemo(() => {\n if (renderDisplay) {\n return renderDisplay({ value, emptyLabel, type: resolvedType })\n }\n const baseValue = value && typeof value === 'string' ? value : ''\n const anchorClass =\n variant === 'plain'\n ? 'inline-flex max-w-full min-w-0 items-center gap-2 text-xl font-semibold leading-tight text-primary hover:text-primary/90 hover:underline'\n : 'flex max-w-full min-w-0 items-center gap-2 text-sm text-primary hover:text-primary/90 hover:underline'\n const textClass = variant === 'plain' ? 'text-2xl font-semibold leading-tight' : 'text-sm break-words'\n if (resolvedType === 'email') {\n if (!baseValue.length) {\n return (\n <p className={variant === 'plain' ? 'text-base text-muted-foreground' : 'text-sm text-muted-foreground'}>\n {emptyLabel}\n </p>\n )\n }\n return (\n <a className={anchorClass} href={`mailto:${baseValue}`}>\n <Mail aria-hidden className={variant === 'plain' ? 'h-5 w-5' : 'h-4 w-4'} />\n <span className=\"truncate min-w-0\">{baseValue}</span>\n </a>\n )\n }\n if (!baseValue.length) {\n return (\n <p className={variant === 'plain' ? 'text-base text-muted-foreground' : 'text-sm text-muted-foreground'}>\n {emptyLabel}\n </p>\n )\n }\n if (resolvedType === 'tel') {\n const sanitizedValue = baseValue.replace(/[^+\\d]/g, '')\n const hrefValue = sanitizedValue.length ? sanitizedValue : baseValue\n return (\n <a className={anchorClass} href={`tel:${hrefValue}`}>\n <Phone aria-hidden className={variant === 'plain' ? 'h-5 w-5' : 'h-4 w-4'} />\n <span className=\"truncate\">{baseValue}</span>\n </a>\n )\n }\n if (resolvedType === 'url') {\n const safeHref = resolveSafeInlineUrlHref(baseValue)\n if (!safeHref) {\n return <p className={textClass}>{baseValue}</p>\n }\n return (\n <a className={textClass} href={safeHref} target=\"_blank\" rel=\"noopener noreferrer\">\n {baseValue}\n </a>\n )\n }\n return <p className={textClass}>{baseValue}</p>\n }, [emptyLabel, renderDisplay, resolvedType, value, variant])\n\n const editingContainerClass = variant === 'plain' ? 'mt-0 w-full max-w-sm space-y-3' : 'mt-2 space-y-3'\n\n return (\n <div className={containerClasses} onClick={handleInteractiveClick}>\n <div className=\"flex items-start justify-between gap-2 min-w-0\">\n <div className={readOnlyWrapperClasses} {...interactiveProps}>\n {hideLabel ? null : <p className=\"text-xs uppercase tracking-wide text-muted-foreground\">{label}</p>}\n {editing ? (\n <form\n className={editingContainerClass}\n onSubmit={(event) => {\n event.preventDefault()\n if (!saving) void handleSave()\n }}\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n setEditingSafe(false)\n setError(null)\n return\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (!saving) void handleSave()\n }\n }}\n >\n {(() => {\n const lowerType = (inputType ?? resolvedType ?? '').toLowerCase()\n const isDate = lowerType === 'date'\n const isDateTime = lowerType === 'datetime-local' || lowerType === 'datetime'\n if (resolvedType === 'tel') {\n return (\n <PhoneNumberField\n value={draft.length ? draft : undefined}\n onValueChange={(next) => {\n if (error) setError(null)\n setDraft(next ?? '')\n }}\n placeholder={placeholder}\n autoFocus\n disabled={saving}\n minDigits={7}\n />\n )\n }\n if (isDate || isDateTime) {\n let parsed: Date | null = null\n if (draft && draft.length) {\n const candidate = new Date(draft)\n if (!Number.isNaN(candidate.getTime())) parsed = candidate\n }\n return (\n <DatePicker\n value={parsed}\n onChange={(date) => {\n if (error) setError(null)\n const formatted = !date\n ? ''\n : isDateTime\n ? format(date, \"yyyy-MM-dd'T'HH:mm\")\n : format(date, 'yyyy-MM-dd')\n setDraft(formatted)\n setSaving(true)\n ;(async () => {\n try {\n await onSave(formatted.length ? formatted : null)\n setEditingSafe(false)\n } catch (err) {\n setError(resolveInlineErrorMessage(err, fallbackError))\n } finally {\n setSaving(false)\n }\n })()\n }}\n withTime={isDateTime}\n footer=\"apply-cancel\"\n placeholder={placeholder}\n disabled={saving}\n />\n )\n }\n return (\n <input\n className=\"w-full rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n value={draft}\n onChange={(event) => {\n if (error) setError(null)\n setDraft(event.target.value)\n }}\n placeholder={placeholder}\n type={inputType ?? resolvedType}\n autoFocus\n />\n )\n })()}\n {error ? <p className=\"text-xs text-destructive\">{error}</p> : null}\n {renderBelowInput ? renderBelowInput({ draft, resolvedType, error, saving }) : null}\n {(() => {\n const lowerType = (inputType ?? resolvedType ?? '').toLowerCase()\n const isDateLike = lowerType === 'date' || lowerType === 'datetime-local' || lowerType === 'datetime'\n if (isDateLike) return null\n return (\n <div className=\"flex items-center gap-2\">\n <Button type=\"submit\" size=\"sm\" disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {computedSaveLabel}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => setEditingSafe(false)} disabled={saving}>\n {t('ui.detail.inline.cancel', 'Cancel')}\n </Button>\n </div>\n )\n })()}\n </form>\n ) : (\n <div className={variant === 'plain' ? '' : 'mt-1'}>{displayContent}</div>\n )}\n </div>\n {renderActions ? <div className=\"flex items-center gap-2\">{renderActions}</div> : null}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size={triggerSize}\n className={triggerClasses}\n onClick={(event) => {\n event.stopPropagation()\n const next = !editing\n setEditingSafe(next)\n }}\n >\n {editing ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n </Button>\n </div>\n </div>\n )\n}\n\nexport type InlineMultilineEditorProps = {\n label: string\n value: string | null | undefined\n placeholder?: string\n emptyLabel: string\n onSave: (value: string | null) => Promise<void>\n validator?: (value: string) => string | null\n variant?: EditorVariant\n activateOnClick?: boolean\n containerClassName?: string\n triggerClassName?: string\n renderDisplay?: (params: { value: string | null | undefined; emptyLabel: string }) => React.ReactNode\n}\n\nconst isTestEnv =\n typeof process !== 'undefined' &&\n (process.env.NODE_ENV === 'test' || typeof process.env.JEST_WORKER_ID !== 'undefined')\n\nlet markdownPluginsPromise: Promise<PluggableList> | null = null\n\nasync function loadMarkdownPlugins(): Promise<PluggableList> {\n if (isTestEnv) return []\n if (!markdownPluginsPromise) {\n markdownPluginsPromise = import('remark-gfm')\n .then((mod) => [mod.default ?? mod] as PluggableList)\n .catch(() => [])\n }\n return markdownPluginsPromise\n}\n\nexport function InlineMultilineEditor({\n label,\n value,\n placeholder,\n emptyLabel,\n onSave,\n validator,\n variant = 'default',\n activateOnClick = true,\n containerClassName,\n triggerClassName,\n renderDisplay,\n}: InlineMultilineEditorProps) {\n const t = useT()\n const [editing, setEditing] = React.useState(false)\n const [draft, setDraft] = React.useState(value ?? '')\n const [error, setError] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n const [isMarkdownEnabled, setIsMarkdownEnabled] = React.useState(true)\n const textareaRef = React.useRef<HTMLTextAreaElement | null>(null)\n const [markdownPlugins, setMarkdownPlugins] = React.useState<PluggableList>([])\n const fallbackError = React.useMemo(\n () => t('ui.detail.inline.error', 'Failed to save value.'),\n [t],\n )\n React.useEffect(() => {\n if (isTestEnv) return\n let mounted = true\n void loadMarkdownPlugins().then((plugins) => {\n if (!mounted) return\n setMarkdownPlugins(plugins)\n })\n return () => {\n mounted = false\n }\n }, [])\n\n const adjustTextareaSize = React.useCallback((element: HTMLTextAreaElement | null) => {\n if (!element) return\n element.style.height = 'auto'\n element.style.height = `${element.scrollHeight}px`\n }, [])\n\n React.useEffect(() => {\n adjustTextareaSize(textareaRef.current)\n }, [adjustTextareaSize, draft, isMarkdownEnabled])\n\n React.useEffect(() => {\n if (!editing) return\n const element = textareaRef.current\n if (!element) return\n window.requestAnimationFrame(() => {\n adjustTextareaSize(element)\n element.focus()\n })\n }, [adjustTextareaSize, editing, isMarkdownEnabled])\n\n const handleMarkdownToggle = React.useCallback(() => {\n setIsMarkdownEnabled((prev) => !prev)\n }, [])\n\n React.useEffect(() => {\n if (!editing) {\n setDraft(value ?? '')\n setError(null)\n }\n }, [editing, value])\n\n const handleActivate = React.useCallback(() => {\n if (!editing) setEditing(true)\n }, [editing])\n\n const handleInteractiveClick = React.useCallback(\n (event: React.MouseEvent<HTMLDivElement>) => {\n if (!activateOnClick || editing) return\n const target = event.target as HTMLElement\n const interactiveElement = target.closest('button, input, select, textarea, a, [role=\"link\"]')\n if (interactiveElement) {\n if (interactiveElement.tagName.toLowerCase() === 'a') {\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n return\n }\n event.preventDefault()\n // Links should not block activation; let the click toggle edit mode\n } else {\n return\n }\n }\n handleActivate()\n },\n [activateOnClick, editing, handleActivate],\n )\n\n const handleContainerKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!activateOnClick || editing) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handleActivate()\n }\n },\n [activateOnClick, editing, handleActivate],\n )\n\n const adjustError = React.useCallback(\n (nextValue: string) => {\n if (!validator) return null\n const trimmed = nextValue.trim()\n return validator(trimmed)\n },\n [validator],\n )\n\n const containerClasses = cn(\n 'group rounded-lg border p-4',\n variant === 'muted' ? 'bg-muted/30' : null,\n activateOnClick && !editing ? 'cursor-pointer' : null,\n containerClassName ?? null,\n )\n const triggerClasses = cn(\n 'transition-opacity duration-150',\n editing\n ? 'opacity-100'\n : 'opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100',\n triggerClassName ?? null,\n )\n\n const handleSave = React.useCallback(async () => {\n const trimmed = draft.trim()\n const validationError = adjustError(draft)\n if (validationError) {\n setError(validationError)\n return\n }\n setSaving(true)\n try {\n await onSave(trimmed.length ? trimmed : null)\n setEditing(false)\n } catch (err) {\n setError(resolveInlineErrorMessage(err, fallbackError))\n } finally {\n setSaving(false)\n }\n }, [adjustError, draft, fallbackError, onSave])\n\n return (\n <div className={containerClasses} onClick={handleInteractiveClick}>\n <div className=\"flex items-start justify-between gap-2\">\n <div\n className={cn('flex-1 min-w-0', activateOnClick && !editing ? 'cursor-pointer' : null)}\n {...(activateOnClick && !editing\n ? { role: 'button' as const, tabIndex: 0, onKeyDown: handleContainerKeyDown }\n : {})}\n >\n <p className=\"text-xs uppercase tracking-wide text-muted-foreground\">{label}</p>\n {editing ? (\n <form\n className=\"mt-2 space-y-3\"\n onSubmit={(event) => {\n event.preventDefault()\n if (!saving) void handleSave()\n }}\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n setEditing(false)\n setError(null)\n return\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (!saving) void handleSave()\n }\n }}\n >\n <Textarea\n ref={textareaRef}\n rows={isMarkdownEnabled ? 8 : 3}\n className=\"w-full resize-none overflow-hidden rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n placeholder={placeholder}\n value={draft}\n onChange={(event) => {\n if (error) setError(null)\n setDraft(event.target.value)\n }}\n onInput={(event) => adjustTextareaSize(event.currentTarget)}\n autoFocus\n disabled={saving}\n />\n {error ? <p className=\"text-xs text-destructive\">{error}</p> : null}\n <div className=\"flex items-center gap-2\">\n <Button type=\"submit\" size=\"sm\" disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {t('ui.detail.inline.saveShortcut', 'Save \u2318\u23CE / Ctrl+Enter')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => setEditing(false)} disabled={saving}>\n {t('ui.detail.inline.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n onClick={handleMarkdownToggle}\n aria-pressed={isMarkdownEnabled}\n title={\n isMarkdownEnabled\n ? t('ui.detail.inline.markdownDisable', 'Disable Markdown')\n : t('ui.detail.inline.markdownEnable', 'Enable Markdown')\n }\n aria-label={\n isMarkdownEnabled\n ? t('ui.detail.inline.markdownDisable', 'Disable Markdown')\n : t('ui.detail.inline.markdownEnable', 'Enable Markdown')\n }\n className={cn('h-8 w-8', isMarkdownEnabled ? 'text-primary' : undefined)}\n disabled={saving}\n >\n <FileCode className=\"h-4 w-4\" aria-hidden />\n <span className=\"sr-only\">\n {isMarkdownEnabled\n ? t('ui.detail.inline.markdownDisable', 'Disable Markdown')\n : t('ui.detail.inline.markdownEnable', 'Enable Markdown')}\n </span>\n </Button>\n </div>\n </form>\n ) : (\n <div\n className={cn(\n 'mt-1 text-sm break-words',\n renderDisplay ? null : 'whitespace-pre-wrap',\n activateOnClick && !editing ? 'cursor-pointer' : null,\n )}\n >\n {renderDisplay ? (\n renderDisplay({ value, emptyLabel })\n ) : value && value.length ? (\n <MarkdownPreview\n remarkPlugins={markdownPlugins}\n className=\"prose prose-sm max-w-none text-foreground [&>*]:my-2 [&>*:last-child]:mb-0 [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-3 [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5\"\n >\n {value}\n </MarkdownPreview>\n ) : (\n <span className=\"text-muted-foreground\">{emptyLabel}</span>\n )}\n </div>\n )}\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className={triggerClasses}\n onClick={(event) => {\n event.stopPropagation()\n setEditing((state) => !state)\n }}\n >\n {editing ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n </Button>\n </div>\n </div>\n )\n}\n\nexport type InlineSelectOption = { value: string; label: string; description?: string }\n\nexport type InlineSelectEditorProps = {\n label: string\n value: string | null | undefined\n emptyLabel: string\n options: InlineSelectOption[]\n onSave: (value: string | null) => Promise<void>\n variant?: EditorVariant\n activateOnClick?: boolean\n containerClassName?: string\n triggerClassName?: string\n hideLabel?: boolean\n renderEditor?: (params: { value: string; onChange: (next: string) => void }) => React.ReactNode\n renderDisplay?: (params: { value: string | null | undefined; emptyLabel: string }) => React.ReactNode\n}\n\nexport function InlineSelectEditor({\n label,\n value,\n emptyLabel,\n options,\n onSave,\n variant = 'default',\n activateOnClick = false,\n containerClassName,\n triggerClassName,\n hideLabel = false,\n renderEditor,\n renderDisplay,\n}: InlineSelectEditorProps) {\n const t = useT()\n const [editing, setEditing] = React.useState(false)\n const [draft, setDraft] = React.useState<string>(value ?? '')\n const [saving, setSaving] = React.useState(false)\n\n React.useEffect(() => {\n if (!editing) setDraft(value ?? '')\n }, [editing, value])\n\n const containerClasses = cn(\n 'group',\n variant === 'muted'\n ? 'relative rounded border bg-muted/30 p-3'\n : variant === 'plain'\n ? 'relative flex flex-col gap-1 rounded-none border-0 p-0'\n : 'rounded-lg border bg-card p-4',\n activateOnClick && !editing ? 'cursor-pointer' : null,\n containerClassName ?? null,\n )\n const triggerClasses = cn(\n 'shrink-0 transition-opacity duration-150',\n editing\n ? 'opacity-100'\n : 'opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100',\n variant === 'muted' ? 'h-8 w-8' : null,\n triggerClassName ?? null,\n )\n\n const handleSave = React.useCallback(async () => {\n setSaving(true)\n try {\n await onSave(draft.length ? draft : null)\n setEditing(false)\n } catch (err) {\n const message = err instanceof Error ? err.message : t('ui.detail.inline.error', 'Failed to save value.')\n console.error(message, err)\n } finally {\n setSaving(false)\n }\n }, [draft, onSave, t])\n\n const selected = options.find((option) => option.value === value)\n\n const interactiveProps: React.HTMLAttributes<HTMLDivElement> =\n activateOnClick && !editing\n ? {\n role: 'button' as const,\n tabIndex: 0,\n onClick: () => setEditing(true),\n onKeyDown: (event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n setEditing(true)\n }\n },\n }\n : {}\n\n return (\n <div className={containerClasses}>\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\" {...interactiveProps}>\n {hideLabel ? null : <p className=\"text-xs uppercase tracking-wide text-muted-foreground\">{label}</p>}\n {editing ? (\n <div className={variant === 'plain' ? 'space-y-2 pt-1' : 'mt-2 space-y-2'}>\n {renderEditor ? (\n renderEditor({ value: draft, onChange: setDraft })\n ) : (\n <Select\n value={draft || undefined}\n onValueChange={(next) => setDraft(next ?? '')}\n >\n <SelectTrigger>\n <SelectValue placeholder={t('ui.detail.inline.select.placeholder', 'Not set')} />\n </SelectTrigger>\n <SelectContent>\n {options.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n {option.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n )}\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" size=\"sm\" onClick={() => void handleSave()} disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-3.5 w-3.5 animate-spin\" /> : null}\n {t('ui.detail.inline.saveShortcut', 'Save \u2318\u23CE / Ctrl+Enter')}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" onClick={() => setEditing(false)} disabled={saving}>\n {t('ui.detail.inline.cancel', 'Cancel')}\n </Button>\n </div>\n </div>\n ) : (\n <div className={variant === 'plain' ? 'flex items-center gap-2' : 'mt-1 text-sm'}>\n {renderDisplay ? (\n renderDisplay({ value, emptyLabel })\n ) : selected ? (\n <div className=\"space-y-0.5\">\n <p className=\"font-medium leading-tight\">{selected.label}</p>\n {selected.description ? (\n <p className=\"text-xs text-muted-foreground\">{selected.description}</p>\n ) : null}\n </div>\n ) : (\n <span className=\"text-muted-foreground\">{emptyLabel}</span>\n )}\n </div>\n )}\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size={variant === 'plain' ? 'icon' : 'sm'}\n className={triggerClasses}\n onClick={(event) => {\n event.stopPropagation()\n setEditing((state) => !state)\n }}\n >\n {editing ? <X className=\"h-4 w-4\" /> : <Pencil className=\"h-4 w-4\" />}\n </Button>\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import dynamic from "next/dynamic";
|
|
4
|
+
const isTestEnv = typeof process !== "undefined" && (process.env.NODE_ENV === "test" || typeof process.env.JEST_WORKER_ID !== "undefined");
|
|
5
|
+
const MarkdownFieldTestStub = ({ value, onChange }) => /* @__PURE__ */ jsx(
|
|
6
|
+
"textarea",
|
|
7
|
+
{
|
|
8
|
+
"data-testid": "markdown-field",
|
|
9
|
+
className: "min-h-[160px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
|
|
10
|
+
value: value ?? "",
|
|
11
|
+
onChange: (event) => onChange(event.target.value)
|
|
12
|
+
}
|
|
13
|
+
);
|
|
14
|
+
const MarkdownFieldLive = dynamic(() => import("./MdxEditorImpl.js"), { ssr: false });
|
|
15
|
+
const MarkdownField = isTestEnv ? MarkdownFieldTestStub : MarkdownFieldLive;
|
|
16
|
+
var MarkdownField_default = MarkdownField;
|
|
17
|
+
export {
|
|
18
|
+
MarkdownField_default as default
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=MarkdownField.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/backend/inputs/MarkdownField.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport dynamic from 'next/dynamic'\nimport type { ComponentType } from 'react'\n\nexport type MarkdownFieldProps = {\n value?: string\n onChange: (markdown: string) => void\n}\n\nconst isTestEnv =\n typeof process !== 'undefined' &&\n (process.env.NODE_ENV === 'test' || typeof process.env.JEST_WORKER_ID !== 'undefined')\n\n// Lightweight stand-in for unit tests (jsdom): MDXEditor/Lexical pull in ESM + CSS that jest\n// would have to transform, so under test we render a plain controlled textarea instead.\nconst MarkdownFieldTestStub: ComponentType<MarkdownFieldProps> = ({ value, onChange }) => (\n <textarea\n data-testid=\"markdown-field\"\n className=\"min-h-[160px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm\"\n value={value ?? ''}\n onChange={(event) => onChange(event.target.value)}\n />\n)\n\nconst MarkdownFieldLive = dynamic(() => import('./MdxEditorImpl'), { ssr: false }) as ComponentType<MarkdownFieldProps>\n\n// Canonical Markdown editor for the whole app: a WYSIWYG MDXEditor (Lexical) that emits Markdown.\n// Client-only (Lexical needs the DOM), loaded via next/dynamic with ssr disabled. Use this\n// everywhere a Markdown editing field is needed.\nconst MarkdownField: ComponentType<MarkdownFieldProps> = isTestEnv ? MarkdownFieldTestStub : MarkdownFieldLive\n\nexport default MarkdownField\n"],
|
|
5
|
+
"mappings": ";AAkBE;AAfF,OAAO,aAAa;AAQpB,MAAM,YACJ,OAAO,YAAY,gBAClB,QAAQ,IAAI,aAAa,UAAU,OAAO,QAAQ,IAAI,mBAAmB;AAI5E,MAAM,wBAA2D,CAAC,EAAE,OAAO,SAAS,MAClF;AAAA,EAAC;AAAA;AAAA,IACC,eAAY;AAAA,IACZ,WAAU;AAAA,IACV,OAAO,SAAS;AAAA,IAChB,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA;AAClD;AAGF,MAAM,oBAAoB,QAAQ,MAAM,OAAO,iBAAiB,GAAG,EAAE,KAAK,MAAM,CAAC;AAKjF,MAAM,gBAAmD,YAAY,wBAAwB;AAE7F,IAAO,wBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import {
|
|
5
|
+
MDXEditor,
|
|
6
|
+
headingsPlugin,
|
|
7
|
+
listsPlugin,
|
|
8
|
+
quotePlugin,
|
|
9
|
+
thematicBreakPlugin,
|
|
10
|
+
linkPlugin,
|
|
11
|
+
linkDialogPlugin,
|
|
12
|
+
imagePlugin,
|
|
13
|
+
tablePlugin,
|
|
14
|
+
markdownShortcutPlugin,
|
|
15
|
+
diffSourcePlugin,
|
|
16
|
+
toolbarPlugin,
|
|
17
|
+
UndoRedo,
|
|
18
|
+
BoldItalicUnderlineToggles,
|
|
19
|
+
CodeToggle,
|
|
20
|
+
StrikeThroughSupSubToggles,
|
|
21
|
+
ListsToggle,
|
|
22
|
+
BlockTypeSelect,
|
|
23
|
+
CreateLink,
|
|
24
|
+
InsertImage,
|
|
25
|
+
InsertTable,
|
|
26
|
+
InsertThematicBreak,
|
|
27
|
+
Separator,
|
|
28
|
+
DiffSourceToggleWrapper
|
|
29
|
+
} from "@mdxeditor/editor";
|
|
30
|
+
import "@mdxeditor/editor/style.css";
|
|
31
|
+
import { cn } from "@open-mercato/shared/lib/utils";
|
|
32
|
+
import { useTheme } from "../../theme/index.js";
|
|
33
|
+
function MdxEditorImpl({ value = "", onChange }) {
|
|
34
|
+
const editorRef = React.useRef(null);
|
|
35
|
+
const latestRef = React.useRef(value);
|
|
36
|
+
const typingRef = React.useRef(false);
|
|
37
|
+
const { resolvedTheme } = useTheme();
|
|
38
|
+
React.useEffect(() => {
|
|
39
|
+
if (typingRef.current) return;
|
|
40
|
+
if (value !== latestRef.current) {
|
|
41
|
+
latestRef.current = value;
|
|
42
|
+
editorRef.current?.setMarkdown(value ?? "");
|
|
43
|
+
}
|
|
44
|
+
}, [value]);
|
|
45
|
+
const commit = React.useCallback(() => {
|
|
46
|
+
if (!typingRef.current) return;
|
|
47
|
+
typingRef.current = false;
|
|
48
|
+
onChange(latestRef.current);
|
|
49
|
+
}, [onChange]);
|
|
50
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full overflow-hidden rounded-md border border-input bg-background", onBlur: commit, children: /* @__PURE__ */ jsx(
|
|
51
|
+
MDXEditor,
|
|
52
|
+
{
|
|
53
|
+
ref: editorRef,
|
|
54
|
+
markdown: value ?? "",
|
|
55
|
+
onChange: (markdown) => {
|
|
56
|
+
typingRef.current = true;
|
|
57
|
+
latestRef.current = markdown;
|
|
58
|
+
},
|
|
59
|
+
className: cn("om-mdx-editor", resolvedTheme === "dark" && "dark-theme"),
|
|
60
|
+
contentEditableClassName: "om-mdx-prose",
|
|
61
|
+
plugins: [
|
|
62
|
+
headingsPlugin(),
|
|
63
|
+
listsPlugin(),
|
|
64
|
+
quotePlugin(),
|
|
65
|
+
thematicBreakPlugin(),
|
|
66
|
+
linkPlugin(),
|
|
67
|
+
linkDialogPlugin(),
|
|
68
|
+
imagePlugin(),
|
|
69
|
+
tablePlugin(),
|
|
70
|
+
markdownShortcutPlugin(),
|
|
71
|
+
diffSourcePlugin({ viewMode: "rich-text" }),
|
|
72
|
+
toolbarPlugin({
|
|
73
|
+
toolbarContents: () => /* @__PURE__ */ jsxs(DiffSourceToggleWrapper, { children: [
|
|
74
|
+
/* @__PURE__ */ jsx(UndoRedo, {}),
|
|
75
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
76
|
+
/* @__PURE__ */ jsx(BoldItalicUnderlineToggles, {}),
|
|
77
|
+
/* @__PURE__ */ jsx(CodeToggle, {}),
|
|
78
|
+
/* @__PURE__ */ jsx(StrikeThroughSupSubToggles, {}),
|
|
79
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
80
|
+
/* @__PURE__ */ jsx(ListsToggle, {}),
|
|
81
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
82
|
+
/* @__PURE__ */ jsx(BlockTypeSelect, {}),
|
|
83
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
84
|
+
/* @__PURE__ */ jsx(CreateLink, {}),
|
|
85
|
+
/* @__PURE__ */ jsx(InsertImage, {}),
|
|
86
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
87
|
+
/* @__PURE__ */ jsx(InsertTable, {}),
|
|
88
|
+
/* @__PURE__ */ jsx(InsertThematicBreak, {})
|
|
89
|
+
] })
|
|
90
|
+
})
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
) });
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
MdxEditorImpl as default
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=MdxEditorImpl.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/backend/inputs/MdxEditorImpl.tsx"],
|
|
4
|
+
"sourcesContent": ["/// <reference path=\"../../types/css.d.ts\" />\n\"use client\"\n\nimport * as React from 'react'\nimport {\n MDXEditor,\n type MDXEditorMethods,\n headingsPlugin,\n listsPlugin,\n quotePlugin,\n thematicBreakPlugin,\n linkPlugin,\n linkDialogPlugin,\n imagePlugin,\n tablePlugin,\n markdownShortcutPlugin,\n diffSourcePlugin,\n toolbarPlugin,\n UndoRedo,\n BoldItalicUnderlineToggles,\n CodeToggle,\n StrikeThroughSupSubToggles,\n ListsToggle,\n BlockTypeSelect,\n CreateLink,\n InsertImage,\n InsertTable,\n InsertThematicBreak,\n Separator,\n DiffSourceToggleWrapper,\n} from '@mdxeditor/editor'\nimport '@mdxeditor/editor/style.css'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useTheme } from '../../theme'\n\ntype MdxEditorImplProps = {\n value?: string\n onChange: (markdown: string) => void\n}\n\n// WYSIWYG Markdown editor (MDXEditor / Lexical) wired to the CrudForm value/onChange\n// contract. Markdown is the source of truth. Edits are buffered locally and committed\n// on blur to avoid re-rendering the whole form on every keystroke.\nexport default function MdxEditorImpl({ value = '', onChange }: MdxEditorImplProps) {\n const editorRef = React.useRef<MDXEditorMethods>(null)\n const latestRef = React.useRef<string>(value)\n const typingRef = React.useRef(false)\n const { resolvedTheme } = useTheme()\n\n // External value changes (form reset / async initial load) are pushed into the editor,\n // but never while the user is actively typing (would reset the caret).\n React.useEffect(() => {\n if (typingRef.current) return\n if (value !== latestRef.current) {\n latestRef.current = value\n editorRef.current?.setMarkdown(value ?? '')\n }\n }, [value])\n\n const commit = React.useCallback(() => {\n if (!typingRef.current) return\n typingRef.current = false\n onChange(latestRef.current)\n }, [onChange])\n\n return (\n <div className=\"w-full overflow-hidden rounded-md border border-input bg-background\" onBlur={commit}>\n <MDXEditor\n ref={editorRef}\n markdown={value ?? ''}\n onChange={(markdown) => {\n typingRef.current = true\n latestRef.current = markdown\n }}\n className={cn('om-mdx-editor', resolvedTheme === 'dark' && 'dark-theme')}\n contentEditableClassName=\"om-mdx-prose\"\n plugins={[\n headingsPlugin(),\n listsPlugin(),\n quotePlugin(),\n thematicBreakPlugin(),\n linkPlugin(),\n linkDialogPlugin(),\n imagePlugin(),\n tablePlugin(),\n markdownShortcutPlugin(),\n diffSourcePlugin({ viewMode: 'rich-text' }),\n toolbarPlugin({\n toolbarContents: () => (\n <DiffSourceToggleWrapper>\n <UndoRedo />\n <Separator />\n <BoldItalicUnderlineToggles />\n <CodeToggle />\n <StrikeThroughSupSubToggles />\n <Separator />\n <ListsToggle />\n <Separator />\n <BlockTypeSelect />\n <Separator />\n <CreateLink />\n <InsertImage />\n <Separator />\n <InsertTable />\n <InsertThematicBreak />\n </DiffSourceToggleWrapper>\n ),\n }),\n ]}\n />\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAyFc,SACE,KADF;AAtFd,YAAY,WAAW;AACvB;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,OAAO;AACP,SAAS,UAAU;AACnB,SAAS,gBAAgB;AAUV,SAAR,cAA+B,EAAE,QAAQ,IAAI,SAAS,GAAuB;AAClF,QAAM,YAAY,MAAM,OAAyB,IAAI;AACrD,QAAM,YAAY,MAAM,OAAe,KAAK;AAC5C,QAAM,YAAY,MAAM,OAAO,KAAK;AACpC,QAAM,EAAE,cAAc,IAAI,SAAS;AAInC,QAAM,UAAU,MAAM;AACpB,QAAI,UAAU,QAAS;AACvB,QAAI,UAAU,UAAU,SAAS;AAC/B,gBAAU,UAAU;AACpB,gBAAU,SAAS,YAAY,SAAS,EAAE;AAAA,IAC5C;AAAA,EACF,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,SAAS,MAAM,YAAY,MAAM;AACrC,QAAI,CAAC,UAAU,QAAS;AACxB,cAAU,UAAU;AACpB,aAAS,UAAU,OAAO;AAAA,EAC5B,GAAG,CAAC,QAAQ,CAAC;AAEb,SACE,oBAAC,SAAI,WAAU,uEAAsE,QAAQ,QAC3F;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,UAAU,SAAS;AAAA,MACnB,UAAU,CAAC,aAAa;AACtB,kBAAU,UAAU;AACpB,kBAAU,UAAU;AAAA,MACtB;AAAA,MACA,WAAW,GAAG,iBAAiB,kBAAkB,UAAU,YAAY;AAAA,MACvE,0BAAyB;AAAA,MACzB,SAAS;AAAA,QACP,eAAe;AAAA,QACf,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,oBAAoB;AAAA,QACpB,WAAW;AAAA,QACX,iBAAiB;AAAA,QACjB,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,uBAAuB;AAAA,QACvB,iBAAiB,EAAE,UAAU,YAAY,CAAC;AAAA,QAC1C,cAAc;AAAA,UACZ,iBAAiB,MACf,qBAAC,2BACC;AAAA,gCAAC,YAAS;AAAA,YACV,oBAAC,aAAU;AAAA,YACX,oBAAC,8BAA2B;AAAA,YAC5B,oBAAC,cAAW;AAAA,YACZ,oBAAC,8BAA2B;AAAA,YAC5B,oBAAC,aAAU;AAAA,YACX,oBAAC,eAAY;AAAA,YACb,oBAAC,aAAU;AAAA,YACX,oBAAC,mBAAgB;AAAA,YACjB,oBAAC,aAAU;AAAA,YACX,oBAAC,cAAW;AAAA,YACZ,oBAAC,eAAY;AAAA,YACb,oBAAC,aAAU;AAAA,YACX,oBAAC,eAAY;AAAA,YACb,oBAAC,uBAAoB;AAAA,aACvB;AAAA,QAEJ,CAAC;AAAA,MACH;AAAA;AAAA,EACF,GACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,59 +1,27 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
-
import
|
|
4
|
-
import { LoadingMessage } from "../detail/LoadingMessage.js";
|
|
5
|
-
import { useMarkdownRemarkPlugins } from "../markdown/useMarkdownRemarkPlugins.js";
|
|
6
|
-
import { useTheme } from "../../theme/index.js";
|
|
7
|
-
const isTestEnv = typeof process !== "undefined" && (process.env.NODE_ENV === "test" || typeof process.env.JEST_WORKER_ID !== "undefined");
|
|
8
|
-
const MarkdownEditorTestStub = ({ value, onChange }) => /* @__PURE__ */ jsx(
|
|
9
|
-
"textarea",
|
|
10
|
-
{
|
|
11
|
-
className: "min-h-[160px] w-full rounded border px-3 py-2 text-sm",
|
|
12
|
-
value: value ?? "",
|
|
13
|
-
onChange: (event) => onChange?.(event.target.value)
|
|
14
|
-
}
|
|
15
|
-
);
|
|
16
|
-
const UiMarkdownEditor = isTestEnv ? MarkdownEditorTestStub : dynamic(() => import("@uiw/react-md-editor"), {
|
|
17
|
-
ssr: false,
|
|
18
|
-
loading: () => /* @__PURE__ */ jsx(
|
|
19
|
-
LoadingMessage,
|
|
20
|
-
{
|
|
21
|
-
label: "Loading editor...",
|
|
22
|
-
className: "min-h-[220px] justify-center"
|
|
23
|
-
}
|
|
24
|
-
)
|
|
25
|
-
});
|
|
3
|
+
import MarkdownField from "./MarkdownField.js";
|
|
26
4
|
function SwitchableMarkdownInput({
|
|
27
5
|
value,
|
|
28
6
|
onChange,
|
|
29
7
|
isMarkdownEnabled,
|
|
30
8
|
disableMarkdown,
|
|
31
|
-
height = 220,
|
|
32
9
|
placeholder,
|
|
33
10
|
rows = 3,
|
|
34
11
|
textareaRef,
|
|
35
12
|
onTextareaInput,
|
|
36
13
|
textareaClassName,
|
|
37
|
-
|
|
38
|
-
editorClassName,
|
|
39
|
-
disabled,
|
|
40
|
-
remarkPlugins
|
|
14
|
+
disabled
|
|
41
15
|
}) {
|
|
42
|
-
const resolvedPlugins = useMarkdownRemarkPlugins(remarkPlugins);
|
|
43
|
-
const { resolvedTheme } = useTheme();
|
|
44
|
-
const editorWrapperClasses = editorWrapperClassName ?? "w-full rounded-lg border border-muted-foreground/20 bg-background p-2";
|
|
45
|
-
const editorClasses = editorClassName ?? "w-full";
|
|
46
16
|
const textareaClasses = textareaClassName ?? "w-full resize-none overflow-hidden rounded-lg border border-muted-foreground/20 bg-background px-3 py-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
|
|
47
17
|
if (isMarkdownEnabled && !disableMarkdown) {
|
|
48
|
-
return /* @__PURE__ */ jsx(
|
|
49
|
-
|
|
18
|
+
return /* @__PURE__ */ jsx(
|
|
19
|
+
MarkdownField,
|
|
50
20
|
{
|
|
51
21
|
value,
|
|
52
|
-
|
|
53
|
-
onChange: (nextValue) => onChange(typeof nextValue === "string" ? nextValue : ""),
|
|
54
|
-
previewOptions: resolvedPlugins.length ? { remarkPlugins: resolvedPlugins } : void 0
|
|
22
|
+
onChange: (nextValue) => onChange(typeof nextValue === "string" ? nextValue : "")
|
|
55
23
|
}
|
|
56
|
-
)
|
|
24
|
+
);
|
|
57
25
|
}
|
|
58
26
|
return /* @__PURE__ */ jsx(
|
|
59
27
|
"textarea",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/inputs/SwitchableMarkdownInput.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * @deprecated Prefer the DS `RichEditor` primitive from\n * `@open-mercato/ui/primitives/rich-editor` for any new rich-text input.\n *\n * `RichEditor` produces sanitized HTML (with the DS toolbar, color palette,\n * Figma-aligned styling, and auto-overflow toolbar variants). The DS direction\n * is to consolidate on a single rich-text format (HTML) so that user-authored\n * content renders consistently across email, exports, and the customer portal.\n *\n * `SwitchableMarkdownInput` is kept as a backward-compatibility shim for\n * existing Markdown-backed surfaces (notably `customers` Notes). It will be\n * removed once those surfaces migrate their storage format from Markdown to\n * sanitized HTML \u2014 track the migration in the spec referenced from\n * `customers/AGENTS.md`.\n *\n * Migration:\n *\n * ```diff\n * - import { SwitchableMarkdownInput } from '@open-mercato/ui/backend/inputs/SwitchableMarkdownInput'\n * - <SwitchableMarkdownInput value={md} onChange={setMd} isMarkdownEnabled={enabled} />\n * + import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'\n * + <RichEditor value={html} onChange={setHtml} variant=\"basic\" />\n * ```\n *\n * For surfaces that genuinely need plain Markdown storage (e.g. agent prompts,\n * code-adjacent docs), keep using `SwitchableMarkdownInput` until a Markdown\n * mode lands on `RichEditor` \u2014 but do NOT introduce new Markdown surfaces.\n */\n\"use client\"\n\nimport * as React from 'react'\nimport
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["/**\n * @deprecated Prefer the DS `RichEditor` primitive from\n * `@open-mercato/ui/primitives/rich-editor` for any new rich-text input.\n *\n * `RichEditor` produces sanitized HTML (with the DS toolbar, color palette,\n * Figma-aligned styling, and auto-overflow toolbar variants). The DS direction\n * is to consolidate on a single rich-text format (HTML) so that user-authored\n * content renders consistently across email, exports, and the customer portal.\n *\n * `SwitchableMarkdownInput` is kept as a backward-compatibility shim for\n * existing Markdown-backed surfaces (notably `customers` Notes). It will be\n * removed once those surfaces migrate their storage format from Markdown to\n * sanitized HTML \u2014 track the migration in the spec referenced from\n * `customers/AGENTS.md`.\n *\n * Migration:\n *\n * ```diff\n * - import { SwitchableMarkdownInput } from '@open-mercato/ui/backend/inputs/SwitchableMarkdownInput'\n * - <SwitchableMarkdownInput value={md} onChange={setMd} isMarkdownEnabled={enabled} />\n * + import { RichEditor } from '@open-mercato/ui/primitives/rich-editor'\n * + <RichEditor value={html} onChange={setHtml} variant=\"basic\" />\n * ```\n *\n * For surfaces that genuinely need plain Markdown storage (e.g. agent prompts,\n * code-adjacent docs), keep using `SwitchableMarkdownInput` until a Markdown\n * mode lands on `RichEditor` \u2014 but do NOT introduce new Markdown surfaces.\n */\n\"use client\"\n\nimport * as React from 'react'\nimport type { PluggableList } from 'unified'\nimport MarkdownField from './MarkdownField'\n\n/** @deprecated See module-level JSDoc. */\nexport type SwitchableMarkdownInputProps = {\n value: string\n onChange: (value: string) => void\n isMarkdownEnabled: boolean\n disableMarkdown?: boolean\n height?: number\n placeholder?: string\n rows?: number\n textareaRef?: React.Ref<HTMLTextAreaElement>\n onTextareaInput?: React.FormEventHandler<HTMLTextAreaElement>\n textareaClassName?: string\n editorWrapperClassName?: string\n editorClassName?: string\n disabled?: boolean\n remarkPlugins?: PluggableList\n}\n\n/** @deprecated Use `RichEditor` from `@open-mercato/ui/primitives/rich-editor` for new code. See module JSDoc. */\nexport function SwitchableMarkdownInput({\n value,\n onChange,\n isMarkdownEnabled,\n disableMarkdown,\n placeholder,\n rows = 3,\n textareaRef,\n onTextareaInput,\n textareaClassName,\n disabled,\n}: SwitchableMarkdownInputProps) {\n const textareaClasses =\n textareaClassName\n ?? 'w-full resize-none overflow-hidden rounded-lg border border-muted-foreground/20 bg-background px-3 py-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring'\n\n if (isMarkdownEnabled && !disableMarkdown) {\n return (\n <MarkdownField\n value={value}\n onChange={(nextValue) => onChange(typeof nextValue === 'string' ? nextValue : '')}\n />\n )\n }\n\n return (\n <textarea\n ref={textareaRef}\n rows={rows}\n className={textareaClasses}\n placeholder={placeholder}\n value={value}\n onChange={(event) => onChange(event.target.value)}\n onInput={onTextareaInput}\n disabled={disabled}\n />\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAuEM;AAvCN,OAAO,mBAAmB;AAqBnB,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,kBACJ,qBACG;AAEL,MAAI,qBAAqB,CAAC,iBAAiB;AACzC,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,UAAU,CAAC,cAAc,SAAS,OAAO,cAAc,WAAW,YAAY,EAAE;AAAA;AAAA,IAClF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,MAChD,SAAS;AAAA,MACT;AAAA;AAAA,EACF;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|