@zafuru/primitives
v1.0.0-alpha.0
Published
lowcode-ai cross-platform atomic primitives for @zafuru AI page generation, with json-render runtime integrations.
Maintainers
Readme
@zafuru/primitives
Cross-platform atomic primitives package maintained in the lowcode-ai monorepo. It was split from the historical source/json-render/packages/primitives path; lowcode-ai is now the maintenance source for this @zafuru/* package.
This package exposes two reusable layers for external low-code editors:
schema + token + meta: the stable component contractreactAtomicViews: pure React H5 views for editor canvases and preview panels
json-render remains the generic runtime / renderer integration target. Its runtime registries still exist for React H5, Taro, and React Native, but json-render is no longer the maintenance source for these AI primitives.
Installation
Current local consumers still use file: / workspace dependencies. The npm commands below describe the intended usage after these packages are published.
npm install @zafuru/primitives @json-render/core @json-render/react @json-render/react-native zodInstall Taro only if you need the Taro renderer:
npm install @tarojs/components @tarojs/taroShared Layers
1. Schema and Tokens
Use these exports when you need the component contract itself:
import {
atomicComponentDefinitions,
spaceOptions,
radiusOptions,
sizeOptions,
toneOptions,
} from "@zafuru/primitives";This layer is the source of truth for:
- component names
- strict props schemas
- shared token enums and option lists
- cross-platform prop constraints
2. Metadata for Low-Code Editors
Use atomicComponentMeta to build a component palette, inspector, and default props in a low-code editor.
import { atomicComponentMeta } from "@zafuru/primitives";
const buttonMeta = atomicComponentMeta.Button;
// {
// displayName: "Button",
// category: "input",
// canHaveChildren: true,
// layoutDisplay: "block",
// defaultProps: { label: "Button", variant: "primary", size: "md" },
// propControls: [...]
// }Recommended usage:
- palette: use
displayName,category,defaultProps - canvas nesting rules: use
canHaveChildren - inspector: render controls from
propControls - shared layout semantics: use
layoutDisplayso editor wrappers and previews agree on block vs inline behavior. Static components can use a plain string, while prop-dependent components likeDividercan declare aby-proprule. - resize handles: use
resizePolicyso the editor knows which components support width and/or height resizing without maintaining a second whitelist - edit-mode sanitizing: use
editorSanitizeso the editor knows which props should be filtered down to safe display values after expression resolution - bindable inputs: expose natural value fields like
valueandchecked, then switch that field to expression mode for{"$bindState": "/path"} - default insertion sizing:
Image.defaultProps.widthis"100%"so newly inserted images follow their wrapper instead of relying on the source image's natural width - AI generation hints: use
generationMetato understand component roles, recommended layout intent, and platform support when generating specs from PRDs or design screenshots
3. AI Generation Prompt
Use buildPrimitiveGenerationPrompt on the server side when an AI model needs to generate primitives specs. Use buildPrimitiveEvaluationPrompt when a separate evaluator model needs to review an existing spec and return a diagnostic report.
import {
buildPrimitiveEvaluationPrompt,
buildPrimitiveGenerationPrompt,
} from "@zafuru/primitives";
const systemPrompt = buildPrimitiveGenerationPrompt({
targetPlatform: "h5",
includePropControls: true,
output: "spec",
customRules: ["Prefer concise mobile page structures."],
});
const evaluationPrompt = buildPrimitiveEvaluationPrompt({
targetPlatform: "h5",
includePropControls: true,
});The generated prompts are derived from atomicComponentDefinitions and atomicComponentMeta, including component roles, children rules, events, default props, generationMeta, dynamic expression rules, and report guidance. The default generation prompt keeps the legacy { spec, report } shape; pass output: "spec" for a two-stage flow where generation returns only the spec and evaluation returns the report separately.
4. Pure React H5 Views
Use reactAtomicViews when your editor or canvas needs the same H5 presentation as json-render without pulling in the json-render runtime.
import { reactAtomicViews } from "@zafuru/primitives";
function EditorCanvasButton() {
return (
<reactAtomicViews.Button
label="Save"
variant="primary"
onPress={() => {}}
/>
);
}These views:
- accept normalized props and simple callbacks
- do not depend on
emit,bindings, or editor-specific APIs - are suitable for Craft.js-like canvases, previews, or custom inspectors
Runtime Registries
If you want the full json-render runtime behavior, keep using the existing registries:
reactAtomicRegistrytaroAtomicRegistryreactNativeAtomicRegistry
Example:
import {
ActionProvider,
Renderer,
StateProvider,
ValidationProvider,
VisibilityProvider,
} from "@json-render/react";
import { reactAtomicRegistry } from "@zafuru/primitives/react";
function App({ spec }) {
return (
<StateProvider initialState={spec.state ?? {}}>
<VisibilityProvider>
<ActionProvider handlers={{}}>
<ValidationProvider>
<Renderer spec={spec} registry={reactAtomicRegistry} />
</ValidationProvider>
</ActionProvider>
</VisibilityProvider>
</StateProvider>
);
}How to Share with a Craft.js Project
Recommended split of responsibilities:
- current package (
@zafuru/primitives)- owns schema, tokens, metadata, and pure H5 views
- companion package (
@zafuru/primitives-craft)- owns spec-to-Craft and Craft-to-spec conversion helpers
- your Craft.js project
- owns palette UI, inspector UI, canvas wrappers, and editor state
The minimal consumption path is:
- Use
atomicComponentMetato build the palette and inspector - Use
reactAtomicViewsto render the canvas layer - Keep json-render spec as the publishable output
- Use
@zafuru/primitives-craftforspec -> Craft nodes -> edit -> spec
Craft.js Adapter
Craft.js conversion helpers live in the companion package:
npm install @zafuru/primitives-craft @craftjs/coreThis install command is also for post-publish npm consumption. Local verification should continue to use the monorepo workspace package or the consuming repo's file: dependency.
The core package still does not include:
- Craft.js resolvers
- editor preview runtime for
visible,repeat,watch,$state,$bindState
Those remain editor responsibilities layered on top of the interfaces exposed here.
Atomic Components
ScreenViewFlexScrollViewTextImageIconSpacerDividerPressableButtonInputTextareaCheckboxRadioGroupSwitchSelectSlider
Component Rules
- No
style,className,sx, or Tailwind escape hatches - Only cross-platform props are allowed
visible,repeat, andwatchstay on the element object- Inputs use
$bindStateon their natural value prop - Input-like components can use
checksandvalidateOnfor runtime validation - Interaction uses
on.press,on.change,on.focus,on.blur, andon.submit
Form Validation
The bindable input primitives support the same validation contract as
@json-render/react:
Input,Textarea,RadioGroup,Select, andSlidervalidate theirvalueCheckboxandSwitchvalidate theircheckedvaluechecksstores validation checks such asrequired,email,minLength,maxLength,pattern,min,max,numeric, andurlvalidateOncontrols when field-level validation runs:change,blur, orsubmit
Validation is registered only when the natural value prop is bound with
$bindState. The validateForm action validates all registered fields and writes
the result to /formValidation by default.
Notes
Iconships with a tiny fallback renderer that displays a semantic glyph based on the icon name. Production apps will usually replace it with their own icon system.Select,RadioGroup,Checkbox, andSliderstill use lightweight built-in fallbacks on React Native so the spec stays portable without introducing extra runtime dependencies.Divider.lengthcontrols the separator length along its main axis. Horizontal dividers treat it as width; vertical dividers treat it as height.
