Pop out dynamic form editor into dialog

This commit is contained in:
Gregory Schier
2025-07-11 08:33:04 -07:00
parent 791e5ad486
commit ad4e073f62
2 changed files with 82 additions and 18 deletions
+67 -4
View File
@@ -14,11 +14,14 @@ import classNames from 'classnames';
import { useAtomValue } from 'jotai'; import { useAtomValue } from 'jotai';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useActiveRequest } from '../hooks/useActiveRequest'; import { useActiveRequest } from '../hooks/useActiveRequest';
import { useRandomKey } from '../hooks/useRandomKey';
import { capitalize } from '../lib/capitalize'; import { capitalize } from '../lib/capitalize';
import { showDialog } from '../lib/dialog';
import { resolvedModelName } from '../lib/resolvedModelName'; import { resolvedModelName } from '../lib/resolvedModelName';
import { Banner } from './core/Banner'; import { Banner } from './core/Banner';
import { Checkbox } from './core/Checkbox'; import { Checkbox } from './core/Checkbox';
import { Editor } from './core/Editor/Editor'; import { Editor } from './core/Editor/Editor';
import { IconButton } from './core/IconButton';
import { Input } from './core/Input'; import { Input } from './core/Input';
import { Label } from './core/Label'; import { Label } from './core/Label';
import { Select } from './core/Select'; import { Select } from './core/Select';
@@ -271,7 +274,8 @@ function EditorArg({
// Read-only editor force refresh for every defaultValue change // Read-only editor force refresh for every defaultValue change
// Should this be built into the <Editor/> component? // Should this be built into the <Editor/> component?
const forceUpdateKey = arg.readOnly ? arg.defaultValue + stateKey : stateKey; const [popoutKey, regeneratePopoutKey] = useRandomKey();
const forceUpdateKey = popoutKey + (arg.readOnly ? arg.defaultValue + stateKey : stateKey);
return ( return (
<div className="w-full grid grid-cols-1 grid-rows-[auto_minmax(0,1fr)]"> <div className="w-full grid grid-cols-1 grid-rows-[auto_minmax(0,1fr)]">
@@ -284,13 +288,15 @@ function EditorArg({
> >
{arg.label} {arg.label}
</Label> </Label>
<Editor <div
id={id}
className={classNames( className={classNames(
'border border-border rounded-md overflow-hidden px-2 py-1', 'border border-border rounded-md overflow-hidden px-2 py-1',
'focus-within:border-border-focus', 'focus-within:border-border-focus',
'max-h-[15rem]', // So it doesn't take up too much space 'max-h-[10rem]', // So it doesn't take up too much space
)} )}
>
<Editor
id={id}
autocomplete={arg.completionOptions ? { options: arg.completionOptions } : undefined} autocomplete={arg.completionOptions ? { options: arg.completionOptions } : undefined}
disabled={arg.disabled} disabled={arg.disabled}
language={arg.language} language={arg.language}
@@ -302,9 +308,66 @@ function EditorArg({
autocompleteVariables={autocompleteVariables} autocompleteVariables={autocompleteVariables}
stateKey={stateKey} stateKey={stateKey}
forceUpdateKey={forceUpdateKey} forceUpdateKey={forceUpdateKey}
actions={
<div>
<IconButton
variant="border"
size="sm"
className="my-0.5 opacity-60 group-hover:opacity-100"
icon="expand"
title="Pop out to large editor"
onClick={() => {
showDialog({
id: 'id',
size: 'dynamic',
title: 'Edit Value',
description: (
<Label
htmlFor={id}
required={!arg.optional}
visuallyHidden={arg.hideLabel}
help={arg.description}
tags={arg.language ? [capitalize(arg.language)] : undefined}
>
{arg.label}
</Label>
),
onClose() {
// Force the main editor to update on close
regeneratePopoutKey();
},
render() {
return (
<div className="w-[100vw] max-w-[40rem] h-[calc(100vh-10rem)] max-h-[40rem]">
<Editor
id={id}
autocomplete={
arg.completionOptions ? { options: arg.completionOptions } : undefined
}
disabled={arg.disabled}
language={arg.language}
onChange={onChange}
defaultValue={
value === DYNAMIC_FORM_NULL_ARG ? arg.defaultValue : value
}
placeholder={arg.placeholder ?? undefined}
autocompleteFunctions={autocompleteFunctions}
autocompleteVariables={autocompleteVariables}
stateKey={stateKey}
forceUpdateKey={forceUpdateKey}
/>
</div>
);
},
});
}}
/>
</div>
}
hideGutter hideGutter
/> />
</div> </div>
</div>
); );
} }
+1
View File
@@ -45,6 +45,7 @@ const icons = {
download: lucide.DownloadIcon, download: lucide.DownloadIcon,
ellipsis: lucide.EllipsisIcon, ellipsis: lucide.EllipsisIcon,
external_link: lucide.ExternalLinkIcon, external_link: lucide.ExternalLinkIcon,
expand: lucide.ExpandIcon,
eye: lucide.EyeIcon, eye: lucide.EyeIcon,
eye_closed: lucide.EyeOffIcon, eye_closed: lucide.EyeOffIcon,
file_code: lucide.FileCodeIcon, file_code: lucide.FileCodeIcon,