Assignment editor with activity tracking for Hiyve -- rich text editing, due dates, time estimates, status management, per-user activity sessions, and cloud persistence.
npx @hiyve/cli login
npm install @hiyve/react-assignments
import { AssignmentEditor } from '@hiyve/react-assignments';
import { HiyveProvider } from '@hiyve/react';
function TeamAssignment() {
return (
<HiyveProvider generateRoomToken={generateRoomToken}>
<AssignmentEditor
title="Sprint Task"
enableAutoSave
onSave={(assignment) => console.log('Saved:', assignment.id)}
onStatusChange={(status) => console.log('Status:', status)}
/>
</HiyveProvider>
);
}
| Component | Description |
|---|---|
AssignmentEditor |
Full-featured assignment editor with rich text, metadata controls, activity tracking, and auto-save |
AssignmentViewer |
Read-only renderer for an AssignmentFile (or raw JSONContent); supports file embeds |
AssignmentToolbar |
Standalone formatting toolbar (bold, italic, headings, lists, tables, etc.) |
AssignmentMetadata |
Metadata panel for due date, time estimate, status, and user assignment |
ActivityControlPanel |
Per-user activity controls -- session timer, progress slider, status, and notes |
ActivityDashboard |
Activity overview with stats cards, average progress, and per-user activity table |
CreateAssignmentDialog |
Dialog for naming a new assignment before creation |
EmbedProvider |
Context provider that wires the file picker / file resolver used by the assignment-embed node |
| Prop | Type | Default | Description |
|---|---|---|---|
open |
boolean |
-- | Whether the dialog is open |
onClose |
() => void |
-- | Called when the dialog is closed |
onCreate |
(fileId: string, fileName: string, fileData: AssignmentFile) => void |
-- | Called after the assignment file is created |
defaultName |
string |
'' |
Pre-filled assignment name |
isCreating |
boolean |
-- | External creating state |
error |
string |
-- | External error message |
labels |
Partial<CreateAssignmentDialogLabels> |
-- | Custom text labels |
import { CreateAssignmentDialog } from '@hiyve/react-assignments';
<CreateAssignmentDialog
open={showDialog}
onClose={() => setShowDialog(false)}
onCreate={(fileId, fileName, fileData) => {
console.log('Created:', fileId);
setShowDialog(false);
}}
defaultName="Design Review"
/>
| Hook | Description |
|---|---|
useAssignmentEditor |
Sets up a rich text editor instance with extensions and content tracking |
useAssignmentPersistence |
Manages auto-save, manual save, and save status tracking |
useActivityTracker |
Manages per-user activity sessions with timer, notes, and duration tracking |
| Export | Description |
|---|---|
createAssignmentFile |
Creates and uploads a new assignment file to the server. Returns { fileId, fileData } |
generateAssignmentId |
Creates a unique assignment identifier |
isContentEmpty |
Checks whether editor content is empty or whitespace-only |
getStatusColor |
Returns the color for a given assignment status |
calculateTotalTime |
Sums total time from activity sessions |
formatDuration |
Formats minutes as human-readable duration ("2h 30m") |
getUserActivity |
Gets or creates a default user activity record |
updateUserActivity |
Immutably updates a user's activity data |
addSession |
Adds an activity session and recalculates totals |
getActivityStats |
Computes team stats (active users, total time, average progress) |
getAssignmentEditorStyles |
Returns CSS styles for the editor area |
| Prop | Type | Default | Description |
|---|---|---|---|
title |
string |
'Assignment' |
Header title |
initialTitle |
string |
-- | Pre-filled title for the assignment |
initialContent |
JSONContent |
-- | Pre-filled editor content |
initialAssignment |
AssignmentFile |
-- | Pre-populated assignment data (populates all fields) |
placeholder |
string |
'Describe the assignment details...' |
Placeholder when editor is empty |
showHeader |
boolean |
true |
Show the panel header |
showToolbar |
boolean |
true |
Show the formatting toolbar |
showTitleInput |
boolean |
true |
Show the title input field |
showMetadata |
boolean |
false |
Show the metadata panel with due date, time, status, and assignees |
showTabs |
boolean |
false |
Show the tab bar (Editor / Activity / My Activity) |
maxHeight |
number | string |
-- | Maximum height before scrolling |
minHeight |
number | string |
-- | Minimum height of the editor |
disabled |
boolean |
false |
Disable the entire panel |
readOnly |
boolean |
false |
Make the editor read-only |
enableAutoSave |
boolean |
false |
Enable auto-save to file storage |
autoSaveInterval |
number |
3000 |
Auto-save interval in milliseconds |
fileId |
string |
-- | Existing file ID (for editing a saved assignment) |
fileLocation |
string |
'/Assignments' |
Storage folder path |
enableTableSupport |
boolean |
true |
Enable table editing |
enableTaskLists |
boolean |
true |
Enable task list (checkbox) support |
enableHighlight |
boolean |
true |
Enable text highlighting |
enableActivityTracking |
boolean |
false |
Enable per-user activity tracking with session timers |
labels |
Partial<AssignmentEditorLabels> |
-- | Label overrides for i18n |
icons |
Partial<AssignmentEditorIcons> |
-- | Icon overrides |
colors |
Partial<AssignmentEditorColors> |
-- | Color overrides |
styles |
Partial<AssignmentEditorStyles> |
-- | Style overrides |
sx |
SxProps<Theme> |
-- | MUI sx prop for the container |
onChange |
(content: JSONContent) => void |
-- | Called when content changes |
onTitleChange |
(title: string) => void |
-- | Called when the title changes |
onSave |
(assignment: AssignmentFile) => void |
-- | Called after a successful save |
onSaveError |
(error: Error) => void |
-- | Called when a save fails |
onAutoSave |
(fileId: string) => void |
-- | Called after a successful auto-save |
onFocus |
() => void |
-- | Called when editor is focused |
onBlur |
() => void |
-- | Called when editor is blurred |
onStatusChange |
(status: AssignmentStatus) => void |
-- | Called when assignment status changes |
AssignmentEditor exposes a ref for external control:
import { useRef } from 'react';
import { AssignmentEditor, type AssignmentEditorRef } from '@hiyve/react-assignments';
function AssignmentsPanel() {
const editorRef = useRef<AssignmentEditorRef>(null);
return (
<div>
<button
onClick={() => editorRef.current?.save()}
disabled={editorRef.current?.isSaving}
>
Save Now
</button>
<AssignmentEditor ref={editorRef} enableAutoSave />
</div>
);
}
The ref provides: save(), isSaving, hasUnsavedChanges, lastSaved, and fileId. File attachments are now managed inline via embed nodes (see Embedding Files).
For custom editor UIs, use the hooks independently:
import { useAssignmentEditor, useAssignmentPersistence, useActivityTracker } from '@hiyve/react-assignments';
function CustomAssignmentEditor() {
const { editor, content, isEmpty, getHTML, focus } = useAssignmentEditor({
placeholder: 'Describe the assignment details...',
onUpdate: (content) => console.log('Changed'),
});
const { startSession, endSession, currentSession } = useActivityTracker({
userId: currentUser.id,
});
// Render your own UI around the editor instance
}
Render an existing AssignmentFile (or just a JSONContent body) read-only — no toolbar, no editing, but with full embed support:
import { AssignmentViewer } from '@hiyve/react-assignments';
<AssignmentViewer
assignment={loadedAssignment}
resolveFile={async (fileId) => ({ url: await getSignedUrl(fileId) })}
onOpenEmbed={(embed) => openPreviewModal(embed.fileId)}
onActivityTick={(elapsedSeconds) => trackTimeSpent(elapsedSeconds)}
/>
| Prop | Type | Default | Description |
|---|---|---|---|
assignment |
AssignmentFile |
-- | Full assignment document; renders title + body. |
content |
JSONContent |
-- | Body content (used when assignment is omitted). |
title |
string |
-- | Override the rendered title. Defaults to assignment.title. |
hideTitle |
boolean |
false |
Hide the title row (body is always rendered). |
resolveFile |
EmbedFileResolver |
-- | Resolve a fileId to a renderable URL (image thumbnails etc.). |
onOpenEmbed |
EmbedOpenCallback |
-- | Called when the user clicks an embed; typically opens a preview modal. |
onActivityTick |
(elapsedSeconds: number) => void |
-- | Periodic tick while the viewer is mounted and visible. |
activityTickMs |
number |
30000 |
Tick interval in milliseconds. |
colors |
Partial<AssignmentEditorColors> |
-- | Color overrides; merged with theme defaults. |
minHeight |
number | string |
200 |
Minimum body height. |
maxHeight |
number | string |
-- | When set, the body scrolls. |
Inline file references are rendered through the assignment-embed TipTap node. Wrap your editor / viewer in <EmbedProvider> to wire the file picker + resolver:
import { AssignmentEditor, EmbedProvider } from '@hiyve/react-assignments';
<EmbedProvider
pickEmbed={async () => openFilePickerDialog()}
resolveFile={async (fileId) => ({ url: await getSignedUrl(fileId) })}
onOpenEmbed={(embed) => openPreviewModal(embed.fileId)}
>
<AssignmentEditor enableFileEmbeds title="Sprint Task" />
</EmbedProvider>
The provider takes:
pickEmbed: EmbedPickerCallback — opens your file picker; resolves to a PickedEmbed (or null to cancel).resolveFile: EmbedFileResolver — turns a fileId into a ResolvedEmbedFile (URL + metadata) for rendering.onOpenEmbed?: EmbedOpenCallback — invoked when an embed card is clicked.For lower-level integration, AssignmentEmbedNode and AssignmentEmbedView are exported directly so they can be added to a custom TipTap configuration. The full set of embed kinds is exposed as ALL_EMBED_KINDS.
Track per-user work sessions with timers, progress, and notes. Use createAssignmentFile() to mint a new assignment with sensible defaults:
import { useState, useEffect } from 'react';
import { AssignmentEditor, createAssignmentFile, type AssignmentFile } from '@hiyve/react-assignments';
function AssignmentScreen({ client, currentUserId }: { client: AssignmentFileClient; currentUserId: string }) {
const [assignment, setAssignment] = useState<AssignmentFile>();
useEffect(() => {
createAssignmentFile(client, {
name: 'Design Review',
ownerId: currentUserId,
}).then(({ fileData }) => setAssignment(fileData));
}, [client, currentUserId]);
if (!assignment) return null;
return (
<AssignmentEditor
title="Design Review"
showMetadata
showTabs
enableActivityTracking
initialAssignment={assignment}
onStatusChange={(status) => console.log('Status:', status)}
/>
);
}
The Activity tab shows individual session controls. The Activity Dashboard tab displays aggregate stats including active users, total time spent, and average progress.
import {
calculateTotalTime,
formatDuration,
getActivityStats,
getStatusColor,
} from '@hiyve/react-assignments';
const totalMinutes = calculateTotalTime(userActivity.sessions);
const display = formatDuration(totalMinutes); // "2h 30m"
const stats = getActivityStats(userActivities);
const color = getStatusColor('in_progress');
For full file-management workflows (create, load, switch between saved assignments) use FileSessionHost from @hiyve/react-collaboration with AssignmentEditor registered as the editor for the assignment resource type. See @hiyve/react-collaboration for details.
All visual aspects of the editor are customizable through labels, icons, colors, and styles props. Pass a partial object -- unspecified keys use defaults.
import { AssignmentEditor } from '@hiyve/react-assignments';
<AssignmentEditor
labels={{
title: 'Tarea',
placeholder: 'Escribe tu tarea...',
save: 'Guardar',
saving: 'Guardando...',
saved: 'Guardado',
bold: 'Negrita',
italic: 'Cursiva',
dueDate: 'Fecha limite',
status: 'Estado',
}}
/>
import { AssignmentEditor } from '@hiyve/react-assignments';
import { FaBold, FaItalic } from 'react-icons/fa';
<AssignmentEditor
icons={{
bold: <FaBold />,
italic: <FaItalic />,
}}
/>
import { AssignmentEditor, buildDefaultAssignmentEditorColors } from '@hiyve/react-assignments';
import { useTheme } from '@mui/material';
// Light theme override — derive defaults from the current MUI theme
function ThemedAssignment() {
const theme = useTheme();
const baseColors = buildDefaultAssignmentEditorColors(theme);
return (
<AssignmentEditor
colors={{
...baseColors,
headerBackground: '#f5f5f5',
editorBackground: '#ffffff',
editorText: '#212121',
toolbarBackground: '#fafafa',
toolbarButtonActive: '#1976d2',
}}
/>
);
}
import { AssignmentEditor } from '@hiyve/react-assignments';
// Compact layout
<AssignmentEditor
styles={{
toolbarButtonSize: 28,
editorPadding: 12,
editorFontSize: '0.875rem',
borderRadius: 8,
}}
/>
Defaults and merge functions:
| Default | Merge Function |
|---|---|
defaultAssignmentEditorLabels |
mergeAssignmentEditorLabels |
defaultAssignmentEditorIcons |
mergeAssignmentEditorIcons |
buildDefaultAssignmentEditorColors |
mergeAssignmentEditorColors |
defaultAssignmentEditorStyles |
mergeAssignmentEditorStyles |
defaultActivityDashboardLabels |
mergeActivityDashboardLabels |
defaultActivityControlPanelLabels |
mergeActivityControlPanelLabels |
defaultCreateAssignmentDialogLabels |
mergeCreateAssignmentDialogLabels |
assignment-embed node and EmbedProviderAssignmentViewer) for displaying assignments without editing| Constant | Description |
|---|---|
DEFAULT_AUTO_SAVE_INTERVAL |
Default auto-save interval (3000ms) |
ACTIVITY_SAVE_INTERVAL |
Activity tracking save interval (30000ms) |
CONTENT_CHANGE_DEBOUNCE |
Content change debounce delay (500ms) |
DEFAULT_FILE_LOCATION |
Default storage folder ('/Assignments') |
DEFAULT_PLACEHOLDER |
Default placeholder text |
DEFAULT_TABLE_DIMENSIONS |
Default rows/columns for new tables |
ASSIGNMENT_FILE_EXTENSION |
File extension for assignment files |
ASSIGNMENT_FILE_MIME_TYPE |
MIME type for assignment files |
ASSIGNMENT_STATUSES |
Array of all valid assignment statuses |
EMPTY_CONTENT |
Empty document structure |
| Type | Description |
|---|---|
AssignmentFile |
Full assignment data model (content, metadata, user activities) |
AssignmentFileClient |
Interface for file persistence operations (uploadFile, modifyFile) |
AssignmentEditorRef |
Imperative handle: save(), isSaving, hasUnsavedChanges, lastSaved, fileId |
AssignmentViewerProps |
Props for AssignmentViewer |
CreateAssignmentDialogProps |
Props for CreateAssignmentDialog |
CreateAssignmentDialogLabels |
Customizable text labels for CreateAssignmentDialog |
CreateAssignmentFileOptions |
Options for createAssignmentFile (name, ownerId, ownerName?, initialContent?, location?) |
CreateAssignmentFileResult |
Return type of createAssignmentFile (fileId, fileData) |
AssignmentStatus |
'not_started' | 'in_progress' | 'on_hold' | 'completed' |
ActivitySession |
A single tracked work session (startTime, endTime?, durationMinutes, optional notes) |
UserActivity |
Per-user activity record (sessions, progress, status, notes) |
AssignmentMetadataState |
Shape of the metadata pane (dueDate, timeHours, timeMinutes, status, assignedTo) |
JSONContent |
Editor content format (structured JSON) |
Editor |
Re-exported editor instance type (returned by useAssignmentEditor) |
EmbedAttrs, EmbedKind, EmbedFileResolver, EmbedOpenCallback, EmbedPickerCallback, EmbedProviderProps, PickedEmbed, ResolvedEmbedFile |
Types for the assignment-embed extension and provider |
type AssignmentStatus = 'not_started' | 'in_progress' | 'on_hold' | 'completed';
@hiyve/react (^2.0.0) -- components must be rendered inside HiyveProvider@hiyve/react-collaboration (^1.0.0) -- optional, for hosting AssignmentEditor inside FileSessionHost@hiyve/utilities (^1.0.0)@mui/material (^5.0.0 || ^6.0.0) and @mui/icons-material@emotion/react (^11.0.0) and @emotion/styled (^11.0.0)react (^18.0.0)Rich text editor dependencies are bundled with the package -- no separate installation needed.
Proprietary - Hiyve SDK
@hiyve/react-assignments - Assignment editor with activity tracking