@miniapp-studio/zapp
v0.0.1
Published
Craft-free component, data-source, and event-handler registries for Miniapp Studio.
Readme
@miniapp-studio/zapp
The application layer: the component, data-source, and event-handler definitions a real mini-app is built from, plus the factory that wires them to host-owned capabilities.
zapp is the one package that may carry application dependencies, because it
is where a real mini-app's components, queries, and actions live. It imports
core and React, never Craft and never the builder.
The zapp dependency policy
zapp is the one package that may carry application dependencies, because it
is where a real mini-app's components, queries, and actions live. Its runtime
dependencies land in the renderer bundle, so the permitted set is closed and
reviewed: swiper, @tabler/icons-react, zustand, and tufarm-shared-utils.
Anything outside it needs a baseline review, not just an install.
Deliberately absent from zapp, each with a replacement rather than a port:
Panda CSS (CSS Modules reading theme tokens), urql/graphql/SWR (a host-created
ZappTransport), wouter (the demo host routes through an injected adapter),
i18next (literal strings in page documents), react-hook-form, zmp-sdk, and
lodash.
@tabler/icons-react follows the same rule lucide-react follows in the
builder: icons are imported by name, never as a re-exported set, so a
bundler keeps only the ones a route reaches.
swiper follows it too. zapp.Slider is a thin mapping from its twelve
authored props onto swiper/react; the modules it needs are named one by one
in slider.tsx rather than pulled from swiper/bundle, and only the
stylesheets those modules use are imported. The carousel's behaviour — sliding,
looping, autoplay, effects, and the accessible control names — belongs to
Swiper, so nothing in this package reimplements it and nothing selects into
Swiper's .swiper-* markup.
One factory, three registries
Data sources need a host-owned transport, navigation handlers need a host-owned
router, and event handlers need a host-owned store. zapp therefore exposes a
factory whose required capabilities are injected rather than constructed:
import {
createZappRegistries,
createZappTransport,
} from "@miniapp-studio/zapp";
const zapp = createZappRegistries({
router: {
navigate: (href, options) => navigate(href, options),
back: (fallbackHref) => backOrReplace(fallbackHref),
},
transport: createZappTransport({
mode: "graphql",
endpoint: "https://example.test/graphql",
headers: { authorization: `Bearer ${token}` },
}),
});
if (!zapp.ok) throw new Error(zapp.errors[0]?.message);
const { components, dataSources, eventHandlers, theme, store } =
zapp.registries;Calling createZappTransport() creates the fixture transport used by tests and
the offline demo. Production hosts may inject the GraphQL transport above or
adapt another API client to the same ZappTransport port. store is the only
state mechanism: handlers write to it, and subscribing sources refetch.
Every call includes the complete zappComponentDefinitions collection. Hosts
extend any registry by passing additionalComponentDefinitions,
additionalDataSourceDefinitions, or additionalEventHandlerDefinitions;
duplicate persisted types are rejected with the registry source attached.
The stylesheet comes with the package
zapp emits one stylesheet, and dist/index.mjs imports it. A host that
imports the package has already imported the styles; there is no second import
to remember and no component that renders correctly in one host and not
another.
It opens with the reset the component stylesheets are authored against —
box-sizing: border-box above all, since the renderer applies a node's
authored width and padding as inline style on the component's own root — and
with the cascade order the rest of the package is written in:
@layer zapp.reset, zapp.scale, zapp.component;A host that wants to re-dress a component writes plain unlayered CSS, which
beats every layer above. Out-specifying .root [data-part="…"] is no longer
the way in. See
../../documents/styling-convention.md.
Further reading
documents/component-folder-layout.md— one component per folder, every file named after it, and why the unit is the persisted type.documents/component-events.md— which events each component declares and the prop that carries each callback.documents/theme-and-scale.md— the token vocabulary the component set paints with.
