Docyrus

EditableRecordDetail

IField-driven record editor — EditableValue rows with change tracking, conditional required / hidden, validation and a sticky save bar.

iOSAndroid
Preview EditableRecordDetail on your device

Scan with Expo Go

Download Expo Go, then scan the QR code to preview native components.

Installation

pnpm dlx @docyrus/cli add @docyrus/rn-editable-record-detail

Usage

import {
  EditableRecordDetail,
  EditableRecordDetailField,
  type RecordDetailField
} from '@/components/docyrus-native/editable-record-detail';

const fields: RecordDetailField[] = [
  { field: { id: 'title', slug: 'title', name: 'Title', type: 'field-text' }, required: true },
  { field: { id: 'status', slug: 'status', name: 'Status', type: 'field-status' }, enumOptions: statusOptions },
  {
    field: { id: 'reason', slug: 'reason', name: 'Lost reason', type: 'field-textarea' },
    hidden: values => values.status !== 'lost',
    required: values => values.status === 'lost'
  }
];

{/* Every field, in order */}
<EditableRecordDetail fields={fields} record={record} onSave={(changes, values) => api.update(values)} />

{/* Composed layout */}
<EditableRecordDetail fields={fields} record={record} onSave={save} fieldLayout="horizontal">
  <EditableRecordDetailField slug="title" />
  <EditableRecordDetailField slug="status" label="Stage" />
  <EditableRecordDetailField slug="reason" />
</EditableRecordDetail>

API Reference

EditableRecordDetailProps

PropTypeDefaultDescription
fieldsArray<RecordDetailField | LegacyRecordDetailField>—Field configs (required). Legacy { key, label, value, type } entries are converted automatically
recordRecord<string, unknown>—Current values keyed by slug (a record with different content resets the baseline)
onSave(changes: FieldChange[], values: Record<string, unknown>) => void | Promise<void>—Save handler; the baseline resets after it resolves
onCancel() => void—Pending changes discarded
readOnlybooleanfalseAll fields read-only
disabledbooleanfalseAll fields disabled
trackChangesbooleantrueHighlight changed rows
clientRestApiClient—Threaded into every field
childrenReactNode—EditableRecordDetailField composition; omitted → every field
isSavingbooleanfalseExternal saving flag
fieldLayout'vertical' | 'horizontal''vertical'Label above / beside the value
saveLabel / cancelLabelstringui.editableRecordDetail.save / ui.common.cancelAction bar labels
emptyValueTextstring'—'Empty text in renderEditor rows
scrollablebooleantrue without childrenWrap rows in a ScrollView
classNamestring—Additional classes

RecordDetailField

FieldTypeDescription
fieldIFieldField definition
enumOptionsEnumOption[]Options
readOnlybooleanRead-only row
requiredboolean | (values) => booleanRequired (conditional)
hiddenboolean | (values) => booleanHidden (conditional, re-evaluated on every change)
appSlug / dataSourceSlugstringDynamic enum context
renderValue(value) => ReactNodeNative escape hatch: custom display
renderEditor(value, onChange, onDone?) => ReactNodeNative escape hatch: custom inline editor

EditableRecordDetailFieldProps

EditableValueProps (minus the context-provided props) plus:

PropTypeDefaultDescription
slugstring—Field slug (required)
labelReactNodefield.nameLabel override
showLabelbooleantrueLabel + value row
layout'vertical' | 'horizontal'parent fieldLayoutRow layout override

FieldChange

FieldTypeDescription
fieldSlugstringSlug
fieldNamestringField name
originalValueunknownBaseline value
newValueunknownCurrent value
fieldKey / fieldLabelstringDeprecated legacy aliases

useEditableRecordDetail()

Returns EditableRecordDetailContextValue: values, changedFields, validationErrors, setFieldValue(slug, value), getChanges(), handleSave(), handleCancel(), plus the flags (readOnly, disabled, isSaving, trackChanges, fieldLayout).

Components

ComponentDescription
EditableRecordDetailProvider + rows + sticky action bar (pending-changes sheet, Cancel, Save)
EditableRecordDetailFieldEditableValue bound to the context

Type Exports

TypeDescription
EditableRecordDetailProps, EditableRecordDetailFieldPropsProps
RecordDetailField, LegacyRecordDetailFieldField configs
FieldChange, FieldLayoutChange + layout
EditableRecordDetailContextValueContext value

Breaking changes (web-parity release)

  • fields are RecordDetailField ({ field: IField, … }) with values in record; the legacy { key, label, value, type } shape is still accepted.
  • onSave(changes, values) — changes carry fieldSlug / fieldName (legacy fieldKey / fieldLabel kept as deprecated aliases).
  • Rows edit through EditableValue (field-aware) instead of plain text inputs.

On this page