- Where it sits
- Why the model exists
- Model overview
- How UI concepts map
- Bootstrap in React
- What is deliberately not modeled
- Write only
- Tower position
Nasdanika React Model
An Ecore micro-model of JSX and the React component shape, defined in react.xcore. It extends the TypeScript model and is a transformation target, not something you author directly.
Where it sits
Draw.io (ui + bootstrap shape library)
|
v
ui model ------------------------------> Alpine / HTML static site
| (existing generation, unchanged)
| NSML
v
react model
|
| NSML
v
typescript model --------------------------> .tsx source
The UI model is the authoring model: framework neutral vocabulary, dialect neutral bindings, and Element extends Workable, GovernedElement so every drawn element carries work and governance. Bootstrap extends it with Bootstrap 5.3 vocabulary. React does not extend it.
That distinction is the design. Bootstrap is vocabulary: a bootstrap.Card is still a ui.Container, and a Bootstrap document is still a valid UI document. React is a rendering technology. If React classes extended UI classes, a drawn interface would become React shaped at authoring time and the one drawing, several renderers property would be lost. The UI to React mapping therefore lives in a transformation rather than in inheritance.
Why the model exists
The TypeScript model covers the declaration surface and leaves bodies as opaque CodeBlock text. It has no JSX, on purpose. Generating React through it alone would put every component body into opaque text and throw away the three things the code model layer exists for:
- Import management for the components used inside JSX, which is the hardest part of emitting TypeScript correctly and the reason the code models are models at all.
- Provenance: nested markers from a Draw.io shape, through the
uielement, to the JSX element it produced. - Structure: a generated interface that can be diffed, analysed and reported on rather than compared as text.
typescript.CodeBlock carries a references list precisely so that a structured body could be substituted later. JsxBlock is that substitution.
Model overview
| Area | Types |
|---|---|
| Base | ReactElement, TsxModule |
| Components | ComponentDeclaration (extends typescript.FunctionDeclaration), JsxBlock |
| Hooks | Hook, StateHook, EffectHook, MemoHook, ContextHook, RefHook, OpaqueHook |
| Context | ContextDeclaration, ContextProvider |
| JSX | JsxNode, JsxContainer, JsxElement, JsxFragment, JsxText, JsxExpression, JsxConditional, JsxIterator, OpaqueJsx |
| Attributes | JsxAttribute, LiteralAttribute, ExpressionAttribute, EventAttribute, SpreadAttribute |
JsxElement.componentType is the load bearing feature: the emitter walks it to decide which components must be imported, from which specifier, and whether the import can be type only.
How UI concepts map
| UI model | React model | Note |
|---|---|---|
Component | ComponentDeclaration | Clean fit: a named reusable tree becomes a function component |
Include | JsxElement with componentType | arguments become attributes |
Slot | children, or a render prop | Named slots become props holding nodes |
Container / children | JsxContainer.children | Visual nesting is DOM nesting |
Fragment | JsxFragment | Both render nothing of their own |
ValueBinding | ExpressionAttribute | target becomes the JSX attribute name |
EventBinding | EventAttribute | event becomes on<Event> |
Iterator | JsxIterator | key already exists in the UI model and is what React requires |
Conditional | JsxConditional | Short circuit, or a ternary when otherwise is set |
DataContext | StateHook or ContextProvider | See below: the one place the mapping is not local |
styleClasses | LiteralAttribute className | |
attributes | LiteralAttribute | data-bs-* and ARIA pass through unchanged |
DataContext is the sharp edge. In Alpine, x-data establishes a scope on any element. React has no element level equivalent: data scope is component state or a context provider. The transformation must hoist a DataContext to the nearest enclosing Component, emitting a StateHook, or wrap it in a ContextProvider when the scope is consumed below by more than a subtree. A DataContext on a bare element inside no component is an error the transformation should report rather than paper over.
Bootstrap in React
Bootstrap 5 is CSS plus vanilla JavaScript, not a React component library, so generation emits className markup and supplies React implementations for the handful of components that need behaviour: modal, offcanvas, dropdown, collapse, toast, tooltip.
The bootstrap model earns its keep here. It models the semantics (Modal has a title, size, centered, scrollable) rather than the markup, so the same drawn model renders through the Alpine and HTML stack today and through React components tomorrow without being re-authored. No React Bootstrap wrapper library is used: one less dependency to outlive, and a wrapper would not supply the generic components this ecosystem actually needs.
What is deliberately not modeled
Hook semantics, suspense, transitions, server components, error boundaries as a concept, and routing. They arrive as OpaqueHook and OpaqueJsx, both of which carry a references list so that opaque text does not silently defeat import management.
This is the same bargain the TypeScript and Python models make, and it is why this model is about thirty classes rather than chasing a framework that moves quarterly.
Write only
There is no loader. Parsing TSX means the TypeScript compiler API, which is TypeScript rather than Java. If reverse engineering is ever wanted it belongs on the TypeScript side, emitting this model as JSON. The omission is a decision, not a gap.
Tower position
Branches off nxcore through the TypeScript model, and nothing higher. Ownership, documentation, work and governance come from the UI model, whose Element already extends Workable and GovernedElement, and reach generated code through nested markers back to the UI elements rather than by making every JSX attribute a governed object. The artifact points at its cause, and the cause is the thing with an owner.
Nasdanika Models