GitHub

Custom Component Integration in flect

Integrating custom components into flect significantly enhances the framework's capabilities. By incorporating your own React components, you can tailor flect functionality to meet your specific needs.

flect Frontend Ecosystem

flect frontend ecosystem comprises two primary packages:

  • The flect Component Library: This package includes all of flect built-in components.
  • Prebuilt: This package is specifically designed for rendering page logic as a React application.

This structure promotes modularity and customization, allowing you to adjust the default styles and logic of flect components as needed.

Guide Overview

This guide outlines the steps to implement custom components by creating your own prebuilt package. We will demonstrate this process by developing a simple badge component.

Implementing Custom Components: A Step-by-Step Guide

1. Project Structure Setup

Begin by creating the project structure and installing necessary dependencies. For a project named "ui", use the Cookiecutter template with the following commands:

cookiecutter https://github.com/Chaoyingz/cokiecutter-flect-prebuilt
cd ui
pnpm install

This will set up a project using a standard Vite React-TS template and install the required dependencies.

2. Custom Component Development

Develop your custom badge component by editing the src/components/badge.tsx file. Insert the following code:

import { cn } from '@/lib/utils.ts'

interface BadgeProps {
  package: 'ui'
  type: 'badge'
  subType: 'badge'
  className?: string
  text: string
}

export const Badge = (props: BadgeProps) => {
  return (
    <div
      className={cn(
        'inline-flex rounded-md px-2.5 py-1 text-xs font-semibold bg-primary text-primary-foreground',
        props.className,
      )}
    >
      {props.text}
    </div>
  )
}

Ensure to specify the package, type, and subType attributes correctly, with package referring to your component's package name and type and subType referring to the component type.

3. ComponentResolver Implementation

The ComponentResolver locates and renders components in response to backend requests. Implement it in the src/components/component-resolver.tsx file as follows:

import { BadgeProps, Badge } from '@/components/badge'
import { ComponentResolver } from '@chaoying/flect'

type AnyComponentProps = BadgeProps

export const UIComponentResolver: ComponentResolver = (props: AnyComponentProps) => {
  switch (props.subType) {
    case 'badge':
      return <Badge {...props} />
    default:
      return null
  }
}
UIComponentResolver.package = 'ui'

4. Integrating the ComponentResolver

Update the src/app.tsx file to include the ComponentResolver:

import { flect, ActionResolverProvider, ComponentResolverProvider } from '@chaoying/flect'
import { UIComponentResolver } from '@/components/component-resolver'

function App() {
  return (
    <ActionResolverProvider resolver={flectActionResolver}>
      <ComponentResolverProvider resolver={flectComponentResolver}>
        <ComponentResolverProvider resolver={UIComponentResolver}>
          <flect />
        </ComponentResolverProvider>
      </ComponentResolverProvider>
    </ActionResolverProvider>
  )
}

export default App

5. Building the Component

Compile your component package with:

pnpm build

6. Python Integration

Incorporate your component into the flect Python project by adding the following to a components.py file:

from typing import Literal, Optional
from flect import components as c

class BaseUIComponent(c.Custom):
    package: Literal["ui"] = "ui"
    sub_type: Literal["badge"] = "badge"

class Badge(BaseUIComponent):
    class_name: Optional[str] = None
    text: str

7. Updating prebuilt_uri

Modify main.py to update the prebuilt_uri:

from flect import flect

from project import app as project_app

app = flect(
    project_app,
    prebuilt_uri={Your dist assets absolute path here e.g "/tmp/ui/dist/assets"},
)

8. Using the Custom Component

Your custom component is now ready for use within the flect application, just like any built-in component. For example:

from flect import PageResponse
from components import Badge

async def page():
    return PageResponse(
        body=Badge(text="Hello Badge!"),
    )

Upon starting the service, you will see a badge displaying "Hello Badge!" on your webpage.

custom-badge