Responsive Widgets Implementation Guide
Complete guide for adapting widgets to work with the responsive system
Responsive Widgets Implementation Guide
This document describes how to adapt existing widgets to work with the new responsive system.
Overview
The responsive system allows widgets to have different properties (position, size, styles) for each breakpoint. To facilitate this adaptation, we have created a ResponsiveWidgetPropsDirective that provides helper methods to access these properties.
Steps to Adapt a Widget
1. Import Required Components
In the widget component (.ts file):
import {
ResponsiveWidgetPropsDirective,
// Other required directives...
} from 'libs/shared-ui/src/lib/directives';
import {
BreakpointKey,
ResponsiveWidgetService,
// Other models and services...
} from '@libs-foundational/core-models';
2. Add the Directive to Component Imports
@Component({
// ...
imports: [
// Existing imports...
ResponsiveWidgetPropsDirective,
],
// ...
})
3. Add the activeBreakpoint Input
export class MyWidgetComponent implements OnInit {
// Existing inputs...
@Input() activeBreakpoint: BreakpointKey = 'base';
// Rest of component...
}
4. Modify the HTML Template
Add the directive and its bindings:
<div class="widget-container" <!-- Other attributes and events... -->
libResponsiveWidgetProps [widget]="widget" [activeBreakpoint]="activeBreakpoint"
#widgetProps="responsiveWidgetProps">
<!-- Widget content... -->
</div>
5. Replace Direct Property Access with Directive Methods
In the HTML template, replace:
[resizeMinWidth]="widget?.size?.minWidth || 20"
With:
[resizeMinWidth]="widgetProps.getSizeProp('minWidth') || 20"
6. Update Manipulation Methods
For manipulating widgets (drag, resize, etc.), use ResponsiveWidgetService:
onDragEnd(event: any): void {
if (this.isPreview) return;
const { x, y } = event;
const responsiveWidgetService = inject(ResponsiveWidgetService);
if (responsiveWidgetService.isResponsiveWidget(this.widget)) {
// For responsive widgets, update position for current breakpoint
let updatedWidget = responsiveWidgetService.setWidgetPropertyForBreakpoint(
this.widget,
'position.x',
Math.round(x / 8) * 8,
this.activeBreakpoint
);
// More updates...
this.widgetChange.emit(updatedWidget);
} else {
// For non-responsive widgets, direct update
const updatedPosition = {
x: Math.round(x / 8) * 8,
y: Math.round(y / 8) * 8,
constrainToParent: (this.widget.position as Position).constrainToParent,
};
this.updateWidget({
position: updatedPosition,
});
}
}
Visualization and Style Calculation
To generate visual styles for a widget:
readonly containerStyles = computed(() => {
const widgetSize = this.responsiveWidgetService.getWidgetSize(
this.widget,
this.activeBreakpoint
);
const widgetPosition = this.responsiveWidgetService.getWidgetPosition(
this.widget,
this.activeBreakpoint
);
return {
width: `${widgetSize.width}px`,
height: `${widgetSize.height}px`,
position: 'absolute',
left: `${widgetPosition.x}px`,
top: `${widgetPosition.y}px`,
// Other styles...
};
});
Available Helper Methods
The ResponsiveWidgetPropsDirective provides these helper methods:
Size Properties
// Get size properties for current breakpoint
widgetProps.getSizeProp('width')
widgetProps.getSizeProp('height')
widgetProps.getSizeProp('minWidth')
widgetProps.getSizeProp('minHeight')
widgetProps.getSizeProp('maxWidth')
widgetProps.getSizeProp('maxHeight')
Position Properties
// Get position properties for current breakpoint
widgetProps.getPositionProp('x')
widgetProps.getPositionProp('y')
widgetProps.getPositionProp('constrainToParent')
Style Properties
// Get style properties for current breakpoint
widgetProps.getStyleProp('backgroundColor')
widgetProps.getStyleProp('borderRadius')
widgetProps.getStyleProp('opacity')
// ... any custom style property
Complete Property Objects
// Get complete objects for current breakpoint
widgetProps.getSize() // Returns complete Size object
widgetProps.getPosition() // Returns complete Position object
widgetProps.getStyles() // Returns complete styles object
Responsive Widget Service Methods
The ResponsiveWidgetService provides these key methods:
Widget Type Detection
// Check if widget supports responsive properties
responsiveWidgetService.isResponsiveWidget(widget)
Property Getters
// Get properties for specific breakpoint
responsiveWidgetService.getWidgetSize(widget, breakpoint)
responsiveWidgetService.getWidgetPosition(widget, breakpoint)
responsiveWidgetService.getWidgetStyles(widget, breakpoint)
Property Setters
// Set properties for specific breakpoint
responsiveWidgetService.setWidgetPropertyForBreakpoint(
widget,
'size.width',
newValue,
breakpoint
)
responsiveWidgetService.setWidgetPropertyForBreakpoint(
widget,
'position.x',
newValue,
breakpoint
)
Breakpoint System
The responsive system supports these breakpoints:
base- Default/mobile (0px+)sm- Small tablets (640px+)md- Medium tablets (768px+)lg- Large tablets/small desktops (1024px+)xl- Desktops (1280px+)2xl- Large desktops (1536px+)
Adapted Widgets
The following widgets have already been adapted to the responsive system:
- ContainerWidgetComponent
- VideoWidgetComponent
All other widgets should follow this guide to adapt to the new responsive system.
Best Practices
1. Always Check Widget Type
if (responsiveWidgetService.isResponsiveWidget(this.widget)) {
// Use responsive methods
} else {
// Use traditional methods
}
2. Use Computed Styles
readonly containerStyles = computed(() => {
// Calculate styles based on current breakpoint
return this.calculateResponsiveStyles();
});
3. Handle Breakpoint Changes
// Listen for breakpoint changes
effect(() => {
const breakpoint = this.activeBreakpoint();
// Update widget display based on new breakpoint
this.updateWidgetDisplay();
});
4. Preserve Backward Compatibility
// Always support both responsive and non-responsive widgets
const size = responsiveWidgetService.isResponsiveWidget(this.widget)
? responsiveWidgetService.getWidgetSize(this.widget, this.activeBreakpoint)
: this.widget.size;
Testing Responsive Widgets
1. Test All Breakpoints
- Verify widget displays correctly at each breakpoint
- Check that properties change appropriately
- Ensure smooth transitions between breakpoints
2. Test Property Updates
- Drag and drop at different breakpoints
- Resize at different breakpoints
- Style changes at different breakpoints
3. Test Backward Compatibility
- Ensure non-responsive widgets still work
- Verify no breaking changes for existing widgets
Troubleshooting
Common Issues
1. Widget Not Responding to Breakpoint Changes
Solution: Ensure activeBreakpoint input is properly bound and the directive is correctly applied.
2. Properties Not Updating
Solution: Check that you're using the directive methods (widgetProps.getSizeProp()) instead of direct property access.
3. Styles Not Applying
Solution: Verify that computed styles are properly reactive and use the responsive service methods.
Migration Checklist
- Import
ResponsiveWidgetPropsDirectiveandResponsiveWidgetService - Add directive to component imports
- Add
activeBreakpointinput - Apply directive to template
- Replace direct property access with directive methods
- Update manipulation methods to use responsive service
- Add computed styles for responsive display
- Test at all breakpoints
- Verify backward compatibility
Summary
The responsive widget system provides a powerful way to create widgets that adapt to different screen sizes and breakpoints. By following this guide, you can ensure your widgets work seamlessly across all device types while maintaining backward compatibility with existing non-responsive widgets.
The key is to use the provided directive and service methods instead of direct property access, and always check whether a widget supports responsive properties before applying responsive logic.