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-elements
or
yarn add @smarterservices/smarter-elements
This 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/index.browser.js"></script>
<!-- Specific version (recommended for production) -->
<script src="https://unpkg.com/@smarterservices/smarter-elements@1.0.16/dist/index.browser.js"></script>
<!-- Latest in a major version -->
<script src="https://unpkg.com/@smarterservices/smarter-elements@1/dist/index.browser.js"></script>
<!-- Latest in a minor version -->
<script src="https://unpkg.com/@smarterservices/smarter-elements@1.0/dist/index.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:3000/elements-examples/elements-integration.html
When 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/index.browser.js"></script>
<script>
// 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,
},
});
</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/index.browser.js"></script>
<!-- Using a specific minor version (1.0.x - latest patch in 1.0 range) -->
<script src="https://unpkg.com/@smarterservices/smarter-elements@1.0/dist/index.browser.js"></script>
<!-- Using an exact version (1.0.16) -->
<script src="https://unpkg.com/@smarterservices/smarter-elements@1.0.16/dist/index.browser.js"></script>
<script>
// 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 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/smarter-elements@1.0
# Install an exact version
npm install @smarterservices/smarter-elements@1.0.16
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 a simple modal manager for displaying elements in a modal without using React Context:
// Import the modal manager
import { modalManager } from '@smarterservices/smarter-elements';
// Open an exam card in a modal
const modalController = modalManager.openModal('examCard', {
exam: {
id: 'exam456',
title: 'Physics 202',
course: 'PHYS 202 - Quantum Mechanics',
date: '2025-10-15',
startTime: '2:00 PM',
duration: 120,
},
});
// Close the modal programmatically
modalController.close();
// You can also listen for modal events
modalManager.on('open', (modalId) => {
console.log(`Modal ${modalId} opened`);
});
modalManager.on('close', (modalId) => {
console.log(`Modal ${modalId} closed`);
});
The modal manager is a lightweight alternative to React Context, making it more compatible with various React versions and environments.
Iframe Resizing
SmarterElements includes built-in support for automatically resizing iframes to fit their content. This is especially useful for modals and embedded content that may change size dynamically.
Basic Usage
In the parent page (hosting the iframe):
import { setupIframeResize } from '@smarterservices/smarter-elements/utils/iframeResize';
// Assuming you have an iframe element
const iframe = document.getElementById('my-iframe');
// Set up resize handling
const cleanup = setupIframeResize(iframe, (height) => {
// This callback is called whenever the iframe content changes size
iframe.style.height = `${height}px`;
});
// Later, when you're done (e.g., when unmounting the component)
cleanup();
In the iframe content (React example):
import { setupIframeContentResize } from '@smarterservices/smarter-elements/utils/iframeContentResize';
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// Set up automatic resizing
const cleanup = setupIframeContentResize({
minHeight: 100, // Minimum height in pixels (default: 100)
offset: 0, // Additional height to add (default: 0)
elementId: '123' // Optional element ID for targeted messages
});
return () => cleanup();
}, []);
return (
<div>
{/* Your component content */}
</div>
);
}
HTML/JS Usage (No Build Step)
If you can't use a build step in your iframe content, include this script:
<script src="https://your-cdn.com/iframe-resize.js"
data-auto-resize
data-min-height="100"
data-offset="0"
data-element-id="your-element-id">
</script>
Or initialize it manually:
<script>
window.smarterElementsResize({
minHeight: 100, // Minimum height in pixels
offset: 0, // Additional height to add
elementId: '123' // Optional element ID for targeted messages
});
</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:
element.on('resize', (height) => {
console.log('Element height changed to:', height);
});
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
postMessage
communication - Verify the iframe is loaded - Wait for the iframe's
load
event before setting up resizing
Common Issues
- Content jumps on load: Set a reasonable
minHeight
to prevent layout shifts - Resize not working with dynamic content: Ensure you've added
data-observe-resize
to dynamic content containers - Messages not received: Check that the
elementId
matches 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/index.browser.js
): An IIFE build that includes React internally
This bundle is exposed as a global variable SmarterElements
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