npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zafuru/primitives

v1.0.0-alpha.0

Published

lowcode-ai cross-platform atomic primitives for @zafuru AI page generation, with json-render runtime integrations.

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 contract
  • reactAtomicViews: 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 zod

Install Taro only if you need the Taro renderer:

npm install @tarojs/components @tarojs/taro

Shared 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 layoutDisplay so editor wrappers and previews agree on block vs inline behavior. Static components can use a plain string, while prop-dependent components like Divider can declare a by-prop rule.
  • resize handles: use resizePolicy so the editor knows which components support width and/or height resizing without maintaining a second whitelist
  • edit-mode sanitizing: use editorSanitize so the editor knows which props should be filtered down to safe display values after expression resolution
  • bindable inputs: expose natural value fields like value and checked, then switch that field to expression mode for {"$bindState": "/path"}
  • default insertion sizing: Image.defaultProps.width is "100%" so newly inserted images follow their wrapper instead of relying on the source image's natural width
  • AI generation hints: use generationMeta to 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:

  • reactAtomicRegistry
  • taroAtomicRegistry
  • reactNativeAtomicRegistry

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:

  1. Use atomicComponentMeta to build the palette and inspector
  2. Use reactAtomicViews to render the canvas layer
  3. Keep json-render spec as the publishable output
  4. Use @zafuru/primitives-craft for spec -> Craft nodes -> edit -> spec

Craft.js Adapter

Craft.js conversion helpers live in the companion package:

npm install @zafuru/primitives-craft @craftjs/core

This 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

  • Screen
  • View
  • Flex
  • ScrollView
  • Text
  • Image
  • Icon
  • Spacer
  • Divider
  • Pressable
  • Button
  • Input
  • Textarea
  • Checkbox
  • RadioGroup
  • Switch
  • Select
  • Slider

Component Rules

  • No style, className, sx, or Tailwind escape hatches
  • Only cross-platform props are allowed
  • visible, repeat, and watch stay on the element object
  • Inputs use $bindState on their natural value prop
  • Input-like components can use checks and validateOn for runtime validation
  • Interaction uses on.press, on.change, on.focus, on.blur, and on.submit

Form Validation

The bindable input primitives support the same validation contract as @json-render/react:

  • Input, Textarea, RadioGroup, Select, and Slider validate their value
  • Checkbox and Switch validate their checked value
  • checks stores validation checks such as required, email, minLength, maxLength, pattern, min, max, numeric, and url
  • validateOn controls when field-level validation runs: change, blur, or submit

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

  • Icon ships 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, and Slider still use lightweight built-in fallbacks on React Native so the spec stays portable without introducing extra runtime dependencies.
  • Divider.length controls the separator length along its main axis. Horizontal dividers treat it as width; vertical dividers treat it as height.