Skip to content

Cross-Platform

Craft Easy Admin runs on web, iOS, and Android from a single codebase using React Native + Expo. The UI adapts automatically to each platform.

Platform Support

Platform Runtime Notes
Web react-native-web Standard browser deployment
iOS Expo (native) Full native performance
Android Expo (native) Full native performance

Responsive Layout

Desktop (width >= 768px)

  • Sidebar is permanently visible on the left (250px wide)
  • Header spans the remaining width, no menu button
  • Content fills the remaining space
┌──────────┬─────────────────────────────────┐
│          │          Header                  │
│ Sidebar  ├─────────────────────────────────┤
│ (250px)  │                                 │
│          │        Content Area             │
│          │                                 │
│          │                                 │
└──────────┴─────────────────────────────────┘

Mobile (width < 768px)

  • Sidebar hidden, rendered as a drawer/modal overlay
  • Header shows a menu button to open the drawer
  • Content takes full width
┌─────────────────────────────────┐
│  [☰]     Header                 │
├─────────────────────────────────┤
│                                 │
│         Content Area            │
│         (full width)            │
│                                 │
└─────────────────────────────────┘

Mobile-Optimized Components

Several components use modal-based pickers optimized for touch:

Component Desktop Mobile
Select Modal dropdown Slide-up modal with FlatList
MultiSelect Modal with checkboxes Same — touch-friendly checkboxes
RelationPicker Search modal Same — with ActivityIndicator
Navigation Sidebar Drawer overlay

All interactive elements use appropriate touch targets:

  • Minimum hitSlop={8} on small buttons
  • Pressable components with adequate spacing
  • Modal animations via animationType="slide" for native feel

ETag Collision Modal

When two users edit the same document simultaneously, the API returns 412 Precondition Failed. The admin app handles this with a dedicated collision modal:

interface ETagCollisionModalProps {
  visible: boolean;
  onReload: () => void;
  onOverwrite: () => void;
  onCancel: () => void;
}

When it appears: A PATCH or PUT request fails with HTTP 412, meaning the document was modified since it was loaded.

Options:

Action Behavior
Reload Fetches the latest version, re-initializes the form with updated data
Overwrite Fetches the latest ETag, re-submits the user's changes with the new ETag
Cancel Closes the modal, abandons the save attempt

This prevents silent data loss from concurrent edits.

Soft Delete Filter

List views include a SoftDeleteFilter toggle that controls whether soft-deleted items are visible:

interface SoftDeleteFilterProps {
  showDeleted: boolean;
  onToggle: (showDeleted: boolean) => void;
}

When enabled, the list query includes is_deleted=true items in the results.

Views

The admin app includes four view types that adapt to the current resource schema:

ListView

  • Breadcrumb navigation
  • Title with item count
  • Search bar (when search_fields configured)
  • Sort chips (when sort_fields configured)
  • Paginated list with FlatList
  • Bulk selection via long-press
  • Create button (when features.create is true)

DetailView

  • Read-only display of all fields
  • Edit button (when features.edit is true)
  • Delete button with confirmation dialog (when features.delete is true)
  • Audit trail section (created_at, updated_at, created_by, updated_by)
  • Formatted values: booleans as checkmarks, dates localized, numbers formatted

CreateView

  • Form groups from resource.form.groups
  • Field validation: required, min_length, regex pattern
  • Cancel and Save buttons

EditView

  • Same form layout as CreateView
  • Pre-populated with current data via useResource()
  • ETag collision detection on save
  • Cancel, Save buttons

npm Package

@craft-easy/admin is published to npm and can be used as a library when embedding the admin framework into an existing Expo project.

Installation

npm install @craft-easy/admin
yarn add @craft-easy/admin
pnpm add @craft-easy/admin

Peer Dependencies

The package requires the following peer dependencies to be installed in the host project:

Package Version
react >= 18.0.0
react-native >= 0.74.0
expo >= 55.0.0
expo-router >= 5.0.0
expo-constants >= 17.0.0
expo-linking >= 7.0.0
expo-status-bar >= 2.0.0
react-native-safe-area-context >= 5.0.0
react-native-screens >= 4.0.0

Web-only (optional):

Package Version
react-dom >= 18.0.0
react-native-web >= 0.19.0

Exported Components

All exports are available from the root @craft-easy/admin entry point, or via subpath imports for tree-shaking.

View Components (@craft-easy/admin/components)

Export Description
ListView Paginated resource list with search, sort chips, and bulk selection
DetailView Read-only record display with audit trail
CreateView Form view for creating new records
EditView Pre-populated form view with ETag collision detection

Layout Components (@craft-easy/admin/components)

Export Description
Breadcrumbs Navigation breadcrumb bar
Header App header with menu button for mobile
Sidebar Schema-driven navigation sidebar
ApplicationSwitcher Switcher for multi-API sessions
ETagCollisionModal Modal for resolving concurrent edit conflicts
SoftDeleteFilter Toggle to include/exclude soft-deleted records
TenantSwitcher Tenant selector for multi-tenant APIs

Field Widgets (@craft-easy/admin/components)

Export Description
FieldRenderer Auto-renders the correct widget for a field schema
TextInputField Single-line text input
TextArea Multi-line text input
NumberInput Numeric input with optional min/max/step
Select Single-select dropdown
MultiSelect Multi-select with checkboxes
DatePicker Date-only picker
DateTimePicker Date and time picker
Toggle Boolean switch
FileUpload File/binary upload
RelationPicker Search-and-select for related resources
TagInput Free-text tag list
JsonEditor Raw JSON text editor

Hooks (@craft-easy/admin/hooks)

Export Description
useAdminSchema Fetches and caches the /admin/schema response
useResource Fetches a single resource record by ID
useResourceList Fetches a paginated resource list with filters
useResourceMutations Returns create, update, remove mutation functions

Stores (@craft-easy/admin/stores)

Export Description
useApplicationStore Zustand store for managing API connections and active session
applicationStore Raw store instance for use outside React

Context (@craft-easy/admin/context)

Export Description
ThemeProvider Wraps the app with light/dark theme support
useTheme Returns current colors palette and mode

Lib (@craft-easy/admin/lib)

Export Description
createApiClient Factory for an authenticated API client with ETag support
ApiError Error class thrown on non-2xx responses
getListFields Extracts display fields from a resource schema
getFormFields Extracts form fields from a resource schema
getFieldLabel Returns the display label for a field
formatCellValue Formats a raw field value for list display

Types (@craft-easy/admin/types)

Export Description
AdminSchema Root schema object from /admin/schema
ResourceSchema Single resource definition
FieldSchema Field metadata and widget type
FormConfig / FormGroup Form group structure
ListConfig List view configuration
NavigationGroup Sidebar navigation group
AuthConfig Auth endpoint configuration
ThemeConfig API-driven theme overrides
Application Stored API connection record

Subpath Import Example

import { useAdminSchema, useResourceList } from '@craft-easy/admin/hooks';
import { FieldRenderer, ListView } from '@craft-easy/admin/components';
import { useApplicationStore } from '@craft-easy/admin/stores';
import { ThemeProvider, useTheme } from '@craft-easy/admin/context';
import type { AdminSchema, ResourceSchema } from '@craft-easy/admin/types';
import { createApiClient } from '@craft-easy/admin/lib';