diff --git a/README.md b/README.md index 1f60bee1..59cf09fb 100644 --- a/README.md +++ b/README.md @@ -20,72 +20,47 @@ Architecture. - 🏝️ **Partial System** - Interactive components with HTMX - 🚀 **Framework Agnostic** - Core composition engine -## Quick Start +## What is Reface? + +Reface is a modern web framework built on two key components: + +1. **Core Library** (RefaceComposer) - Template engine for HTML generation +2. **Framework** (Reface) - Full-featured web framework with plugins and Islands + Architecture + +- [Getting Started](./docs/getting-started.md) - Quick introduction and basic + setup +- [Main Concepts](./docs/concepts.md) - Core ideas and architecture +- [API Reference](./docs/api.md) - Detailed API documentation + +### Quick Example ```typescript +// Core API (Template Engine) import { RefaceComposer } from "@reface/core"; -import { StyledPlugin } from "@reface/plugins/styled"; -import { PartialsPlugin } from "@reface/plugins/partials"; -// Create composer instance const composer = new RefaceComposer(); -composer.use(new StyledPlugin()); -composer.use(new PartialsPlugin()); - -// Create styled component -const Button = styled.button` - & { - background: var(--primary-color, #3182ce); - color: white; - padding: 0.5rem 1rem; - } -`; - -// Create interactive component -const Counter = partial(async () => { - const count = 0; - return ( -
- {count} - -
- ); -}, "counter"); - -// Create page template -function HomePage() { - return ( -
-

Welcome to Reface

