PURPOSE
Controlled React editor for a list of UniformDecl entries used by the VFX/weapon-workbench shader component schema. Renders one row per uniform with a type dropdown and doc input, plus a draft row for adding a new uniform with name validation and duplicate-name guarding.
OWNS
- Local draft state via
useState:draftName(string),draftType(UniformKind, default'float'), anderror(string | null). - The
VALID_NAMEregex^[a-zA-Z_][a-zA-Z0-9_]{0,63}$enforcing C-style identifiers up to 64 chars. - The
UNIFORM_KINDSlist:'float','int','vec2','vec3','vec4','sampler2D'. - Three local mutators:
setUniform(patches one row by index),addUniform(validates then appends),deleteUniform(filters by name). - Inline styling for the uniforms block: dark panel rows on
#14141e, monospace name cells,#44ffccadd button,#442222delete button,#ff7777error text.
READS FROM
value: UniformDecl[]prop — the current uniform list rendered as rows.UniformDeclandUniformKindtype imports from@engine/vfx-workbench/component-schema.- Local
draftName,draftType,errorstate for the add-row UI.
PUSHES TO
onChange(next: UniformDecl[])prop — invoked fromsetUniform(patched copy),addUniform(appended entry with{ name, type, doc: '' }), anddeleteUniform(filtered copy).setDraftName('')after a successful add;setError(null)at the start of an add attempt andsetError('invalid name')/setError('name already exists')on validation failure.
DOES NOT
- Persist uniforms — has no store, file, or network access; lifts all changes through
onChange. - Edit uniform names after creation — the existing-row name cell is a read-only
<span>; renaming requires delete + re-add. - Validate uniform values, defaults, ranges, or shader compatibility — only the name regex and duplicate-name check.
- Provide reordering, drag-and-drop, or undo.
- Coerce
doccontent — accepts any string verbatim and writesdoc: ''for new entries. - Render a header label beyond the
UNIFORMScaption; no count, no help text.
Signals
data-testid="uniform-row-${name}"— one per existing uniform row.data-testid="uniform-type-${name}"— type<select>per row.data-testid="uniform-doc-${name}"— doc<input>per row.data-testid="delete-uniform-${name}"— row delete button.data-testid="new-uniform-name"— draft name input.data-testid="new-uniform-type"— draft type select.data-testid="add-uniform"— draft add button.data-testid="uniform-editor-error"— error message div, only rendered whenerroris non-null.
Entry points
- Default export: none. Named export
UniformSchemaEditor({ value, onChange }). - Props interface
Props { value: UniformDecl[]; onChange: (next: UniformDecl[]) => void }. - Consumed by parent weapon-workbench shader/component editor screens that own the persisted
UniformDecl[].
Pattern notes
- Pure controlled component: parent owns the array, child owns only the draft inputs and transient error.
- Validation happens at add-time only; existing rows assume the prop list is already well-formed.
- Duplicate-name check uses
value.some((u) => u.name === draftName)against current props, not against the draft history. - Type cast
e.target.value as UniformKindtrusts the<select>options to enumerate the fullUniformKindunion. - Row keying uses
u.namedirectly, which relies on names being unique — guaranteed by the add-time duplicate check. - Styling is inline and self-contained; there is no CSS module or theme hook.