Overview
Centinela provides specialized input components for common use cases including file uploads (InputFile), color pickers with transparency (InputColor), and status chips (ChipCustom). These components extend Material-UI functionality with custom styling and behavior.
A file upload component with visual feedback, specifically designed for image uploads.
Import
import InputFile from '../../../components/InputFile/InputFile'
Props
title
string
default:"Subir Archivo"
Button label text for the file upload button.
Callback function triggered when a file is selected. Receives the event object.fnc={(event) => {
const file = event.target.files[0]
console.log('Selected file:', file)
}}
Currently selected file object to display. Used for controlled component behavior.fileSelected={currentFile}
Usage Examples
Basic File Upload
import { useState } from 'react'
import InputFile from '../../../components/InputFile/InputFile'
function ImageUploader() {
const [file, setFile] = useState(null)
const handleFileChange = (event) => {
const selectedFile = event.target.files[0]
setFile(selectedFile)
}
return (
<InputFile
title="Subir Imagen"
fnc={handleFileChange}
fileSelected={file}
/>
)
}
Upload with Validation
function ValidatedImageUpload() {
const [file, setFile] = useState(null)
const [error, setError] = useState('')
const handleFileChange = (event) => {
const selectedFile = event.target.files[0]
// Validate file size (max 5MB)
if (selectedFile.size > 5 * 1024 * 1024) {
setError('File size must be less than 5MB')
return
}
// Validate file type
if (!selectedFile.type.startsWith('image/')) {
setError('Only image files are allowed')
return
}
setError('')
setFile(selectedFile)
}
return (
<div>
<InputFile
title="Upload Logo"
fnc={handleFileChange}
fileSelected={file}
/>
{error && <p className="text-red-600 mt-2">{error}</p>}
</div>
)
}
Upload with Preview
function ImageUploadWithPreview() {
const [file, setFile] = useState(null)
const [preview, setPreview] = useState(null)
const handleFileChange = (event) => {
const selectedFile = event.target.files[0]
setFile(selectedFile)
// Create preview URL
if (selectedFile) {
const reader = new FileReader()
reader.onloadend = () => {
setPreview(reader.result)
}
reader.readAsDataURL(selectedFile)
}
}
return (
<div className="flex flex-col gap-4">
<InputFile
title="Select Image"
fnc={handleFileChange}
fileSelected={file}
/>
{preview && (
<div className="border rounded p-2">
<img
src={preview}
alt="Preview"
className="max-w-xs max-h-64 object-contain"
/>
</div>
)}
</div>
)
}
Component Source
Location: ~/workspace/source/src/components/InputFile/InputFile.jsx
InputFile accepts only image files by default (accept=‘image/*’). The component displays the selected filename below the upload button.
A color picker component with transparency/opacity control, outputting RGBA color values.
Import
import InputColor from '../../../components/InputColor/InputColor'
Props
Callback function that receives the updated RGBA color string.updateBackground={(rgbaColor) => {
console.log('New color:', rgbaColor)
// Example output: "rgba(255, 0, 0, 0.5)"
}}
Initial color value in RGBA format.backgroundText="rgba(0, 0, 0, 1)"
Usage Examples
Basic Color Picker
import { useState } from 'react'
import InputColor from '../../../components/InputColor/InputColor'
function ColorSelector() {
const [backgroundColor, setBackgroundColor] = useState('rgba(0, 0, 0, 1)')
return (
<div>
<InputColor
updateBackground={setBackgroundColor}
backgroundText={backgroundColor}
/>
<div
className="mt-4 p-4 rounded"
style={{ backgroundColor }}
>
Preview
</div>
</div>
)
}
Chart Background Configuration
import InputColor from '../../../components/InputColor/InputColor'
import { useForm } from 'react-hook-form'
function ChartConfig() {
const { setValue, watch } = useForm({
defaultValues: {
backgroundColor: 'rgba(255, 255, 255, 0.8)'
}
})
const bgColor = watch('backgroundColor')
return (
<div className="flex flex-col gap-3">
<InputColor
updateBackground={(color) => setValue('backgroundColor', color)}
backgroundText={bgColor}
/>
<div
className="chart-preview p-6 rounded-lg"
style={{ backgroundColor: bgColor }}
>
<h3>Chart Title</h3>
{/* Chart content */}
</div>
</div>
)
}
function ThemeEditor() {
const [primaryColor, setPrimaryColor] = useState('rgba(59, 130, 246, 1)')
const [secondaryColor, setSecondaryColor] = useState('rgba(168, 85, 247, 1)')
const [bgColor, setBgColor] = useState('rgba(255, 255, 255, 0.95)')
return (
<div className="flex flex-col gap-4">
<div>
<label className="block mb-2 font-semibold">Primary Color</label>
<InputColor
updateBackground={setPrimaryColor}
backgroundText={primaryColor}
/>
</div>
<div>
<label className="block mb-2 font-semibold">Secondary Color</label>
<InputColor
updateBackground={setSecondaryColor}
backgroundText={secondaryColor}
/>
</div>
<div>
<label className="block mb-2 font-semibold">Background Color</label>
<InputColor
updateBackground={setBgColor}
backgroundText={bgColor}
/>
</div>
</div>
)
}
Component Source
Location: ~/workspace/source/src/components/InputColor/InputColor.jsx
InputColor outputs colors in RGBA format, allowing for transparency control through the opacity slider. The color is converted from HEX to RGB internally.
ChipCustom
A customizable chip/badge component with color variants and action icons.
Import
import ChipCustom from '../../../components/ChipCustom/ChipCustom'
Props
Text content to display in the chip.
Color variant for the chip. Options:
default - Gray background
success - Green background
error - Red background
Click handler for the chip label. Makes the chip clickable.onClick={() => console.log('Chip clicked')}
Shows a delete icon and calls this function when clicked.onDelete={() => handleRemove(id)}
Shows an info icon and calls this function when clicked.onInfo={() => showDetails(id)}
Usage Examples
Basic Chips
import ChipCustom from '../../../components/ChipCustom/ChipCustom'
function StatusDisplay() {
return (
<div className="flex gap-2">
<ChipCustom label="Pending" color="default" />
<ChipCustom label="Active" color="success" />
<ChipCustom label="Error" color="error" />
</div>
)
}
Clickable Chips
function FilterChips() {
const [selectedFilter, setSelectedFilter] = useState('all')
return (
<div className="flex gap-2">
<ChipCustom
label="All"
color={selectedFilter === 'all' ? 'success' : 'default'}
onClick={() => setSelectedFilter('all')}
/>
<ChipCustom
label="Active"
color={selectedFilter === 'active' ? 'success' : 'default'}
onClick={() => setSelectedFilter('active')}
/>
<ChipCustom
label="Inactive"
color={selectedFilter === 'inactive' ? 'success' : 'default'}
onClick={() => setSelectedFilter('inactive')}
/>
</div>
)
}
function TagManager() {
const [tags, setTags] = useState(['sensor-a', 'high-priority', 'monitored'])
const removeTag = (tagToRemove) => {
setTags(tags.filter(tag => tag !== tagToRemove))
}
return (
<div className="flex flex-wrap gap-2">
{tags.map(tag => (
<ChipCustom
key={tag}
label={tag}
color="success"
onDelete={() => removeTag(tag)}
/>
))}
</div>
)
}
Chips with Info Action
function AlarmChips() {
const alarms = [
{ id: 1, name: 'Temperature High', severity: 'error' },
{ id: 2, name: 'Pressure Normal', severity: 'success' },
]
const showAlarmDetails = (alarmId) => {
console.log('Show details for alarm:', alarmId)
}
return (
<div className="flex flex-wrap gap-2">
{alarms.map(alarm => (
<ChipCustom
key={alarm.id}
label={alarm.name}
color={alarm.severity}
onInfo={() => showAlarmDetails(alarm.id)}
/>
))}
</div>
)
}
Multi-Action Chips
function SensorTags() {
const [sensors, setSensors] = useState([
{ id: 1, name: 'Temp Sensor A', status: 'success' },
{ id: 2, name: 'Flow Sensor B', status: 'error' },
])
const viewSensor = (id) => {
console.log('View sensor:', id)
}
const removeSensor = (id) => {
setSensors(sensors.filter(s => s.id !== id))
}
const showSensorInfo = (id) => {
console.log('Show info for sensor:', id)
}
return (
<div className="flex flex-wrap gap-2">
{sensors.map(sensor => (
<ChipCustom
key={sensor.id}
label={sensor.name}
color={sensor.status}
onClick={() => viewSensor(sensor.id)}
onDelete={() => removeSensor(sensor.id)}
onInfo={() => showSensorInfo(sensor.id)}
/>
))}
</div>
)
}
Component Source
Location: ~/workspace/source/src/components/ChipCustom/ChipCustom.jsx
Color Variants
<ChipCustom label="Default" color="default" />
// Gray background (bg-gray-500)
Common Use Cases
Best Practices
- Validation: Always validate file size and type before processing
- User Feedback: Show preview or filename to confirm selection
- Error Handling: Provide clear error messages for invalid files
- Accessibility: Ensure the label is descriptive and meaningful
- Initial Values: Always provide a valid RGBA string as initial value
- Preview: Show a live preview of the selected color
- Contrast: Consider text contrast when using backgrounds
- Transparency: Remember that transparency affects overlapping elements
ChipCustom
- Color Semantics: Use colors consistently (success=positive, error=negative)
- Interactive States: Only make chips clickable when there’s an action
- Icon Usage: Don’t combine too many actions on a single chip
- Spacing: Use flex gap for proper chip spacing in groups