bluefly / bluefly_ui_library
A collection of reusable UI components for Drupal and Experience Builder
Requires
- php: >=8.1
- drupal/components: ^3.0
- drupal/core: ^11
- drupal/eca: ^2.1
- drupal/experience_builder: ^0.3
Requires (Dev)
- drupal/coder: ^8.3
- drupal/drupal-extension: ^5.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
README
A TypeScript-based UI component library for Drupal, providing modern, accessible, and reusable components for building rich web applications.
Features
- TypeScript-first development
- Modern component architecture
- Full accessibility support
- Responsive design
- Theme customization
- Drupal integration
- CodeMirror integration
- Form integration
- Event handling
- Utility functions
Installation
npm install @bluefly/bfui-library
Usage
Import Components
import { PromptEditor, Modal, Card, ThresholdSlider } from '@bluefly/bfui-library';
Create a Prompt Editor
const editor = new PromptEditor({
id: 'prompt-editor',
name: 'prompt',
label: 'Enter your prompt',
description: 'Use Markdown for formatting',
value: '',
placeholder: 'Type your prompt here...',
mode: 'markdown',
theme: 'light',
height: '300px',
max_tokens: 4096,
show_token_count: true,
show_context: true,
context_items: [
{
id: 'user_context',
label: 'User Context',
description: 'Insert user information',
type: 'text'
},
{
id: 'code_example',
label: 'Code Example',
description: 'Insert code snippet',
type: 'code'
}
],
required: true
});
document.querySelector('#editor-container').appendChild(editor.getElement());
Create a Modal
const modal = new Modal({
id: 'example-modal',
title: 'Example Modal',
content: '<p>This is an example modal.</p>',
footer: '<button class="button">Close</button>',
size: 'medium',
dismissible: true,
closeOnEsc: true,
closeOnOutsideClick: true
});
document.querySelector('#modal-container').appendChild(modal.getElement());
Create a Card
const card = new Card({
id: 'example-card',
title: 'Example Card',
content: '<p>This is an example card.</p>',
footer: '<button class="button">Action</button>',
image: 'path/to/image.jpg',
variant: 'elevated',
size: 'medium'
});
document.querySelector('#card-container').appendChild(card.getElement());
Create a Threshold Slider
const slider = new ThresholdSlider({
id: 'example-slider',
name: 'threshold',
label: 'Threshold',
min: 0,
max: 100,
step: 1,
value: 50,
marks: [
{ value: 0, label: '0%' },
{ value: 50, label: '50%' },
{ value: 100, label: '100%' }
],
show_value: true,
color: 'primary',
size: 'medium'
});
document.querySelector('#slider-container').appendChild(slider.getElement());
Development
Prerequisites
- Node.js 14+
- npm 6+
- TypeScript 4+
Setup
Clone the repository:
git clone https://github.com/bluefly/bfui-library.git cd bfui-library
Install dependencies:
npm install
Build the library:
npm run build
Run tests:
npm test
Run linter:
npm run lint
Format code:
npm run format
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and linting
- Submit a pull request
License
This project is licensed under the GPL-2.0-or-later License - see the LICENSE file for details.
Permissions:
- administer bluefly ui library: Configure or manage Bluefly UI Library assets and components.
Extending (Drupal 11 Best Practices):
- Use DI (dependency injection) and typed arguments (PHP 8+) in your custom services.
- Register your custom Twig extensions (or trusted callbacks) via a services.yml file.
- Use a .libraries.yml file to register your UI assets (CSS, JS, etc.) and ensure they are reusable.
- Avoid duplicating core or contrib functionality; leverage Drupal's theme system and Twig.
Integration Testing: Drupal & React
This module supports both manual and automated integration testing to ensure React components render and function correctly within Drupal.
Manual Checklist
- [ ] Build React components (
npm run build
in BFUI) - [ ] Ensure Drupal loads the built JS/CSS assets
- [ ] Place a React component via a Drupal block or field and verify it renders
- [ ] Pass all documented props from Drupal to React and verify correct rendering
- [ ] Test both server-side and client-side rendering (if applicable)
- [ ] Confirm errors in React are logged and do not break Drupal pages
- [ ] Check rendered components for accessibility compliance
Automated Testing
Automated integration tests should be placed in the tests/
directory at the module root. Example test types:
- PHPUnit Functional Test: Ensures a React block renders on a Drupal page.
- Jest/React Testing Library: Validates React components with Drupal-provided props (in BFUI).
Example: PHPUnit Functional Test
// tests/src/Functional/ReactBlockTest.php
public function testReactBlockRenders() {
$this->drupalPlaceBlock('my_react_block');
$this->drupalGet('<front>');
$this->assertSession()->elementExists('css', '.my-react-component');
}
Example: Jest Test (in BFUI)
// __tests__/DrupalIntegration.test.tsx
import { render } from '@testing-library/react';
import { MyComponent } from '../src/components/MyComponent';
test('renders with Drupal-provided props', () => {
const { getByText } = render(<MyComponent label="From Drupal" />);
expect(getByText('From Drupal')).toBeInTheDocument();
});
See the tests/
directory for more examples and to add your own integration tests.
ModelRegistryTable (React)
A production-grade React component for displaying and managing LLM models in the Drupal admin UI. Supports advanced actions (reload, unload, logs, rollback) and modal dialogs.
Usage
Register the component in your Drupal admin page or block:
- Use the llm_platform route
/admin/llm/models-react
to render the component in a page. - The component is mounted at
#bfui-model-registry-root
and loaded via thebluefly_ui_library/bfui
library.
- Use the llm_platform route
Extend the component for additional actions or integration:
- Add API calls for reload, unload, logs, and rollback in
ModelRegistryTable.tsx
. - Integrate with ECA triggers or Insights dashboards by emitting events or calling Drupal endpoints.
- Add API calls for reload, unload, logs, and rollback in
See the source in
src/Component/ModelRegistryTable.tsx
for details.