@salla.sa/twilight-theme-engine
v1.0.0-beta.4
Published
Core engine for Salla React themes - component registry, hooks, contexts, routes, and base components
Maintainers
Readme
@salla.sa/twilight-theme-engine
Slim core engine for Salla React themes built on TanStack Start.
Installation
npm install @salla.sa/twilight-theme-engineFeatures
- Component Registry - Dynamic component resolution with override support
- Hook System - Extension points for content injection
- Data Contexts - Store, Theme, User providers
- i18n - Translation and RTL support
- Utilities - Money formatting, asset helpers, color utilities
Documentation
- Home Components - Home page component system with
dataprop pattern
Quick Start
Setup Providers
import { TwilightProvider } from '@salla.sa/twilight-theme-engine';
import { I18nProvider } from '@salla.sa/twilight-theme-engine/i18n';
function App() {
return (
<TwilightProvider storeIdentifier="my-store" defaultLocale="ar">
<I18nProvider locale="ar" translations={translations}>
{children}
</I18nProvider>
</TwilightProvider>
);
}Component Registry
import { registry, Component, defineComponent } from '@salla.sa/twilight-theme-engine';
// Register components
registry.register('header', Header);
registry.register('product.card', ProductCard);
// Override in custom theme
registry.override('header', CustomHeader);
// Use dynamically
<Component name="product.card" product={product} />;Hook System
import { defineHooks } from '@salla.sa/twilight-theme-engine/hooks/HookRegistry';
import { HookSlot } from '@salla.sa/twilight-theme-engine/hooks/HookSlot';
// Define hooks
defineHooks({
'body:start': () => <AnnouncementBar />,
'product:form.end': ({ product }) => <TrustBadges />,
});
// Use in pages
<HookSlot name="product:form.end" context={{ product }} />;Use Contexts
import { useStore } from '@salla.sa/twilight-theme-engine/hooks/useStore';
import { useTheme } from '@salla.sa/twilight-theme-engine/hooks/useTheme';
import { useTwilight } from '@salla.sa/twilight-theme-engine';
function MyComponent() {
const store = useStore();
const theme = useTheme();
const { user, isRTL } = useTwilight();
const setting = theme.settings.get('header_is_sticky', true);
}Translations
import { useI18n } from '@salla.sa/twilight-theme-engine/i18n';
function MyComponent() {
const { t } = useI18n();
return (
<div>
<h1>{t('pages.cart.title')}</h1>
<p>{t('pages.products.sold_times', { count: 5 })}</p>
</div>
);
}Utilities
import { useMoney } from '@salla.sa/twilight-theme-engine/hooks/useMoney';
import { useAsset } from '@salla.sa/twilight-theme-engine/hooks/useAsset';
function ProductCard({ product, featured }) {
const { formatMoney } = useMoney();
const { asset, cdn } = useAsset();
return (
<div className={cn('card', featured && 'card--featured')}>
<img src={cdn(product.image.url, 400)} />
<p>{formatMoney(product.price)}</p>
</div>
);
}Import Paths
Use granular imports to avoid pulling in the entire package:
// Core
import { TwilightProvider, useTwilight } from '@salla.sa/twilight-theme-engine';
// Hooks (granular)
import { useStore } from '@salla.sa/twilight-theme-engine/hooks/useStore';
import { useTheme } from '@salla.sa/twilight-theme-engine/hooks/useTheme';
import { useMoney } from '@salla.sa/twilight-theme-engine/hooks/useMoney';
import { useAsset } from '@salla.sa/twilight-theme-engine/hooks/useAsset';
// i18n
import {
useI18n,
I18nProvider,
FALLBACK_LOCALE,
getLanguageInfo,
} from '@salla.sa/twilight-theme-engine/i18n';
// Components
import { Link } from '@salla.sa/twilight-theme-engine/common';
// Routes
import { Home } from '@salla.sa/twilight-theme-engine/routes/home';
import type { HomeLoaderData } from '@salla.sa/twilight-theme-engine/routes/home';
// API
import { store } from '@salla.sa/twilight-theme-engine/api/store';
import { translations } from '@salla.sa/twilight-theme-engine/api/translations';
// Types
import type { Store, Theme, Product } from '@salla.sa/twilight-theme-engine/types';License
MIT
