@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.
Files changed (38) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/backend/CrudForm.js +7 -57
  3. package/dist/backend/CrudForm.js.map +3 -3
  4. package/dist/backend/detail/InlineEditors.js +2 -51
  5. package/dist/backend/detail/InlineEditors.js.map +3 -3
  6. package/dist/backend/inputs/MarkdownField.js +20 -0
  7. package/dist/backend/inputs/MarkdownField.js.map +7 -0
  8. package/dist/backend/inputs/MdxEditorImpl.js +98 -0
  9. package/dist/backend/inputs/MdxEditorImpl.js.map +7 -0
  10. package/dist/backend/inputs/SwitchableMarkdownInput.js +6 -38
  11. package/dist/backend/inputs/SwitchableMarkdownInput.js.map +2 -2
  12. package/dist/backend/markdown/markdownToPlainText.js +29 -0
  13. package/dist/backend/markdown/markdownToPlainText.js.map +2 -2
  14. package/dist/types/css.d.js +1 -0
  15. package/dist/types/css.d.js.map +7 -0
  16. package/package.json +4 -3
  17. package/src/backend/CrudForm.tsx +3 -67
  18. package/src/backend/__tests__/CrudForm.custom-fields.test.tsx +0 -1
  19. package/src/backend/__tests__/CrudForm.datetime.test.tsx +0 -1
  20. package/src/backend/__tests__/CrudForm.defaults.test.tsx +0 -1
  21. package/src/backend/__tests__/CrudForm.dotPath.test.tsx +0 -1
  22. package/src/backend/__tests__/CrudForm.doubleSubmit.test.tsx +0 -1
  23. package/src/backend/__tests__/CrudForm.navigation.test.tsx +0 -1
  24. package/src/backend/__tests__/CrudForm.optimisticLock.test.tsx +0 -1
  25. package/src/backend/__tests__/CrudForm.render.test.tsx +0 -1
  26. package/src/backend/__tests__/CrudForm.sortable.test.tsx +0 -1
  27. package/src/backend/__tests__/CrudForm.transformData.test.tsx +0 -1
  28. package/src/backend/__tests__/CrudForm.unsavedNavigation.test.tsx +0 -1
  29. package/src/backend/__tests__/CrudForm.validation.test.tsx +0 -1
  30. package/src/backend/__tests__/CustomDataSection.test.tsx +0 -1
  31. package/src/backend/__tests__/lazy-heavy-libraries.test.ts +16 -3
  32. package/src/backend/detail/InlineEditors.tsx +14 -76
  33. package/src/backend/inputs/MarkdownField.tsx +34 -0
  34. package/src/backend/inputs/MdxEditorImpl.tsx +113 -0
  35. package/src/backend/inputs/SwitchableMarkdownInput.tsx +5 -54
  36. package/src/backend/markdown/__tests__/markdownToPlainText.test.ts +13 -0
  37. package/src/backend/markdown/markdownToPlainText.ts +41 -0
  38. 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
- isMarkdownEnabled ? /* @__PURE__ */ jsx(
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": ["element"]
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 dynamic from "next/dynamic";
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
- editorWrapperClassName,
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("div", { className: editorWrapperClasses, children: /* @__PURE__ */ jsx("div", { "data-color-mode": resolvedTheme, className: editorClasses, children: /* @__PURE__ */ jsx(
49
- UiMarkdownEditor,
18
+ return /* @__PURE__ */ jsx(
19
+ MarkdownField,
50
20
  {
51
21
  value,
52
- height,
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 dynamic from 'next/dynamic'\nimport type { PluggableList } from 'unified'\nimport { LoadingMessage } from '../detail/LoadingMessage'\nimport { useMarkdownRemarkPlugins } from '../markdown/useMarkdownRemarkPlugins'\nimport { useTheme } from '../../theme'\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\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\nconst MarkdownEditorTestStub: React.ComponentType<UiMarkdownEditorProps> = ({ value, onChange }) => (\n <textarea\n className=\"min-h-[160px] w-full rounded border px-3 py-2 text-sm\"\n value={value ?? ''}\n onChange={(event) => onChange?.(event.target.value)}\n />\n)\n\nconst UiMarkdownEditor = isTestEnv\n ? MarkdownEditorTestStub\n : (dynamic(() => import('@uiw/react-md-editor'), {\n ssr: false,\n loading: () => (\n <LoadingMessage\n label=\"Loading editor...\"\n className=\"min-h-[220px] justify-center\"\n />\n ),\n }) as unknown as React.ComponentType<UiMarkdownEditorProps>)\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 height = 220,\n placeholder,\n rows = 3,\n textareaRef,\n onTextareaInput,\n textareaClassName,\n editorWrapperClassName,\n editorClassName,\n disabled,\n remarkPlugins,\n}: SwitchableMarkdownInputProps) {\n const resolvedPlugins = useMarkdownRemarkPlugins(remarkPlugins)\n const { resolvedTheme } = useTheme()\n const editorWrapperClasses =\n editorWrapperClassName ?? 'w-full rounded-lg border border-muted-foreground/20 bg-background p-2'\n const editorClasses = editorClassName ?? 'w-full'\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 <div className={editorWrapperClasses}>\n <div data-color-mode={resolvedTheme} className={editorClasses}>\n <UiMarkdownEditor\n value={value}\n height={height}\n onChange={(nextValue) => onChange(typeof nextValue === 'string' ? nextValue : '')}\n previewOptions={resolvedPlugins.length ? { remarkPlugins: resolvedPlugins } : undefined}\n />\n </div>\n </div>\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": ";AAmEE;AApCF,OAAO,aAAa;AAEpB,SAAS,sBAAsB;AAC/B,SAAS,gCAAgC;AACzC,SAAS,gBAAgB;AA2BzB,MAAM,YACJ,OAAO,YAAY,gBAClB,QAAQ,IAAI,aAAa,UAAU,OAAO,QAAQ,IAAI,mBAAmB;AAE5E,MAAM,yBAAqE,CAAC,EAAE,OAAO,SAAS,MAC5F;AAAA,EAAC;AAAA;AAAA,IACC,WAAU;AAAA,IACV,OAAO,SAAS;AAAA,IAChB,UAAU,CAAC,UAAU,WAAW,MAAM,OAAO,KAAK;AAAA;AACpD;AAGF,MAAM,mBAAmB,YACrB,yBACC,QAAQ,MAAM,OAAO,sBAAsB,GAAG;AAAA,EAC7C,KAAK;AAAA,EACL,SAAS,MACP;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,WAAU;AAAA;AAAA,EACZ;AAEJ,CAAC;AAGE,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,kBAAkB,yBAAyB,aAAa;AAC9D,QAAM,EAAE,cAAc,IAAI,SAAS;AACnC,QAAM,uBACJ,0BAA0B;AAC5B,QAAM,gBAAgB,mBAAmB;AACzC,QAAM,kBACJ,qBACG;AAEL,MAAI,qBAAqB,CAAC,iBAAiB;AACzC,WACE,oBAAC,SAAI,WAAW,sBACd,8BAAC,SAAI,mBAAiB,eAAe,WAAW,eAC9C;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,UAAU,CAAC,cAAc,SAAS,OAAO,cAAc,WAAW,YAAY,EAAE;AAAA,QAChF,gBAAgB,gBAAgB,SAAS,EAAE,eAAe,gBAAgB,IAAI;AAAA;AAAA,IAChF,GACF,GACF;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;",
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
  }