Skip to content

FieldEditor

Shows a field value and turns it into the right editor for its data type.

Installing this pulls FieldValue, the eight typed editors and the three pickers with it.

Terminal window
pnpm dlx shadcn@latest add https://sg-widgets.vercel.app/r/react/field-editor.json
Terminal window
pnpm dlx shadcn-svelte@latest add https://sg-widgets.vercel.app/r/svelte/field-editor.json
FieldEditor: every data type, with a display and edit toggle

React

Loading the React demo…

Svelte

Loading the Svelte demo…

data type editor
text, entity_type, uuid TextEditor
number, float, percent, currency, duration, timecode NumberEditor
checkbox CheckboxEditor
date DateEditor
date_time DateTimeEditor
list ListPicker
url UrlEditor
color ColorEditor
status_list StatusPicker
entity EntityPicker
multi_entity EntityMultiPicker
image, calculated, summary, pivot_column, everything else none; display only

A field whose type has no editor stays on the display half whatever the mode says.

The last three read the API, so they need context. A status field also needs its schema’s entity_type and a link field its valid_types; without either the field stays on the display half. projectId scopes a status picker to the codes the project allows and an entity picker’s search to that project.

proptypedefaultmeaning
errorMessage(message: string) => ReactNode / Snippet<[string]>—Draws the line under the control.
valueunknownnullThe raw attribute value, as the API returned it. Two-way in Svelte.
onValueChange(value: unknown) => void—Called when the editor commits.
dataTypestringthe schema's, then 'text'Picks the editor.
fieldFieldSchema | nullnullThe field schema.
mode'display' | 'edit''display'Which half is showing. Two-way in Svelte, controlled in React.
onModeChange(mode) => void—Called when the toggle moves.
editablebooleanfalseTurns the display half into a control that opens the editor.
editorPlacement'inline' | 'popover''inline'Where the editor opens: in place of the value, or in a popover anchored to it.
statusesRecord<string, StatusRecord> | nullnullStatus rows by code, for the display half.
contextSgContext—The widget context: the site preferences, and what the display half reads.
hoursPerDaynumberthe context'sThe site's working day, for durations.
localestringthe context's, then the runtime'sPassed to the display half.
timeZonestringthe context's, then the runtime'sZone a typed wall-clock time is read in.
frameRatenumberthe context'sFrames a second, for timecodes.
precisionnumber—Decimals on a float.
symbolstring'$'Shown before a currency value.
projectIdnumber—Removes a list field's hidden values, and scopes a status or entity picker.
multilinebooleantrue in a popoverA textarea on a text field. In a textarea Enter adds a line and Cmd or Ctrl with Enter commits.
size'sm' | 'md' | 'lg''md'Control height.
disabledbooleanfalse
readonlybooleanfalse
invalidbooleanfalseForced invalid state.
errorstring | nullnullA message from the caller.
onErrorChange(error: string | null) => void—Called when the parse error appears or clears.
placeholderstring—
emptyLabelstring'empty'Marker the display half shows for an unset value.
class / classNamestring—Merged after the widget's own classes.

onValueChange fires when the editor commits. onModeChange fires on every toggle.

errorMessage receives the message and renders it, in whichever editor is showing.

keydoes
EnterOpens the editor from the display half; commits and closes it from the edit half.
SpaceOpens the editor from the display half.
EscapeCancels the edit and returns to the display half.
TabCommits and returns to the display half, unless focus stays inside a popup the editor opened.
a press outsideCommits and returns to the display half.
Escape, Enter in a popoverCancels and commits as they do in place; Save and Cancel do the same with the pointer.

Enter keeps the textarea of a multi-line text field open; leave it with Tab.

With editorPlacement="popover" the value stays where it is and the editor opens under it: the field’s name, the control, then Cancel and Save. The popover is w-72, or w-96 for a multi-entity field. Focus lands in the control and returns to the value when the popover closes.

On a field whose editor is a button over a popup — a date, a date-time, a list, a status — Enter opens the popup. On an entity field Enter chooses the highlighted row. Either way the value commits inside the popup and the edit half stays until the press or the focus move that leaves it.

The commit is on Enter or on the press that lands outside, never on the blur itself: the control is blurred first so what it holds is emitted, then the editor closes.

The write shapes each editor emits are the ones its own page documents. The dispatch itself follows the data types the corpus names, and the types with no editor here are the ones REST cannot write (field_types/calculated, summary, pivot_column).

A status value is the raw code, never the display label (field_types/status_list). An entity value is one {type, id} hash and a multi-entity value a list of them (field_types/entity).