@lpti/widget-unpam-sso
v0.0.7
Published
SSO Widget component for UNPAM SSO - React dropdown widget with iframe integration
Downloads
4
Readme
Widget SSO
Embed the UNPAM SSO login widget as an iframe. Supports both vanilla JavaScript and React (JSX/TSX) usage. No dependencies required for vanilla JS. TypeScript types included for React.
Installation
npm install @lpti/widget-unpam-ssoOr using yarn:
yarn add @lpti/widget-unpam-ssoUsage
Vanilla JavaScript (Native, No Dependencies)
import { embedWidgetSSO } from '@lpti/widget-unpam-sso';
// Basic usage
embedWidgetSSO('sso-widget-container');
// With options
embedWidgetSSO('sso-widget-container', {
env: 'prod', // 'dev' or 'prod'
lang: 'en', // 'id' or 'en'
size: 'lg', // 'sm', 'md', or 'lg'
theme: 'dark', // 'light' or 'dark'
logoUrl: '/path/to/logo.png',
className: 'my-sso-widget'
});HTML Script Tag (via CDN)
<script type="module">
import { embedWidgetSSO } from 'https://unpkg.com/@lpti/widget-unpam-sso@latest/index.js';
embedWidgetSSO('sso-widget-container', {
env: 'prod',
lang: 'id',
size: 'md',
theme: 'light'
});
</script>
<div id="sso-widget-container"></div>React Component (JSX/TSX)
import { WidgetSSO } from '@lpti/widget-unpam-sso/react';
function App() {
return (
<div className="app">
{/* Basic usage */}
<WidgetSSO />
{/* With options */}
<WidgetSSO
env="prod"
lang="en"
size="lg"
theme="dark"
logoUrl="/path/to/logo.png"
className="my-sso-widget"
onLoad={() => console.log('SSO widget loaded')}
onError={error => console.error('SSO widget error:', error)}
/>
</div>
);
}React Hook Usage
import { useWidgetSSO } from '@lpti/widget-unpam-sso/react';
function CustomSSOComponent() {
const { iframeUrl, isLoading, hasError, reload } = useWidgetSSO({
env: 'prod',
lang: 'id',
size: 'md',
theme: 'light'
});
if (isLoading) return <div>Loading SSO widget...</div>;
if (hasError) return <div>Error loading SSO widget. <button onClick={reload}>Retry</button></div>;
return (
<iframe
src={iframeUrl}
width="100%"
height="40px"
frameBorder="0"
scrolling="no"
/>
);
}Vue 3 Integration
<template>
<div>
<div ref="widgetContainer" class="widget-container"></div>
</div>
</template>
<script>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { WidgetSSO } from '@lpti/widget-unpam-sso/index';
export default {
name: 'SsoWidget',
props: {
theme: { type: String, default: 'light' },
size: { type: String, default: 'md' },
lang: { type: String, default: 'id' },
env: { type: String, default: 'dev' },
logoUrl: { type: String, default: null }
},
setup(props, { emit }) {
const widgetContainer = ref(null);
let ssoWidget = null;
onMounted(() => {
if (widgetContainer.value) {
ssoWidget = new WidgetSSO({
theme: props.theme,
size: props.size,
lang: props.lang,
env: props.env,
logoUrl: props.logoUrl
});
ssoWidget.render(widgetContainer.value);
// Set up iframe load event handler
const iframe = widgetContainer.value.querySelector('iframe');
if (iframe) {
iframe.onload = () => emit('load');
iframe.onerror = (error) => emit('error', error);
}
}
});
onBeforeUnmount(() => {
if (ssoWidget) {
ssoWidget.destroy();
}
});
return {
widgetContainer
};
}
}
</script>Vue 2 Integration
<template>
<div>
<div ref="widgetContainer" class="widget-container"></div>
</div>
</template>
<script>
import { WidgetSSO } from '@lpti/widget-unpam-sso/index';
export default {
name: 'SsoWidget',
props: {
theme: { type: String, default: 'light' },
size: { type: String, default: 'md' },
lang: { type: String, default: 'id' },
env: { type: String, default: 'dev' },
logoUrl: { type: String, default: null }
},
data() {
return {
ssoWidget: null
};
},
mounted() {
if (this.$refs.widgetContainer) {
this.ssoWidget = new WidgetSSO({
theme: this.theme,
size: this.size,
lang: this.lang,
env: this.env,
logoUrl: this.logoUrl
});
this.ssoWidget.render(this.$refs.widgetContainer);
// Set up iframe load event handler
const iframe = this.$refs.widgetContainer.querySelector('iframe');
if (iframe) {
iframe.onload = () => this.$emit('load');
iframe.onerror = (error) => this.$emit('error', error);
}
}
},
beforeDestroy() {
if (this.ssoWidget) {
this.ssoWidget.destroy();
}
}
}
</script>Vue 3 with Composition API (Alternative)
// UseWidgetSSO.js - Composable
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { WidgetSSO } from '@lpti/widget-unpam-sso/index';
export function useWidgetSSO(options = {}) {
const containerRef = ref(null);
const isLoading = ref(true);
const hasError = ref(false);
let widget = null;
const initWidget = () => {
if (!containerRef.value) return;
isLoading.value = true;
hasError.value = false;
try {
widget = new WidgetSSO(options);
widget.render(containerRef.value);
const iframe = containerRef.value.querySelector('iframe');
if (iframe) {
iframe.onload = () => {
isLoading.value = false;
};
iframe.onerror = () => {
isLoading.value = false;
hasError.value = true;
};
}
} catch (error) {
isLoading.value = false;
hasError.value = true;
console.error('Failed to initialize widget:', error);
}
};
onMounted(() => {
initWidget();
});
onBeforeUnmount(() => {
if (widget) {
widget.destroy();
}
});
return {
containerRef,
isLoading,
hasError,
reload: initWidget
};
}API
Configuration Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| theme | 'light' \| 'dark' | 'light' | Widget color theme |
| size | 'sm' \| 'md' \| 'lg' | 'md' | Widget size |
| lang | 'id' \| 'en' | 'id' | Language code |
| url | string | '' | Custom widget URL (overrides env) |
| env | 'dev' \| 'prod' | 'dev' | Environment to use |
| logoUrl | string \| null | null | URL to logo image |
| className | string | '' | Custom class for the container |
| buttonClassName | string | '' | Custom class for the button |
| dropdownClassName | string | '' | Custom class for the dropdown |
| style | object | {} | Custom styles for the container |
| buttonStyle | object | {} | Custom styles for the button |
| dropdownStyle | object | {} | Custom styles for the dropdown |
| width | string | '100%' | CSS width of the widget |
| height | string | 'auto' | CSS height of the widget |
Vanilla JavaScript
embedWidgetSSO(elementId, options)
Embeds the SSO widget into a target element.
Parameters:
elementId(string): The id of the target HTML elementoptions(object, optional): Configuration options (see above)
React Component
<WidgetSSO /> Props
All the same options as the vanilla JS version, plus:
onLoad(function): Callback when iframe loads successfullyonError(function): Callback when iframe fails to load
useWidgetSSO(options) Hook
Returns an object with:
iframeUrl(string): The generated iframe URLisLoading(boolean): Whether the URL is being validatedhasError(boolean): Whether there was an error loadingreload(function): Function to retry loading the URL
Environments
- Development:
https://devsso.unpam.ac.id/widget - Production:
https://satu.unpam.ac.id/widget
Features
- ✅ No dependencies for vanilla JS
- ✅ Native JavaScript ES6 modules
- ✅ React component (JSX/TSX) and TypeScript support
- ✅ React hooks for advanced usage
- ✅ Vue 2 and Vue 3 integration
- ✅ Multiple language support (Indonesian/English)
- ✅ Theme support (light/dark)
- ✅ Responsive sizing options
- ✅ URL validation before iframe creation
- ✅ Error handling and logging
- ✅ Loading states for React components
Browser Support
The widget supports all modern browsers (Chrome, Firefox, Safari, Edge).
License
MIT
