Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@smarterservices/smarter-elements

matthew.underhill842MIT1.0.22TypeScript support: included

Embeddable UI components for SmarterServices

proctoring, ui, components, embeddable, iframe

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-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 actions
  • proctorSchedule: Shows proctor schedule with calendar view
  • examVerification: Handles exam verification process
  • identityCheck: Manages identity verification
  • elementsLayout: 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 clicked
  • view-details: Triggered when the view details button is clicked
  • resize: Triggered when the element's size changes

ProctorSchedule Events

  • date-changed: Triggered when the selected date changes
  • session-selected: Triggered when a session is selected

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

  1. Use a minimum height to prevent the iframe from collapsing when content is loading
  2. Add padding/margin to the offset if your content has space that isn't captured by the height calculation
  3. Use element IDs when embedding multiple iframes to ensure messages don't get mixed up
  4. Clean up event listeners when unmounting components to prevent memory leaks

Troubleshooting

Iframe Not Resizing

  1. Check the console for any error messages
  2. Verify the iframe URL - The parent and iframe must be on the same domain or have proper CORS headers
  3. Check content security policy - Ensure your CSP allows postMessage communication
  4. 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:

  1. For new projects: Use the latest version available
  2. For existing projects:
    • Check the CHANGELOG.md for breaking changes before upgrading major versions
    • Test thoroughly in a staging environment before deploying to production
  3. 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