@seliseblocks/app-kit
v0.1.2
Published
Shared React components, layouts, providers, authentication and utilities for SELISE Blocks applications.
Maintainers
Keywords
Readme
@seliseblocks/app-kit
React app-shell composition package for SELISE Blocks applications: guards, layouts, providers, pages, stores, hooks, an HTTP client, and a shadcn/Radix based component library. It is the shared frontend foundation consumed by the Blocks service applications (IAM, OS, Data, Logic, Monitor, Release, Studio, Utilities, Localization).
Ships as ESM and CJS with bundled TypeScript declarations. Every module carries a "use client" banner, and runtime initialization is preserved across entry points.
Installation
npm install @seliseblocks/app-kit
# or
yarn add @seliseblocks/app-kit
# or
pnpm add @seliseblocks/app-kitPeer Dependencies
Your application must provide these packages (@types/react is optional, for TypeScript users):
{
"@tanstack/react-query": "^5.0.0",
"nuqs": "^2.9.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-router": "^8.0.0",
"zustand": "^5.0.0"
}Styling Contract
This package intentionally ships no CSS files. Host applications are responsible for:
Tailwind CSS setup, including scanning this package's dist output so its utility classes are generated:
// tailwind.config.ts export default { content: ["./app/**/*.{ts,tsx}", "./node_modules/@seliseblocks/app-kit/dist/**/*.{js,jsx,ts,tsx}"], };Tailwind CSS setup
shared design tokens (CSS variables) for theming
Any global CSS imports required by their design system
Runtime Configuration
Service base URLs and keys are read at runtime, not baked in at build time. Provide them on window.__BLOCKS_ENV__ before the app boots (typically an inline script in index.html), or through import.meta.env in ESM/Vite builds. CommonJS builds use the runtime window configuration:
<script>
window.__BLOCKS_ENV__ = {
BLOCKS_IAM_BASE_URL: "https://iam.example.com",
BLOCKS_LOGIC_BASE_URL: "https://logic.example.com",
BLOCKS_X_BLOCKS_KEY: "your-blocks-key",
};
</script>Read values with getRuntimeEnv from @seliseblocks/app-kit/lib. The full key list is the RuntimeKey union exported from @seliseblocks/app-kit/types (per-service *_BASE_URL, *_CLIENT_ID, and *_CALLBACK_URL keys plus BLOCKS_X_BLOCKS_KEY and others).
Quick Start
Wrap your app in the providers, then compose routes from the guards, layouts, and pages:
import { NuqsAdapter } from "nuqs/adapters/react-router/v8";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { createBrowserRouter, Navigate, Outlet, RouterProvider } from "react-router";
import { AuthResolver, ProtectedGuard, PublicGuard } from "@seliseblocks/app-kit/guards";
import { ConsoleLayout } from "@seliseblocks/app-kit/layouts";
import { CallbackPage, ConsolePage, LoginPage, ProfilePage } from "@seliseblocks/app-kit/pages";
import { BlocksAppLayout, QueryProvider, ThemeProvider } from "@seliseblocks/app-kit/providers";
const router = createBrowserRouter([
{
path: "/login/callback",
element: <CallbackPage defaultRedirectUrl="/app/console" />,
},
{
element: (
<AuthResolver>
<Outlet />
</AuthResolver>
),
children: [
{
element: (
<PublicGuard>
<Outlet />
</PublicGuard>
),
children: [{ path: "/login", element: <LoginPage /> }],
},
{
path: "/app",
element: (
<ProtectedGuard>
<ConsoleLayout>
<Outlet />
</ConsoleLayout>
</ProtectedGuard>
),
children: [
{ index: true, element: <Navigate to="console" replace /> },
{ path: "console", element: <ConsolePage /> },
{ path: "profile", element: <ProfilePage /> },
],
},
],
},
]);
createRoot(document.getElementById("root")!).render(
<StrictMode>
<QueryProvider>
<ThemeProvider>
<NuqsAdapter>
<BlocksAppLayout
config={{
name: "blocks-monitor",
appLogoUrl: { dark: "/logo-dark.svg", light: "/logo-light.svg" },
}}
>
<RouterProvider router={router} />
</BlocksAppLayout>
</NuqsAdapter>
</ThemeProvider>
</QueryProvider>
</StrictMode>,
);BlocksAppLayout takes a config with the service name (one of the ServiceName union values, for example "blocks-os" or "blocks-monitor") and an appLogoUrl (a string, or { dark, light } variants).
Package Exports
The main entry (@seliseblocks/app-kit) re-exports everything below. Subpath imports keep intent clearer and are what the Blocks applications use.
| Subpath | Contents |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ./guards | AuthResolver, ProtectedGuard, PublicGuard, ImpersonationChecker, ImpersonationSynchronizer, ImpersonationTerminator |
| ./layouts | AuthLayout, ConsoleLayout, DashboardLayout, DashboardRoute, OidcLayout, PublicLayout, useOidcContext |
| ./providers | BlocksAppLayout, QueryProvider, ThemeProvider, DashboardLayoutProvider, getQueryClient |
| ./pages | CallbackPage, ConsolePage, DashboardOverview, LoginPage, ProfilePage |
| ./store | useAuthStore, useAppSettingsStore, useImpersonateStore, useLanguageViewStore, useProjectStore, useUserStore, CreateAppConfigStore |
| ./hooks | See Hooks below |
| ./components | See Components below |
| ./lib | See HTTP Client and Lib below |
| ./utils | General-purpose helpers, see Utils below |
| ./models | Domain models: AuthStateShape, AuthTokenPair, BaseUser, UserDetails, IProject, IProjectGroup, IDomain, IEnvRepository, INotification, IMyOrganization, ImpersonationState, RegisteredService, and related payload/response types |
| ./types | Shared types: ApiResponse, ApiError, ApiErrorResponse, ApiPaginatedResponse, BaseRequestParams, Menu, NavigationMenuItem, NavigationNode, RuntimeKey, ProjectKey, Id |
Components
@seliseblocks/app-kit/components bundles two groups:
Core components (Radix UI + shadcn based):
Accordion,Alert,AlertDialog,AspectRatio,Avatar,Badge,Breadcrumb,Button,Calendar,Card,Carousel,ChartContainer,Checkbox,Collapsible,Command,ContextMenu,CopyToClipboardButton,DateRangePicker,Dialog,Drawer,DropdownMenu,FileUploader,Form,HoverCard,InfiniteScroller,Input,InputOTP,KanbanBoard,Label,MaskedText,Menubar,MultiSelect,NavigationMenu,Pagination,PasswordInput,Popover,Progress,RadioGroup,RenderConditionally,RenderAlternatively,ResizablePanel,ScrollArea,Select,Separator,Sheet,Sidebar,Skeleton,Slider,Spinner,Stepper,Switch,Table,TablePagination,Tabs,Textarea,Timeline,Toast,Toaster,Toggle,ToggleGroup,Tooltip, and theWizardStepperfamily, along with their subcomponents (CardContent,DialogTrigger,SelectItem, and so on).Common composites:
AppSwitcher,ArchiveProject,BackToConsoleNavigator,ConfirmationModal,ConsoleHeader,CopyableSnippet,DashboardHeader,DashboardSectionCard,DataTable,EnvironmentCard,EnvironmentList,EnvironmentSelected,ErrorBoundary,ErrorDisplay,FilterToolbar,ImportFileModal,LanguageSelector,LoaderSpinner,LoadingButton,LoginHeader,Logo,LogoutButton,ModeToggle,Notification,NotificationBell,NotificationHeader,NotificationItem,NotificationList,ProjectList,ProjectDetail,ProjectEdit,ProjectActions,SidebarMenu,ThemeSwitcher,UserDropdownMenu, and more.
import { Button, Card, CardContent } from "@seliseblocks/app-kit/components";
function MyComponent() {
return (
<Card>
<CardContent>
<Button variant="default">Click Me</Button>
</CardContent>
</Card>
);
}Hooks
State and UI helpers: useBoolean, useCopyToClipboard, useCountDown, useDebounce, useMediaQuery, useIsMobile, usePathSegments, usePopoverWidth, useTheme, useToast, useIcon, useLogo, useScopedPath, useBlocksAppConfigStore.
Search: useFuseIndex, useFuseSearch, useDebouncedFuseFilter.
Query helpers: useQueryClientKit, useQueryStatesKit, createQueryKeyFactory.
Domain data (TanStack Query backed): useGetProject, useGetProjects, useUpdateProject, useDisableProject, useGetEnvRepositories, useGetAllServices, useGetMyOrganizations, useGetNotifications, useMarkAsRead, useMarkAllAsRead, useStartImpersonation, useStopImpersonation, useImpersonationStatusChecker, useInitiateRedirect, usePrefetchRedirect, useLanguage, useLanguageSwitcher, useLogout, useFilteredMenus, useIsActiveMenu.
import { useBoolean, useToast } from "@seliseblocks/app-kit/hooks";
function MyComponent() {
const { toast } = useToast();
const { value: isOpen, toggle } = useBoolean(false);
return (
<button
onClick={() => {
toggle();
toast({ title: isOpen ? "Closed" : "Opened" });
}}
>
Toggle
</button>
);
}HTTP Client and Lib
@seliseblocks/app-kit/lib exports:
HttpClientandHttpError: a fetch-based client with Blocks key headers, token refresh queueing, and auth-failure redirects- Preconfigured instances wired to the runtime env:
iamClient,logicClient,notificationClient getRuntimeEnv,createRuntimeEnvGetter,resolveBaseUrl,resolveEnvCookieStorage,cn, theme helpers (applyTheme,getSystemTheme), and motion presets (fadeInUp,fadeInScale,fadeTransition,motionEase,staggerContainer,staggerItem)
import { getRuntimeEnv, HttpClient, logicClient } from "@seliseblocks/app-kit/lib";
// Use a preconfigured instance:
async function fetchProjects() {
return logicClient.get("/api/Project/Gets?page=0&pageSize=100");
}
// Or configure your own:
const client = new HttpClient({
baseURL: () => getRuntimeEnv("BLOCKS_LOGIC_BASE_URL"),
blocksKey: () => getRuntimeEnv("BLOCKS_X_BLOCKS_KEY"),
});Utils
@seliseblocks/app-kit/utils covers formatting (formatDate, formatFullDate, formatNumber, formatCurrency, formatBytes, formatFileSize, formatDuration), objects and arrays (pick, omit, deepClone, deepEqual, deepMerge, groupBy, uniqueBy), functions (debounce, throttle, memoize, sleep), validation (isEmail, isUrl, isUuid, isPhone, isValidDomain, isValidSubdomain), query strings (parseQueryString, stringifyQueryString), ids (generateId, getUniqueID), storage (createStorage, createCookieStore), error handling (getErrorMessage, handleErrorMessages, hasErrorCode), and toast helpers (showSuccessToast, showErrorToast, showInfoToast).
Versioning and compatibility
The new package starts at 0.1.0. Existing public exports and subpaths are preserved; future changes to those APIs should be coordinated across Blocks applications.
License
MIT (c) SELISE Blocks
Local development and publishing
The console resolves this package to its local entries/ source through Vite and TypeScript aliases. Other applications install the published package. Internal @app-kit/ paths are bundled and do not need aliases in consuming applications.
From client/, run:
npm run build:app-kit
npm run pack:app-kitThe first release uses version 0.1.0. Inspect the tarball before publishing. From this package directory, an npm account with publishing access to the @seliseblocks scope can run:
npm publish --access publicPublishing runs the type check and builds the package. Only compiled output, this README, the license and package metadata are included; tests and local source instructions stay out of the tarball. No publication is performed by the console build.
Migration
Replace imports from @seliseblocks/genesis-os with @seliseblocks/app-kit, keeping the existing subpaths and exported symbols. The existing published genesis-os package is unaffected.
Shared application shell
AppShell from @seliseblocks/app-kit/layouts owns the top bar, desktop/mobile
sidebar, workspace switcher, theme controls and account menu. AppSidebar,
AppTopbar and WorkspaceSwitcher are also exported from ./components.
import { AppShell } from "@seliseblocks/app-kit/layouts";
<AppShell sidebar sections={scopedNavigationSections} onOpenCommand={openCommandMenu}>
<Outlet />
</AppShell>Use it inside the app-kit auth/impersonation guards and the existing
BlocksAppLayout, query and theme providers. The host supplies its filtered,
URL-scoped navigation and command-menu opener; no sidebar markup or tenant
switching code is required in the host. Omit sidebar for console/profile pages.
The workspace picker loads projects only when opened, groups environments under
projects, disables unavailable environments, and establishes impersonation before
updating selection and navigating to /app/:itemId/dashboard. Standalone
WorkspaceSwitcher consumers can override environmentPath and receive
onNavigate to close their own mobile drawer. Errors preserve the selection and
route and show feedback; a failed list query offers retry.
Tailwind 4 hosts should expose the usual semantic sidebar colours, for example:
@theme {
--color-sidebar: hsl(var(--background));
--color-sidebar-foreground: hsl(var(--foreground));
--color-sidebar-border: hsl(var(--border));
--color-sidebar-accent: hsl(var(--accent));
--color-sidebar-accent-foreground: hsl(var(--accent-foreground));
--color-sidebar-ring: hsl(var(--ring));
}Continue scanning the package's dist directory for Tailwind utilities.