- -
- ); -} - -// Compose HTML -const html = composer.render(); -``` +const template = div({ class: "greeting" })`Hello ${name}!`; +const html = composer.render(template); -## Examples +// Framework API (Full Features) +import { Reface } from "@reface"; -- [📚 Basic Components](./examples/basic) - Component composition -- [🧩 Styled Components](./examples/styled) - CSS-in-JS examples -- [🏝️ Partial Components](./examples/partials) - Interactive components -- [🔌 Custom Plugin](./examples/plugin) - Plugin development +const app = new Reface({ + layout: Layout, +}).page("/", Home); -## Documentation - -- [Architecture](./docs/architecture.md) - Core concepts and composition design -- [Components](./docs/components.md) - Component composition system -- [Styling](./docs/styling.md) - CSS-in-JS styling -- [Partials](./docs/partials.md) - Interactive components -- [Plugins](./docs/plugins.md) - Plugin system +Deno.serve(app.fetch); +``` -## Contributing +## Installation -We welcome contributions! Please see our [Contributing Guide](./CONTRIBUTING.md) -for details. +```typescript +// Using Deno +import { Reface } from "jsr:@vseplet/reface"; -## License +// Using NPM (coming soon) +npm install @reface/core +``` MIT © [Reface](./LICENSE) diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 00000000..25cd6a14 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,121 @@ +# API Reference + +## Core API + +### Template + +Base template creation and manipulation: + +```typescript +import { createTemplate } from "@reface/template"; + +const template = createTemplate({ tag: "div" }); +template({ class: "container" })`Content`; +``` + +### Elements + +Pre-defined HTML elements: + +```typescript +import { button, div, span } from "@reface/elements"; + +div({ class: "container" })` + ${span`Text`} + ${button({ type: "button" })`Click me`} +`; +``` + +### JSX + +JSX support: + +```typescript +import { createElement, Fragment } from "@reface"; + +// Fragment +<> +
First
+
Second
+; + +// Components +function Button(props: ButtonProps) { + return ; +} +``` + +### Components + +Component creation: + +```typescript +import { component } from "@reface"; + +const Button = component((props, children) => { + // Elements API + return button({ class: props.class })`${children}`; + + // Or JSX + return ; +}); +``` + +## Framework API + +### Reface + +Main framework class: + +```typescript +const app = new Reface({ + layout: Layout, + plugins: [...plugins], +}); + +// Pages +app.page("/", HomePage); + +// Hono integration +app.hono(); +``` + +### Plugins + +Built-in plugins: + +```typescript +import { StyledPlugin } from "@reface/plugins/styled"; +import { PartialsPlugin } from "@reface/plugins/partials"; + +app.use(new StyledPlugin()); +app.use(new PartialsPlugin()); +``` + +### Styling + +CSS-in-JS system: + +```typescript +import { styled } from "@reface/plugins/styled"; + +const Button = styled.button` + & { + /* styles */ + } +`; +``` + +### Islands + +Interactive components: + +```typescript +import { island } from "@reface"; + +const Interactive = island({ + template: () => {...}, + state: {...}, + rpc: {...} +}); +``` diff --git a/docs/architecture.md b/docs/architecture.md deleted file mode 100644 index f02eda7e..00000000 --- a/docs/architecture.md +++ /dev/null @@ -1,182 +0,0 @@ -# Architecture - -## System Architecture - -```ts -┌─────────────────────────────────────────┐ -│ Reface │ -│ │ -│ ┌─────────────┐ ┌────────────┐ │ -│ │ Deno │ │ Router │ │ -│ │ Server │─────▶ │ System │ │ -│ └─────────────┘ └────────────┘ │ -│ │ │ │ -│ ▼ ▼ │ -│ ┌─────────────┐ ┌────────────┐ │ -│ │ Static │ │ Layouts │ │ -│ │ Files │ │ │ │ -│ └─────────────┘ └────────────┘ │ -│ │ │ -│ ▼ │ -│ ┌─────────────────────────────────┐ │ -│ │ RefaceComposer │ │ -│ │ │ │ -│ │ ┌──────────┐ ┌──────────┐ │ │ -│ │ │ Plugin │ │ Template │ │ │ -│ │ │ System │ │ Process │ │ │ -│ │ └──────────┘ └──────────┘ │ │ -│ └─────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────┐ │ -│ │ Interactive System │ │ -│ │ │ │ -│ │ ┌──────────┐ ┌────────┐ │ │ -│ │ │ Partials │ │Islands │ │ │ -│ │ │ (HTMX) │ │ (RPC) │ │ │ -│ │ └──────────┘ └────────┘ │ │ -│ └─────────────────────────────────┘ │ -└─────────────────────────────────────────┘ -``` - -## Core Components - -### 1. Reface Framework - -High-level framework providing: - -- Deno server integration -- Static file handling -- Routing system -- Layout management -- Plugin configuration -- Interactive architecture - -### 2. RefaceComposer - -Template composition engine: - -- Plugin management -- Template processing -- HTML generation -- Component system - -### 3. Interactive System - -#### Partials (HTMX) - -- Live components -- REST-based updates -- HTMX integration -- State management - -#### Islands (RPC) - -- Micro-applications -- RPC protocol support -- Rich interactions -- Isolated state - -## Implementation Details - -### Server Layer - -```typescript -class Reface { - constructor(options: { layout: Layout }) { - this.layout = options.layout; - } - - // Page routing - page(route: string, generator: TemplateGenerator) { - // Page registration - } - - // Server adapters - hono() { - /* Hono integration */ - } - oak() { - /* Oak integration */ - } - express() { - /* Express integration */ - } -} -``` - -### Interactive Components - -```typescript -// Partial Component (HTMX-based) -const Counter = partial(async () => { - return ( -
- -
- ); -}, "counter"); - -// Island Component (RPC-based) -const TodoApp = Reface.addIsland({ - name: "todo", - template: ({ rpc, rest }) => ( -
- - -
- ), - rpc: { - addTodo: async ({ args }) => { - /* RPC handler */ - }, - }, - rest: { - "get|/list": async (req) => { - /* REST handler */ - }, - }, -}); -``` - -## Module Structure - -``` -@reface/ -├── core/ # Core composition engine -│ └── RefaceComposer # Template composition -│ -├── framework/ # Reface framework -│ ├── server/ # Deno server -│ ├── router/ # Routing system -│ └── static/ # Static files -│ -├── interactive/ # Interactive components -│ ├── partials/ # HTMX components -│ └── islands/ # RPC components -│ -└── plugins/ # Official plugins -``` - -## Development Plans - -### Near Future - -1. **Framework Layer** - - - Full server integration - - Advanced routing - - Middleware system - - Static optimization - -2. **Islands Architecture** - - - Enhanced RPC system - - State management - - TypeScript integration - - Development tools - -3. **Build System** - - Asset optimization - - Code splitting - - Tree shaking - - Bundle analysis diff --git a/docs/components.md b/docs/components.md deleted file mode 100644 index 6c26b729..00000000 --- a/docs/components.md +++ /dev/null @@ -1,158 +0,0 @@ -# Components - -RefaceComposer provides a component system for building reusable templates. - -## Basic Components - -### Function Components - -```typescript -// Simple component -function Button({ text }: { text: string }) { - return ; -} - -// Usage - - - ); -}, "counter"); - -// Usage -; -``` - -### HTMX Integration - -```typescript -// Default click trigger -const Button = partial(async () => { - return ; -}, "button"); - -// Custom trigger with delay -const SearchBox = partial(async () => { - return ( -
- - -
- ); -}, "search"); - -// Form submission -const Form = partial(async () => { - return ( -
- - -
- ); -}, "form"); -``` - -## State Management - -### Local State - -```typescript -const TodoList = partial(async () => { - const todos = await fetch("/api/todos").then((r) => r.json()); - - return ( -
-
    - {todos.map((todo) => ( -
  • - {todo.title} - -
  • - ))} -
-
- ); -}, "todo-list"); -``` - -### Shared State - -```typescript -const CartCounter = partial(async () => { - const count = await getCartCount(); - return {count} items; -}, "cart-counter"); - -const AddToCart = partial(async () => { - return ( - - ); -}, "add-to-cart"); -``` - -## Implementation Details - -### Partial Registration - -```typescript -// Partials are automatically registered during render -const composer = new RefaceComposer(); -composer.use(new PartialsPlugin()); - -// Each partial gets a unique identifier -
- - -
-``` - -### HTMX Attributes - -```typescript -// Trigger generates HTMX attributes -const trigger = Counter.trigger("click"); -// Results in: -// hx-get="/reface-partial/counter" -// hx-target="[data-partial='counter']" -// hx-trigger="click" - -// Custom configuration -const trigger = SearchBox.trigger({ - event: "keyup", - modifiers: { - delay: 500, - from: "input", - }, -}); -``` - -### Server Integration - -```typescript -// Partial handler is called on HTMX request -const handler = composer.getPlugin(PartialsPlugin)?.getHandler("counter"); -const result = await handler(); -// Result is used to update the partial -``` - -## Best Practices - -1. **Component Design** - - - Keep partials focused - - Clear state management - - Proper error handling - - Loading states - -2. **Performance** - - - Minimal updates - - Efficient triggers - - Optimized responses - - Cache when possible - -3. **User Experience** - - - Loading indicators - - Error feedback - - Progressive enhancement - - Fallback behavior - -4. **Security** - - Input validation - - CSRF protection - - Rate limiting - - Error handling diff --git a/docs/plugins.md b/docs/plugins.md deleted file mode 100644 index 01b347bc..00000000 --- a/docs/plugins.md +++ /dev/null @@ -1,209 +0,0 @@ -# Plugins - -RefaceComposer's plugin system allows extending the template composition -process. - -## Core Plugin System - -### Basic Plugin Structure - -```typescript -import type { IPlugin } from "@reface/core"; - -class CustomPlugin implements IPlugin { - name = "custom"; - - setup(composer: RefaceComposer) { - const manager = composer.getRenderManager(); - // Plugin initialization - } -} - -// Usage -const composer = new RefaceComposer(); -composer.use(new CustomPlugin()); -``` - -## Official Plugins - -### Styled Plugin - -CSS-in-JS support with type safety: - -```typescript -import { StyledPlugin } from "@reface/plugins/styled"; - -const composer = new RefaceComposer(); -composer.use(new StyledPlugin()); - -// Create styled component -const Button = styled.button` - & { - background: blue; - color: white; - } - - &:hover { - background: darkblue; - } -`; - -// Extend existing component -const PrimaryButton = styled(Button)` - & { - padding: 1rem 2rem; - border-radius: 4px; - } -`; -``` - -### Partials Plugin - -Interactive components with HTMX integration: - -```typescript -import { PartialsPlugin } from "@reface/plugins/partials"; - -const composer = new RefaceComposer(); -composer.use(new PartialsPlugin()); - -// Create interactive component -const Counter = partial(async () => { - const count = 0; - return ( -
- {count} - -
- ); -}, "counter"); - -// With custom trigger -const SearchBox = partial(async () => { - return ( -
- - -
- ); -}, "search"); -``` - -## Plugin Interface - -```typescript -interface IPlugin { - name: string; - setup(composer: RefaceComposer): void | Promise; -} -``` - -## Render Pipeline Hooks - -```typescript -class LoggerPlugin implements IPlugin { - name = "logger"; - - setup(composer: RefaceComposer) { - const manager = composer.getRenderManager(); - - // Before render hook - manager.on("render.render.start", ({ template }) => { - console.log("Starting render:", template); - }); - - // After render hook - manager.on("render.render.end", ({ html }) => { - console.log("Rendered HTML:", html); - }); - } -} -``` - -### Available Hooks - -- render.render.start/end - Full render cycle -- render.template.start/end - Template processing -- render.child.start/end - Child element processing -- render.children.start/end - Multiple children processing -- render.attributes.start/end - Attribute handling -- render.class.start/end - Class attribute processing -- render.style.start/end - Style attribute processing - -## Plugin Storage - -```typescript -class StatePlugin implements IPlugin { - name = "state"; - - setup(composer: RefaceComposer) { - const manager = composer.getRenderManager(); - - // Store plugin data - manager.store.set("state", { count: 0 }); - - // Access plugin data - const state = manager.store.get("state"); - } -} -``` - -## Best Practices - -1. **Plugin Design** - - - Single responsibility - - Clear initialization - - Proper error handling - - TypeScript support - -2. **Performance** - - - Minimal overhead - - Efficient hooks - - Resource cleanup - - Caching when possible - -3. **Integration** - - - Plugin dependencies - - Version compatibility - - Documentation - - Examples - -4. **Testing** - - Unit tests - - Integration tests - - Performance tests - - Error scenarios - -## Development Guide - -1. **Setup** - - - Create plugin class - - Implement IPlugin interface - - Define clear API - - Add TypeScript types - -2. **Implementation** - - - Add render hooks - - Handle errors - - Add cleanup - - Optimize performance - -3. **Documentation** - - - API reference - - Usage examples - - Configuration options - - Best practices - -4. **Distribution** - - Package structure - - Dependencies - - Version management - - Release notes diff --git a/docs/styling.md b/docs/styling.md deleted file mode 100644 index d6116d41..00000000 --- a/docs/styling.md +++ /dev/null @@ -1,201 +0,0 @@ -# Styling - -RefaceComposer provides CSS-in-JS styling through the Styled Plugin. - -## Basic Usage - -### Simple Styled Component - -```typescript -import { styled } from "@reface/plugins/styled"; - -const Button = styled.button` - & { - background: blue; - color: white; - padding: 8px 16px; - } - - &:hover { - background: darkblue; - } -`; - -// Usage -; -``` - -### Component Extension - -```typescript -const BaseButton = styled.button` - & { - padding: 8px 16px; - border: none; - border-radius: 4px; - } -`; - -const PrimaryButton = styled(BaseButton)` - & { - background: blue; - color: white; - } -`; - -const SecondaryButton = styled(BaseButton)` - & { - background: gray; - color: white; - } -`; -``` - -## CSS Features - -### Nested Selectors - -```typescript -const Card = styled.div` - & { - padding: 16px; - border: 1px solid #eee; - } - - & h2 { - margin: 0; - color: #333; - } - - & p { - color: #666; - } - - & .footer { - margin-top: 16px; - border-top: 1px solid #eee; - } -`; -``` - -### Pseudo Classes - -```typescript -const Input = styled.input` - & { - border: 1px solid #ccc; - padding: 8px; - } - - &:focus { - border-color: blue; - outline: none; - } - - &::placeholder { - color: #999; - } - - &:disabled { - background: #f5f5f5; - } -`; -``` - -### Media Queries - -```typescript -const Container = styled.div` - & { - width: 100%; - padding: 16px; - } - - @media (min-width: 768px) { - & { - width: 750px; - margin: 0 auto; - } - } - - @media (min-width: 1200px) { - & { - width: 1170px; - } - } -`; -``` - -## Implementation Details - -### Class Generation - -```typescript -// Unique class names are automatically generated -const Button = styled.button`...`; -// Renders as: - -const Card = styled.div`...`; -// Renders as:
...
-``` - -### Style Collection - -```typescript -// Styles are automatically collected and added to -``` - -### CSS Parser - -- Replaces `&` with generated class name -- Handles nested selectors -- Processes media queries -- Maintains selector specificity - -## Best Practices - -1. **Component Design** - - - Keep styles component-scoped - - Use semantic class names - - Follow BEM-like nesting - - Avoid deep nesting - -2. **Performance** - - - Reuse base components - - Minimize style rules - - Use efficient selectors - - Share common styles - -3. **Maintainability** - - - Clear style structure - - Consistent patterns - - Documentation - - Type safety - -4. **Browser Support** - - Cross-browser testing - - Fallback styles - - Progressive enhancement - - Vendor prefixes diff --git a/docs/template.md b/docs/template.md deleted file mode 100644 index 9f09337c..00000000 --- a/docs/template.md +++ /dev/null @@ -1,603 +0,0 @@ -# Template API Documentation - -## Основное использование - -Template API предоставляет способ создания HTML-шаблонов с поддержкой атрибутов -и вложенного содержимого. - -В конечном итоге, Reface работает на уровне строк и генерирует чистый HTML, что -делает его идеальным для серверного рендеринга. JSX - это просто удобная обертка -для разработки, которая транслируется в те же вызовы Template API. - -### Создание шаблона - -Есть два способа получить Template для HTML-элементов: - -1. Создание через функцию createTemplate: - -```typescript -import { createTemplate } from "@reface/template"; - -// Базовое создание элемента -const div = createTemplate({ tag: "div" }); -const span = createTemplate({ tag: "span" }); -``` - -2. Использование готовых элементов из @reface/elements: - -```typescript -import { button, div, span } from "@reface/elements"; - -// Элементы уже готовы к использованию -div`Hello world`; //
Hello world
-button`Click me`; // -``` - -@reface/elements предоставляет готовые Template-функции для всех HTML-элементов, -что избавляет от необходимости создавать их вручную. - -### Принцип работы - -Template построен на концепции цепочки трансформаций: - -``` -createTemplateFactory() → createTemplate() → Template → Template → Template -(создание фабрики) (базовый (с атрибутами) (с доп. (с контентом) - шаблон) атрибутами) -``` - -Каждый вызов в цепочке создает новый экземпляр: - -```typescript -// 1. Создаем фабрику шаблонов -const buttonFactory = createTemplateFactory({ - type: "button", - transformer: (attrs, children) => createTemplate({ tag: "button", ... }), -}); - -// 2. Создаем базовый шаблон -const baseButton = buttonFactory({ tag: "button" }); - // Template - -// 3. Специализируем шаблон -const primaryButton = baseButton({ class: "primary" }); - // Новый Template с добавленными атрибутами - -// 4. Дальнейшая специализация -const largeButton = primaryButton({ size: "large" }); - // Еще один Template с накопленными атрибутами - -// 5. Финальное использование -largeButton`Click me`; // -``` - -### Правила использования - -Template поддерживает два типа вызовов: - -1. Передача атрибутов - через объект: - -```typescript -// Атрибуты накапливаются при каждом вызове -const btn = createTemplate({ class: "button" })( - // class="button" - { id: "submit" }, -)( - // class="button" id="submit" - { "data-type": "primary" }, -); // class="button" id="submit" data-type="primary" -``` - -2. Передача содержимого - через tagged template literal: - -```typescript -// Важно: каждый вызов с `` полностью заменяет предыдущее содержимое -const btn = div({ class: "button" })`First content`; -btn`New content`; // Предыдущее содержимое "First content" полностью заменено -``` - -### Работа с атрибутами - -Template предоставляет удобные способы работы с атрибутами: - -1. Классы можно передавать объектом с флагами: - -```typescript -div({ - class: { - button: true, - primary: true, - disabled: false, - large: someCondition, - }, -})`Click me`; //
Click me
-``` - -2. Стили передаются в camelCase: - -```typescript -div({ - style: { - backgroundColor: "red", - fontSize: "14px", - }, -})`Content`; //
Content
-``` - -3. Кавычки в атрибутах выбираются автоматически: - -```typescript -div({ - title: 'Contains "quotes"', - "data-message": "Simple text", -})`Content`; //
Content
-``` - -### Безопасность - -По умолчанию все строковые значения и переменные автоматически экранируются для -предотвращения XSS-атак: - -```typescript -const userInput = ''; -div`${userInput}`; //
<script>alert("XSS")</script>
- -// Переменные тоже безопасны -const message = "Hello"; -span`${message}`; // <b>Hello</b> -``` - -Для вставки доверенного HTML-контента используйте обертку html: - -```typescript -import { html } from "@reface/template"; - -const trusted = 'Важный текст'; -div`${html`${trusted}`}`; //
Важный текст
- -⚠️ Используйте html только для доверенного контента! -``` - -#### Продвинутые возможности - -#### Создание собственных типов Template - -```typescript -const buttonFactory = createTemplateFactory({ - type: "button", - - create: { - // template - это RawTemplate без callable сигнатуры - transform: ({ attrs, children, manager }) => ({ - tag: "button", - attributes: { - ...attrs, - class: manager.combineClasses("btn", attrs.class), - }, - children, - payload: { - clickCount: 0, - }, - }), - - defaults: { - attributes: { - class: "default-class", - type: "button", - }, - payload: { - clickCount: 0, - }, - }, - }, - - process: { - // template - это RawTemplate, содержит только данные - attributes: ({ oldAttrs, newAttrs, template, manager }) => ({ - ...oldAttrs, - ...newAttrs, - class: manager.combineClasses(oldAttrs.class, newAttrs.class), - }), - - children: ({ oldChildren, newChildren, template }) => { - return [...oldChildren, ...newChildren]; - }, - }, - - methods: { - // template - это RawTemplate, для работы с данными - incrementClicks: ({ template }) => { - template.payload.clickCount++; - return template; - }, - getClickCount: ({ template }) => template.payload.clickCount, - }, - - render: { - // template - это RawTemplate, только для чтения данных - template: ({ template, manager }) => { - return `${ - manager.renderChildren( - template.children, - ) - }`; - }, - - attributes: ({ attrs, template, manager }) => - manager.renderAttributes(attrs, { prefix: "data-" }), - - styles: ({ styles, template, manager }) => manager.renderStyles(styles), - - classes: ({ classes, template, manager }) => manager.renderClasses(classes), - }, -}); -``` - -Важно: - -1. Во всех методах параметр `template` является `RawTemplate` - это объект, - содержащий только данные шаблона, без возможности вызова. Callable сигнатура - (`template()` и template``) доступна только в финальном Template после - создания. - -2. RawTemplate хранит данные в нормализованном виде: - - `attributes` - обычные атрибуты - - `attributes.classes` - массив классов - - `attributes.styles` - объект стилей - - `children` - массив дочерних элементов - - `payload` - пользовательские данные - -Это позволяет удобно работать с данными внутри методов фабрики, а RenderManager -предоставляет утилиты для работы с этими нормализованными данными. - -Основные разделы API: - -1. `type` - идентификатор типа шаблона -2. `create` - настройки создания шаблона - - `transform({ attrs, children, manager })` - трансформация входных - параметров - - `defaults` - значения по умолчанию -3. `process` - обработка вызовов - - `attributes({ oldAttrs, newAttrs, template, manager })` - обработка - атрибутов - - `children({ oldChildren, newChildren, template })` - обработка содержимого -4. `methods` - методы экземпляра, получают `{ template }` -5. `render` - настройки рендеринга, все методы получают `{ template, manager }` - - `template({ template, manager })` - рендеринг всего шаблона - - `attributes({ attrs, template, manager })` - рендеринг атрибутов - - `styles({ styles, template, manager })` - рендеринг стилей - - `classes({ classes, template, manager })` - рендеринг классов - -RenderManager предоставляет полезные утилиты для работы с шаблонами: - -- combineClasses - объединение классов -- renderChildren - рендеринг дочерних элементов -- renderAttributes - рендеринг атрибутов -- renderStyles - рендеринг стилей -- renderClasses - рендеринг классов - -#### Пример: Создание styled компонентов - -Пример того, как можно использовать createTemplateFactory для создания -styled-components (уже реализовано в @reface/styled): - -```typescript -// 1. Создаем фабрику для styled компонентов -const styledFactory = createTemplateFactory({ - type: "styled", - - create: { - transform: ({ attrs, children, manager }) => { - // Парсим CSS из children и создаем уникальный класс - const css = parseCss(children); - const className = generateUniqueClassName(); - - return { - tag: attrs.tag || "div", - attributes: { - ...attrs, - class: manager.combineClasses(className, attrs.class), - }, - children: [], - payload: { - css, - className, - }, - }; - }, - }, - - render: { - template: ({ template, manager }) => { - // CSS добавится в head при рендеринге - return `<${template.tag} ${ - manager.renderAttributes( - template.attributes, - ) - }>${manager.renderChildren(template.children)} - `; - }, - }, -}); - -// 2. Создаем API для styled -const styled = { - div: (strings: TemplateStringsArray, ...values: any[]) => { - return styledFactory({ - tag: "div", - payload: { styles: strings }, - }); - }, - span: (strings: TemplateStringsArray, ...values: any[]) => { - return styledFactory({ - tag: "span", - payload: { styles: strings }, - }); - }, - // ... другие элементы -}; - -// Использование (уже доступно в @reface/styled) -const RedButton = styled.div` - & { - color: red; - padding: 10px; - } - - &:hover { - color: darkred; - } -`; - -RedButton`Click me!`; //
Click me!
-// + -``` - -⚠️ Примечание: Это упрощенный пример. Полная реализация styled-components уже -доступна в пакете @reface/styled. - -### Альтернативные способы создания - -1. Использование createTemplate без указания тега: - -```typescript -import { createTemplate } from "@reface/template"; - -// Создание шаблона без тега - будет использоваться DocumentFragment -const fragment = createTemplate({}); -fragment`Hello world`; // Hello world (без обертки) - -// Удобно для группировки элементов -fragment` - ${div`First`} - ${div`Second`} -`; //
First
Second
-``` - -## Типы - -### TemplatePayload - -Базовый интерфейс для пользовательских данных, который могут расширять плагины: - -```typescript -interface TemplatePayload { - // Базовые поля, которые могут использовать все шаблоны - [key: string]: any; -} -``` - -### RawTemplate - -Базовая структура данных шаблона: - -```typescript -interface RawTemplate< - Attributes = any, - Payload extends TemplatePayload = TemplatePayload, -> { - // Тип шаблона - type: string; - // HTML тег - tag?: string; - // Нормализованные атрибуты - attributes: { - // Обычные HTML атрибуты - [key: string]: any; - // Массив классов - classes?: string[]; - // Объект стилей - styles?: Record; - }; - // Массив дочерних элементов - children: any[]; - // Пользовательские данные - payload: Payload; -} -``` - -### Template - -Callable интерфейс для работы с шаблоном: - -```typescript -interface Template { - // Вызов с атрибутами - возвращает новый Template - (attributes: Attributes): Template; - - // Вызов с содержимым - возвращает новый Template - (strings: TemplateStringsArray, ...values: any[]): Template< - Attributes, - Payload - >; - - // Доступ к RawTemplate - raw: RawTemplate; -} -``` - -### TemplateFactory - -Функция для создания шаблонов с кастомной логикой: - -```typescript -interface TemplateFactory { - // Создание нового шаблона - (config: TemplateConfig): Template; - - // Тип создаваемых шаблонов - type: string; -} - -// Конфигурация для создания шаблона -interface TemplateConfig { - tag?: string; - attributes?: Attributes; - children?: any[]; - payload?: Payload; -} -``` - -### TemplateFactoryConfig - -Конфигурация для создания фабрики шаблонов: - -```typescript -interface TemplateFactoryConfig { - // Уникальный тип шаблона - type: string; - - // Настройки создания шаблона - create: { - // Трансформация входных параметров - transform: ({ - attrs: Attributes, - children: any[], - manager: RenderManager - }) => RawTemplate; - - // Значения по умолчанию - defaults?: { - attributes?: Attributes; - payload?: Payload; - }; - }; - - // Настройки обработки вызовов - process?: { - // Обработка атрибутов - attributes?: ({ - oldAttrs: Attributes, - newAttrs: Attributes, - template: RawTemplate, - manager: RenderManager - }) => Attributes; - - // Обработка children - children?: ({ - oldChildren: any[], - newChildren: any[], - template: RawTemplate - }) => any[]; - }; - - // Методы экземпляра - methods?: { - [key: string]: ({ - template: RawTemplate - }) => any; - }; - - // Настройки рендеринга - render?: { - // Рендеринг всего шаблона - template?: ({ - template: RawTemplate, - manager: RenderManager - }) => string; - - // Рендеринг атрибутов - attributes?: ({ - attrs: Attributes, - template: RawTemplate, - manager: RenderManager - }) => string; - - // Рендеринг стилей - styles?: ({ - styles: Record, - template: RawTemplate, - manager: RenderManager - }) => string; - - // Рендеринг классов - classes?: ({ - classes: string[], - template: RawTemplate, - manager: RenderManager - }) => string; - }; -} -``` - -Эти типы формируют основу системы шаблонов: - -1. `RawTemplate` - хранит данные в нормализованном виде -2. `Template` - предоставляет интерфейс для работы с шаблоном -3. `TemplateFactory` - создает шаблоны с кастомной логикой -4. `TemplateFactoryConfig` - конфигурация для создания фабрики шаблонов - -### JSX Поддержка - -@reface/jsx предоставляет возможность использовать JSX синтаксис с Template API: - -```typescript -import { createElement, Fragment } from "@reface/jsx"; -import { button, div } from "@reface/elements"; - -// JSX транслируется в вызовы template -const App = () => ( - <> -
- -
- -); - -// Эквивалентно: -const App = () => - div({ class: "container" })` - ${button({ type: "button" })`Click me`} - `; - -// Можно комбинировать JSX и Template API -const Header = () => ( -
{button({ class: "primary" })`Submit`}
-); - -// И наоборот -const Container = () => - div({ class: "container" })` - ${} - `; -``` - -JSX это просто синтаксический сахар, который транслируется в вызовы Template -API: - -1. `createElement` преобразует JSX в вызовы template -2. `Fragment` позволяет группировать элементы без обертки -3. Можно свободно комбинировать JSX и Template API в одном компоненте - -⚠️ Для использования JSX необходимо настроить TypeScript/Babel для работы с -@reface/jsx. - -```json -{ - "compilerOptions": { - "jsx": "react", - "jsxFactory": "createElement", - "jsxFragmentFactory": "Fragment" - } -} -``` diff --git a/website/utils/docs.tsx b/website/utils/docs.tsx index 825f89a2..8ff4c979 100644 --- a/website/utils/docs.tsx +++ b/website/utils/docs.tsx @@ -20,8 +20,9 @@ function generateDocsStructure(pages: Map): DocSection[] { const gettingStarted: DocSection = { title: "Getting Started", items: [ - { path: "readme", title: "Introduction" }, - { path: "architecture", title: "Architecture" }, + { path: "readme", title: "Reface" }, + { path: "getting-started", title: "Getting Started" }, + { path: "concepts", title: "Main Concepts" }, ], }; @@ -31,7 +32,7 @@ function generateDocsStructure(pages: Map): DocSection[] { }; for (const [path, page] of pages.entries()) { - if (path === "readme" || path === "architecture") continue; + if (gettingStarted.items.some((item) => item.path === path)) continue; core.items.push({ path,