@startinblox/solid-tems-shared
v2.0.0
Published
Startin'blox TEMS shared libraries
Keywords
Readme
TEMS Shared Components
Shared libraries and utilities for the TEMS (Trusted European Media data Space) ecosystem. Provides base component classes, data utilities, mock data, and Orbit integration helpers for building federated data space applications.
Table of Contents
- Key Features
- Architecture
- Utilities
- Base Classes
- Mock Data
- Installation
- Quick Start
- Development
- Documentation
- License
Key Features
Component Base Classes
- OrbitComponent: Full Orbit integration with data fetching, caching, and routing awareness
- ComponentObjectHandler: Single resource display without data fetching
- ComponentObjectsHandler: Array/collection of resources without data fetching
- TemsObjectHandler/TemsObjectsHandler: TEMS-specific resource handlers
Data Utilities
- Filtering: Multiple filter generators for value, type, date interval, named value, and ID filtering
- Sorting: Generic sort function supporting nested keys, numbers, strings, and dates
- Data Building: Helper functions for constructing and transforming data structures
UI Helpers
- FormatDate: Date formatting using Intl API
- AvatarSvg: SVG-based avatar generation with initials
- TabsManager: Tab navigation management
- OfferKindHandler: Handle different offer kinds and actions
Orbit Integration
- Cache Invalidation: Setup cache invalidation on resource changes
- Component Subscriptions: Subscribe to component events and lifecycle hooks
- On Save Reset: Setup reset functionality after save operations
- Request Navigation: Navigation wrapper with route-based routing
Mock Data
- Comprehensive mock data for testing: services, data offers, media objects, assets, licenses, locations, providers, users, organizations, and more
Architecture
Component Base Classes
ComponentObjectHandler: Display a single resource. Used for single item/detail views, within OrbitComponent, no data fetching needed.
ComponentObjectsHandler: Display an array/collection of resources. Used for lists/grids, within OrbitComponent, no data fetching needed.
OrbitComponent: Full Orbit integration with data fetching. Extends ComponentObjectsHandler. Used for fetching data from URL (data-src), caching/updates, routing awareness, Orbit interaction, single object and list display.
Utilities
Data Utilities
| Function | Description |
|----------|-------------|
| sort(arr, key, order) | Sort arrays by nested keys, numbers, strings, or dates |
| filterGenerator | Create custom filter functions |
| filterObjectByValue | Filter objects by property value |
| filterObjectByType | Filter objects by @type property |
| filterObjectByNamedValue | Filter by named value (e.g., foaf:name) |
| filterObjectById | Filter by @id property |
| filterObjectByInterval | Filter by numeric interval |
| filterObjectByDateAfter | Filter objects by date after a threshold |
| filterObjectByDateInterval | Filter by date interval |
| dataBuilder | Build and transform data structures |
| checkValueInIntervalRecursive | Recursive interval checking |
UI Helpers
| Function | Description |
|----------|-------------|
| formatDate(date) | Format dates using Intl API |
| AvatarSvg(name, size) | Generate SVG avatar with initials |
| TabsManager | Tab navigation management |
| offerKindHandler | Handle offer kind display |
| offerKindActionHandler | Handle offer kind actions |
| uniq() | Generate unique IDs |
Orbit Integration Helpers
| Function | Description |
|----------|-------------|
| setupCacheInvalidation(component, { keywords }) | Setup cache invalidation on resource changes |
| setupCacheOnResourceReady(component) | Setup cache operations when resource is ready |
| setupComponentSubscriptions(component) | Subscribe to component events |
| setupOnSaveReset(component) | Setup reset after save operations |
| requestNavigation(route, resource) | Navigation wrapper |
Base Classes
OrbitComponent
Key features:
cherryPickedProperties: Declarative data fetching_getProxyValue(url): Fetch and transform resources_responseAdaptator(response): Custom transformationsgatekeeper(): Route-aware rendering optimizationorbitproperty: Orbit integrationsetupCacheInvalidation(): Cache invalidation
Usage:
import OrbitComponent from '@helpers/components/orbitComponent';
@customElement('my-component')
export class MyComponent extends OrbitComponent {
cherryPickedProperties: PropertiesPicker[] = [
{ key: "name", value: "name" },
{ key: "created_at", value: "created_at", cast: formatDate },
{ key: "categories", value: "categories", expand: true, cast: (c) => sort(c, "name") },
];
}ComponentObjectHandler
Used for displaying a single resource without data fetching:
import { ComponentObjectHandler } from '@helpers/components/componentObjectHandler';
@customElement('my-single-item')
export class MySingleItem extends ComponentObjectHandler {
render() {
return html`<p>${this.resource?.name}</p>`;
}
}ComponentObjectsHandler
Used for displaying collections without data fetching:
import { ComponentObjectsHandler } from '@helpers/components/componentObjectsHandler';
@customElement('my-list')
export class MyList extends ComponentObjectsHandler {
render() {
return html`
<ul>
${this.resources?.map(r => html`<li>${r.name}</li>`)}
</ul>
`;
}
}Mock Data
Available mock data for testing:
| Mock | Description |
|------|-------------|
| asset.mock.ts | Asset objects |
| dataOffer.mock.ts | Data offer definitions |
| image.mock.ts | Image objects |
| licence.mock.ts | License information |
| location.mock.ts | Location data |
| namedResource.mock.ts | Named resources |
| object.mock.ts | Generic objects |
| offers.mock.ts | Offer catalog |
| orbit.mock.ts | Orbit configuration |
| organisation.mock.ts | Organization data |
| provider.mock.ts | Provider information |
| service.mock.ts | Service definitions |
| sentiment.mock.ts | Sentiment analysis data |
| user.mock.ts | User profiles |
| mediaObject.mock.ts | Generic media objects |
| 3DObject.mock.ts | 3D object models |
| mediaobjects/ | Specialized media objects (civilSociety, factChecking, etc.) |
Installation
npm install @startinblox/solid-tems-sharedQuick Start
Use TEMSOrbit instead of Orbit in your component.d.ts
import type { TemsLiveOrbit } from "@startinblox/solid-tems-shared";
...
export declare global {
interface Window {
orbit: TemsLiveOrbit;
sibStore: { getData: ProxyValue<Resource | Container>; [key: string]: any };
sibRouter: { [key: string]: any };
}
}Using Base Classes
import OrbitComponent from '@helpers/components/orbitComponent';
import { formatDate } from '@helpers/ui/formatDate';
import { sort } from '@helpers/datas/sort';
@customElement('my-catalog')
export class MyCatalog extends OrbitComponent {
cherryPickedProperties = [
{ key: "name", value: "name" },
{ key: "createdAt", value: "created_at", cast: formatDate },
];
render() {
if (!this.data) return html`<p>Loading...</p>`;
return html`
<div>
${this.data.map(item => html`<div>${item.name}</div>`)}
</div>
`;
}
}Using Data Utilities
import { filterObjectByType } from '@helpers/datas/filterObjectByType';
import { sort } from '@helpers/datas/sort';
const resources = [
{ "@type": "Offer", name: "Offer 1" },
{ "@type": "Asset", name: "Asset 1" },
{ "@type": "Offer", name: "Offer 2" }
];
const offers = filterObjectByType(resources, "Offer");
const sortedOffers = sort(offers, "name", "asc");Using UI Helpers
import { formatDate } from '@helpers/ui/formatDate';
import { AvatarSvg } from '@helpers/ui/avatarSvg';
const date = new Date();
const formatted = formatDate(date);
const avatar = new AvatarSvg("John Doe", 40);Setting Up Cache Invalidation
import setupCacheInvalidation from '@helpers/components/setupCacheInvalidation';
@customElement('my-component')
export class MyComponent extends OrbitComponent {
_afterAttach() {
super._afterAttach();
setupCacheInvalidation(this, { keywords: ["service", "asset"] });
}
}Using Internationalization
<script type="module">
import '@startinblox/solid-tems-shared';
</script>
<script>
// Change locale at runtime
window.setLocale("fr"); // Switch to French
window.getLocale(); // Get current locale
</script>Development
Watch Mode (Hot Reload)
npm run watchRun Tests (Vitest)
npm test # Run all tests
npm run test:open # Run tests in browser (Playwright)
npm run test:watch # Watch mode for tests
npm run test:coverage # Run tests with coverageBuild for Production
npm run buildPreview Production Build
npm run serveLinting & Formatting
npx biome check . # Check for issues
npx biome check . --write # Auto-fix and formatDocumentation
For Developers
- AGENTS.md: Complete development guidelines and coding standards
- src/component.d.ts: Component type definitions
- src/tems.d.ts: TEMS-specific type definitions
Component Conventions
Naming:
- Web component elements: kebab-case (e.g.,
my-component) - Class names: PascalCase (e.g.,
MyComponent) - Properties/attributes: kebab-case in HTML, camelCase in JS
- Private methods: prefix with
_(e.g.,_afterAttach)
Lit Decorators:
@customElement("element-name")- Define web component@property({ attribute: "data-src", reflect: true })- Public attributes reflecting to DOM@property({ attribute: false, type: Object })- Object properties (no attribute reflection)@state()- Private reactive state
Event Handlers:
All event handlers must prevent default behavior:
_handleEvent(e: Event) {
e.preventDefault();
// handler logic
}Style Import:
import ComponentStyle from "@styles/component.scss?inline";
static styles = css`${unsafeCSS(ComponentStyle)}`;Import Paths
Use configured aliases in your code:
import OrbitComponent from '@helpers/components/orbitComponent';
import { sort } from '@helpers/datas/sort';
import { formatDate } from '@helpers/ui/formatDate';
import setupCacheInvalidation from '@helpers/components/setupCacheInvalidation';Orbit Integration
- Import
@src/initializerbefore@customElementdecorator - Use
gatekeeper()to prevent unnecessary renders - Check
this.orbitexists before using Orbit features - Get component references via
this.orbit?.getComponent("component-name") - Wait for readiness with
addEventListener("ready", ...)
Cherry-Picked Properties Pattern
cherryPickedProperties: PropertiesPicker[] = [
{ key: "name", value: "name" },
{ key: "created_at", value: "created_at", cast: formatDate },
{ key: "categories", value: "categories", expand: true, cast: (c) => sort(c, "name") },
];Error Handling
Try-catch in async methods, log errors only in dev mode:
try {
// code
} catch (e) {
if (import.meta.env.DEV) console.error(e);
}License
TEMS Project - Co-funded by the European Union
