Builtin Library
README.md
edui.inspector
The Inspector as an ordered list of sections. A subject — an asset, or a
component on an entity — gets generic sections, merged with the sections its
declarer's inspector.luau adds or replaces, in the order that file names.
local Inspector = require("@builtin::editor.edui.inspector")
local sections, ctx = Inspector.assetSections(ref, asset.inspect(ref))
local nodes = Inspector.render(sections, ctx) -- section cards
local nodes = Inspector.renderAsset(guid) -- the same, from an asset id
local sections, ctx = Inspector.componentSections(entityId, "Camera")
local nodes = Inspector.render(sections, ctx, { nested = true }) -- a component card's body
Sections
A section is { id, title, icon?, open?, build(ctx) -> { node } }. Its
title is a string or an i18n.text value, which the Inspector reads each
time it draws the section, so a title read from a catalog follows the
editor's language. The generic
asset sections, in default order, are identity, problems (present only
when asset.validate reports any), tags, move, settings, preview and
operations (see assetSections.module). A type declares its
own in the file its type.yaml names:
inspector: { type: "inspector.luau" }
That file returns { sections?, replace?, order? }: sections it adds (placed
before operations), generic sections it replaces by id, and the ids to put
first. material.assetType/inspector.luau is a worked example, and
@builtin::assetTypes.assetType.shared.inspector documents the declaration.
A component on an entity has one generic section, settings: its public
fields as typed controls over the live component, three-number colour and
vector aliases as one grouped control, each edit checked against the schema
and written as one undoable operation. A component that ships an
inspector.luau beside its init.luau (named by component.assetType's
inspector: { instance: "inspector.luau" }) adds, replaces and orders
sections of its card the same way; its sections read ctx.component and
ctx.selection.id. SceneModule.component/inspector.luau is a worked example.
A declaration that cannot be read, or that names a section that is not there,
shows its problem as a first inspector-problem section while every other
section still renders. Every build runs through
Inspector.buildSection(section, ctx) -> (rows, problem?): a build that raises,
or returns anything but a list, shows its error inside that section alone.
The Context
Every build(ctx) receives one Context, made by Inspector.valuesContext:
| Field | What it is |
|---|---|
ref | the inspected asset (on an entity, the component asset) |
info | asset.inspect(ref) |
schema | asset.schema(ref), settingsOf resolved |
schemaProblem | why a declared schema did not resolve |
settings | the current values |
setSettings(patch) | checks the patch with Field.checkSchema, then writes it as one undoable operation named for the field; answers (ok, violations) |
rejected | field path -> the message of its last rejected edit, for this subject only |
selection | { scope = "asset" | "entity", id, component?, name? }; on an entity, component is the component's identity and name the name the entity lists it by |
component | the live component proxy (entity scope) |
nameOf(id) | the name an entity-reference field shows for an entity id (entity scope) |
widgets | the edui framework table (field, schemaField, section, button, text, vbox, hbox, ...) |
keyPrefix | the callback-key namespace for this subject |
refresh() | rebuild the Inspector after a write that moves no revision |
actions | when set, the ids of the Settings actions offered ({ reset = true }); nil offers every action that applies |
parts | the building blocks a section composes: facts, lists, tables, asset and entity links, actions, a file opener, problems, swatches, a content-versioned cache, an lsp check and typed values (parts.module) |
Inspector.valuesContext{ subject, schema?, schemaProblem?, values?, write, ref?, keyPrefix?, info?, selection, component?, nameOf?, actions? } is the one way to make a Context: write(patch)
performs a patch already checked against the schema.
The rest of the API
Inspector.mergeSections(generic, decl, problem, file)— the merge and order.Inspector.componentSections(entityId, componentName)— a component card's sections and Context;Inspector.componentSettingsRows(ctx)is its genericsettingssection's body.Inspector.componentValuesSignature(entityId, componentName)— text that moves whenever one of the component's declared fields holds a different value (an edit, an undo, a script's write); a panel folds it into its build signature.Inspector.typeSections(ref)— the sectionsref's type declares, plus Settings when it has values; what the inline editor under an asset chip shows. No other generic section is built for it, so it runs no validation. Nil when the type declares notype:inspector.Inspector.render(sections, ctx, { nested = true })— titled groups inside a card, for the inline editor.Inspector.signature(assetId)— text that moves whenever what the asset view shows can have moved: the asset folder's content version (the change dispatcher moves it after a write inside the asset reaches its type's hook — an edit, an undo or redo, a peer's write) and the settings values file's. A panel folds it into its build signature;edui.widgets.openEditorsSignature()is the same for every open inline editor.Inspector.buildSection(section, ctx)— runs one section's build and judges it:(rows, nil), or one error row and the problem text.settingsSection.fields(ctx)— the field rows of the whole schema without the actions beneath them.settingsSection.fieldRows(ctx, fields)/settingsSection.actionRow(ctx)— the two halves ofsettingsSection.build, for a section that shows part of a schema and acts on all of it.- The Context, Section and Declaration shapes are exported as types:
Inspector.Context,Inspector.Section,Inspector.Declaration. Inspector.release(keyPrefix)— forget the rejections, section disclosures and parts state (action failures, file checks, and cached values no other open Context read) kept under a Context's key prefix and the prefixes nested in it; a closed inline editor calls it for its own.Inspector.epoch()— moves on every disclosure, rejection and write the Inspector records; a panel folds it into its build signature.Inspector.settingsSection— the Settings section (settingsSection.module).@builtin::editor.edui.inspector.presetActions— the Settings section's Save as preset / Apply preset… actions, andpresetsFor(declarer), the presets whose target is a declarer.preset.assetType/inspector.luauis the preset's own view: its target and its values edited through the target's schema.