@smarterservices/smarter-elements
v1.0.24
Published
Embeddable UI components for SmarterServices
Readme
SmarterElements
Embeddable UI components for SmarterServices that can be integrated into any web application. Built with TypeScript for type safety and better developer experience.
Installation
For Node.js/React Applications
npm install @smarterservices/smarter-elementsor
yarn add @smarterservices/smarter-elementsThis will install the package with React as an external dependency, which means it will use your application's React instance.
For Direct Browser Usage
For direct usage in browsers without a build step, include the browser bundle script from unpkg:
<!-- Latest version -->
<script src="https://unpkg.com/@smarterservices/smarter-elements/dist/browser.js"></script>
<!-- Specific version (recommended for production) -->
<script src="https://unpkg.com/@smarterservices/[email protected]/dist/browser.js"></script>
<!-- Latest in a major version -->
<script src="https://unpkg.com/@smarterservices/smarter-elements@1/dist/browser.js"></script>
<!-- Latest in a minor version -->
<script src="https://unpkg.com/@smarterservices/[email protected]/dist/browser.js"></script>TypeScript Support
TypeScript type definitions are included in the package. No additional type installations are required.
import SmarterElements from '@smarterservices/smarter-elements';
// Create a new instance with TypeScript type checking
const elements = SmarterElements({
baseUrl: 'https://your-smarterproctoring-url.com',
});
// Create an element with type checking
export const examCard = elements.create('examCard', {
exam: {
id: 'exam123',
title: 'Biology 101',
// TypeScript will enforce the correct property types
},
});Browser Support
SmarterElements supports all modern browsers.
Usage
TypeScript Support
All components and utilities are fully typed. You'll get autocompletion and type checking when using TypeScript in your project.
TypeScript Configuration
Ensure your tsconfig.json has the following compiler options:
{
"compilerOptions": {
"esModuleInterop": true,
"moduleResolution": "node",
"target": "es2018"
}
}Available Types
import type {
SmarterElements,
ElementInstance,
ElementOptions,
EventHandler
} from '@smarterservices/smarter-elements';Examples
Examples of how to use SmarterElements can be found in the UI application at:
http://localhost:4000/elements-examples/elements-integration.htmlWhen running the UI application locally, you can access these examples to see how different components work and how to integrate them into your application.
JavaScript Integration
Using the Browser Bundle
The browser bundle is specifically designed for direct usage in browsers without a build step. It includes React internally, so you don't need to include React separately.
<!-- Using the browser bundle from unpkg CDN -->
<script src="https://unpkg.com/@smarterservices/smarter-elements/dist/browser.js"></script>
<script>
// Create a new instance with clean API
const elements = new SmarterElements({
baseUrl: 'https://your-smarterproctoring-url.com',
});
// Create an exam card
const examCard = elements.create('examCard', {
exam: {
id: 'exam123',
title: 'Biology 101',
course: 'BIO 101 - Introduction to Biology',
date: '2025-06-15',
startTime: '10:00 AM',
duration: 90,
},
});
</script>Using a Specific Version
You can specify a particular version of the browser bundle:
<!-- Using a specific major version (1.x.x - latest in 1.x range) -->
<script src="https://unpkg.com/@smarterservices/smarter-elements@1/dist/browser.js"></script>
<!-- Using a specific minor version (1.0.x - latest patch in 1.0 range) -->
<script src="https://unpkg.com/@smarterservices/[email protected]/dist/browser.js"></script>
<!-- Using an exact version (1.0.24) -->
<script src="https://unpkg.com/@smarterservices/[email protected]/dist/browser.js"></script>
<script>
// Create a new instance
const elements = new SmarterElements({
baseUrl: 'https://your-smarterproctoring-url.com',
});
// Create an exam card
const examCard = elements.create('examCard', {
exam: {
id: 'exam123',
title: 'Biology 101',
course: 'BIO 101 - Introduction to Biology',
date: '2025-06-15',
startTime: '10:00 AM',
duration: 90,
},
});
// Mount the exam card to a container
examCard.mount('#exam-card-container');
// Add event listeners
examCard.on('start-exam', data => {
console.log('Start exam clicked:', data);
});
examCard.on('view-details', data => {
console.log('View details clicked:', data);
});
</script>React Integration
Installing a Specific Version
# Install the latest version
npm install @smarterservices/smarter-elements
# Install a specific major version (latest in 1.x range)
npm install @smarterservices/smarter-elements@1
# Install a specific minor version (latest patch in 1.0 range)
npm install @smarterservices/[email protected]
# Install an exact version
npm install @smarterservices/[email protected]Basic Integration
When using the package in a React application, the library will use your application's React instance. This avoids duplicate React instances and prevents "Invalid hook call" errors.
import React, { useEffect, useRef } from 'react';
import SmarterElements from '@smarterservices/smarter-elements';
function ExamCardComponent() {
const containerRef = useRef(null);
const examCardRef = useRef(null);
useEffect(() => {
// Create a new instance
const elements = SmarterElements({
baseUrl: 'https://your-smarterproctoring-url.com',
});
// Create an exam card
const examCard = elements.create('examCard', {
exam: {
id: 'exam123',
title: 'Biology 101',
course: 'BIO 101 - Introduction to Biology',
date: '2025-06-15',
startTime: '10:00 AM',
duration: 90,
},
});
// Mount the exam card to the container
examCard.mount(containerRef.current);
// Add event listeners
examCard.on('start-exam', data => {
console.log('Start exam clicked:', data);
});
examCard.on('view-details', data => {
console.log('View details clicked:', data);
});
// Save the reference for cleanup
examCardRef.current = examCard;
// Cleanup
return () => {
if (examCardRef.current) {
examCardRef.current.unmount();
}
};
}, []);
return <div ref={containerRef} className="exam-card-container"></div>;
}
export default ExamCardComponent;Available Elements
examCard: Displays exam information with actionsproctorSchedule: Shows proctor schedule with calendar viewexamVerification: Handles exam verification processidentityCheck: Manages identity verificationelementsLayout: Provides a layout container for elements
Events
Each element emits events that you can listen to:
ExamCard Events
start-exam: Triggered when the start exam button is clickedview-details: Triggered when the view details button is clickedresize: Triggered when the element's size changes
ProctorSchedule Events
date-changed: Triggered when the selected date changessession-selected: Triggered when a session is selected
Modal Support
SmarterElements provides built-in modal support for displaying elements in a centered dialog:
// Create an element instance
const elements = SmarterElements({
baseUrl: 'https://your-smarterproctoring-url.com',
});
const examCard = elements.create('examCard', {
exam: {
id: 'exam456',
title: 'Physics 202',
course: 'PHYS 202 - Quantum Mechanics',
date: '2025-10-15',
startTime: '2:00 PM',
duration: 120,
},
});
// Open the element in a modal
examCard.openModal({
width: '800px',
maxWidth: '90vw',
maxHeight: '90vh'
});
// Close the modal programmatically
examCard.closeModal();
// Listen for modal events
examCard.on('modal:open', (data) => {
console.log('Modal opened:', data);
});
examCard.on('modal:close', (data) => {
console.log('Modal closed:', data);
});Element Constraints & Resizing
SmarterElements includes a unified resizing system with support for min/max constraints and smooth animations.
Setting Constraints
// Create an element
const examCard = elements.create('examCard', { exam: {...} });
// Set constraints after creation
examCard.updateConstraints({
minHeight: 200,
maxHeight: 600,
minWidth: 300,
maxWidth: 800
});
// Get current constraints
const constraints = examCard.getConstraints();
console.log('Current constraints:', constraints);
// Listen for constraint updates
examCard.on('constraints:update', ({ constraints }) => {
console.log('Constraints updated:', constraints);
});Automatic Resizing Setup
In the parent page (hosting the iframe):
import { setupUnifiedParentResize } from '@smarterservices/smarter-elements';
// Set up resize handling
const cleanup = setupUnifiedParentResize(
iframe,
({ height, width }) => {
iframe.style.height = `${height}px`;
console.log('New dimensions:', { height, width });
},
{
elementId: 'my-element',
minHeight: 100,
maxHeight: 800
}
);
// Cleanup when done
cleanup();In the iframe content (React example):
import { setupUnifiedContentResize } from '@smarterservices/smarter-elements';
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// Set up automatic resizing with constraints
const cleanup = setupUnifiedContentResize({
minHeight: 100, // Minimum height in pixels
maxHeight: 600, // Maximum height in pixels
elementId: 'my-element', // Element ID for targeted messages
debounceMs: 16 // Debounce delay (60fps)
});
return cleanup;
}, []);
return (
<div>
{/* Your component content */}
</div>
);
}HTML/JS Usage (No Build Step)
For iframe content without a build step, you can use the auto-initialization feature:
<script src="https://unpkg.com/@smarterservices/smarter-elements/dist/browser.js"
data-auto-resize
data-min-height="100"
data-max-height="600"
data-element-id="your-element-id">
</script>Or initialize manually after loading the script:
<script src="https://unpkg.com/@smarterservices/smarter-elements/dist/browser.js"></script>
<script>
// Initialize resize handling
const cleanup = SmarterElements.setupUnifiedContentResize({
minHeight: 100,
maxHeight: 600,
elementId: 'my-element'
});
// Cleanup when page unloads
window.addEventListener('beforeunload', cleanup);
</script>Observing Specific Elements
To ensure specific elements trigger a resize when they change, add the data-observe-resize attribute:
<div data-observe-resize>
<!-- Content that might change size -->
</div>Resize Events
You can listen for resize events on the element instance:
// Listen for resize events (includes both dimensions)
element.on('resize', ({ height, width, elementId }) => {
console.log('Element resized:', { height, width, elementId });
});
// Listen for constraint updates
element.on('constraints:update', ({ constraints, elementId }) => {
console.log('Constraints updated:', constraints);
});Best Practices
- Use a minimum height to prevent the iframe from collapsing when content is loading
- Add padding/margin to the offset if your content has space that isn't captured by the height calculation
- Use element IDs when embedding multiple iframes to ensure messages don't get mixed up
- Clean up event listeners when unmounting components to prevent memory leaks
Troubleshooting
Iframe Not Resizing
- Check the console for any error messages
- Verify the iframe URL - The parent and iframe must be on the same domain or have proper CORS headers
- Check content security policy - Ensure your CSP allows
postMessagecommunication - Verify the iframe is loaded - Wait for the iframe's
loadevent before setting up resizing
Common Issues
- Content jumps on load: Set a reasonable
minHeightto prevent layout shifts - Resize not working with dynamic content: Ensure you've added
data-observe-resizeto dynamic content containers - Messages not received: Check that the
elementIdmatches between parent and iframe if using targeted messages
Build System
SmarterElements uses a dual build approach to support different usage scenarios:
NPM Package Builds (ESM and CommonJS)
When installed via npm, the package provides:
- ESM build (
dist/index.mjs): For modern bundlers and environments that support ES modules - CommonJS build (
dist/index.js): For Node.js and older bundlers
Both of these builds externalize React, meaning they expect React to be provided by your application. This prevents duplicate React instances and avoids "Invalid hook call" errors.
Browser Bundle (IIFE)
For direct browser usage without a build step, the package includes:
- Browser bundle (
dist/browser.js): An IIFE build that includes React internally
This bundle exposes SmarterElements as a global constructor and can be used directly in a browser without any build tools or separate React installation.
Versioning
This package follows Semantic Versioning:
- MAJOR version changes indicate incompatible API changes
- MINOR version changes add functionality in a backward-compatible manner
- PATCH version changes include backward-compatible bug fixes
Version Compatibility
To ensure your integration remains stable, we recommend the following versioning strategies:
For Production Applications
- Lock to an exact version in your package.json:
"@smarterservices/smarter-elements": "1.2.3" - Update versions manually after testing with your application
For Development/Staging
- Lock to a minor version using the caret syntax:
"@smarterservices/smarter-elements": "^1.2.0" - This allows automatic updates for patch releases (bug fixes) but prevents potentially breaking changes
Version Compatibility Matrix
| SmarterElements Version | React Compatibility | Browser Support | Notes | | ----------------------- | ------------------- | --------------- | ------------------------------------- | | 1.x.x | React 18+ | Modern browsers | Initial stable release series | | 2.x.x (future) | React 18+ | Modern browsers | May contain breaking changes from 1.x |
Choosing the Right Version
When selecting a version for your application:
- For new projects: Use the latest version available
- For existing projects:
- Check the CHANGELOG.md for breaking changes before upgrading major versions
- Test thoroughly in a staging environment before deploying to production
- For critical applications: Pin to an exact version and only upgrade after thorough testing
Browser Support
SmarterElements supports all modern browsers:
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
License
MIT
