Aller au contenu

Composants personnalisés

Les composants personnalisés vous permettent d’étendre PandaSuite avec vos propres éléments interactifs construits avec les technologies web (HTML, CSS, JavaScript). Contrairement aux composants natifs PandaSuite, les composants personnalisés s’exécutent dans une web view, vous donnant accès à tout l’écosystème web : packages npm, React, Vue ou tout autre framework JavaScript.

Grâce aux librairies PandaBridge, votre composant peut communiquer avec le reste de votre projet PandaSuite : recevoir des propriétés, déclencher des événements, répondre à des actions et se synchroniser avec d’autres composants.

Si vous souhaitez simplement intégrer du contenu web externe sans interagir avec d’autres composants PandaSuite, utilisez plutôt le composant Web.

Cas d’utilisation

Les composants personnalisés sont utiles quand vous avez besoin de :

  • Intégrer des services tiers : se connecter à des APIs comme des processeurs de paiement, des plateformes d’analytics ou des backends personnalisés
  • Ajouter des fonctionnalités spécialisées : créer des scanners de QR codes, des zones de signature, des graphiques personnalisés ou des visualisations interactives
  • Réutiliser du code existant : packager votre code JavaScript ou React comme composant PandaSuite
  • Étendre les capacités natives : accéder aux fonctionnalités de l’appareil ou aux APIs du navigateur non disponibles dans les composants standards

Ce que les composants personnalisés peuvent faire

Les composants personnalisés se comportent comme les composants natifs PandaSuite. Ils peuvent :

  • Afficher des propriétés configurables dans le panneau de propriétés du Studio
  • Émettre des événements (déclencheurs) qui activent des actions sur d’autres composants
  • Recevoir des actions d’autres composants
  • Définir des marqueurs (points de données comme des timestamps ou des hotspots)
  • Synchroniser leur état avec d’autres composants
  • Réagir aux changements de langue dans les projets multilingues
  • Recevoir des données dynamiques via le data binding

Manifeste du composant (pandasuite.json)

Chaque composant personnalisé inclut un fichier pandasuite.json qui décrit son interface. Ce manifeste définit les propriétés, événements, actions et autres fonctionnalités qui apparaissent dans PandaSuite Studio.

Structure de base

{
"version": "2.0.0",
"main": "",
"properties": [],
"events": [],
"actions": [],
"resources": [],
"markers": [],
"synchronization": [],
"queryable": {},
"system": {}
}
ChampDescription
versionVersion du manifeste (actuelle : "2.0.0")
mainURL du point d’entrée (généralement vide "" pour les composants PandaBridge)
propertiesOptions de configuration affichées dans le panneau de propriétés
eventsDéclencheurs qui peuvent activer des actions sur d’autres composants
actionsOpérations que d’autres composants peuvent appeler
resourcesEmplacements pour les médias (images, vidéos, audio, fichiers zip)
markersPoints de données définis par l’utilisateur
synchronizationGroupes pour la synchronisation d’état entre composants
queryableDonnées exposées pour le data binding
systemParamètres avancés (localisation, configuration des marqueurs)

Propriétés

Les propriétés apparaissent dans le panneau de propriétés du Studio. Chaque propriété a un type qui détermine son interface utilisateur.

{
"properties": [
{
"id": "url",
"name": "URL",
"locale_name": { "fr_FR": "URL" },
"type": "String",
"value": "https://example.com",
"bindable": true,
"required": true
},
{
"id": "autoplay",
"name": "Autoplay",
"locale_name": { "fr_FR": "Lecture automatique" },
"type": "Boolean",
"value": false
}
]
}

Types de propriétés

TypeDescriptionContrôle UI
StringValeur texteChamp de texte
BooleanVrai/fauxCase à cocher
IntegerNombre entierChamp numérique
FloatNombre décimalChamp numérique
ColorValeur couleurSélecteur de couleur
DropdownSélection dans une listeMenu déroulant
Image, Video, AudioRessource médiaSélecteur de fichier
BindExpression de data bindingÉditeur de binding
JSONDonnées structuréesÉditeur JSON
CodeCode avec coloration syntaxiqueÉditeur de code
SelectionRéférence à un autre composantSélecteur de composant

Options des propriétés

OptionTypeDescription
idstringIdentifiant unique (utilisé dans le code)
namestringNom affiché dans le Studio
locale_nameobjectNoms localisés (ex: { "fr_FR": "Nom" })
typestringType de propriété
valueanyValeur par défaut
bindablebooleanAutoriser le data binding
requiredbooleanMarquer comme requis
hiddenstring | booleanExpression de visibilité conditionnelle
placeholderstringTexte indicatif pour les champs
separatorbooleanAfficher un séparateur visuel au-dessus

Visibilité conditionnelle

Utilisez la propriété hidden pour afficher/masquer des propriétés selon d’autres valeurs :

{
"properties": [
{
"id": "mode",
"name": "Mode",
"type": "Dropdown",
"items": [
{ "id": "simple", "name": "Simple" },
{ "id": "advanced", "name": "Advanced" }
],
"value": "simple"
},
{
"id": "advancedOption",
"name": "Advanced Option",
"type": "String",
"hidden": "properties.mode.value != 'advanced'"
}
]
}

Éléments de dropdown

{
"id": "quality",
"name": "Quality",
"type": "Dropdown",
"value": "medium",
"items": [
{ "id": "low", "name": "Low", "locale_name": { "fr_FR": "Basse" } },
{ "id": "medium", "name": "Medium", "locale_name": { "fr_FR": "Moyenne" } },
{ "id": "high", "name": "High", "locale_name": { "fr_FR": "Haute" } }
]
}

Contraintes numériques

{
"id": "speed",
"name": "Speed",
"type": "Float",
"value": 1.0,
"restrict": {
"min": 0.1,
"max": 10.0,
"step": 0.1
}
}

Événements (déclencheurs)

Les événements permettent à votre composant de déclencher des actions sur d’autres composants. Définissez des données queryable qui deviennent disponibles lorsque l’événement se déclenche.

{
"events": [
{
"id": "onItemSelected",
"name": "Item selected",
"locale_name": { "fr_FR": "Élément sélectionné" },
"queryable": {
"itemId": "example-id",
"__desc_itemId": {
"name": "Item ID",
"locale_name": { "fr_FR": "ID de l'élément" }
},
"itemName": "Example Name",
"__desc_itemName": {
"name": "Item name",
"locale_name": { "fr_FR": "Nom de l'élément" }
}
}
}
]
}

L’objet queryable définit les données exposées lorsque l’événement se déclenche. Utilisez des clés préfixées par __desc_ pour fournir des métadonnées pour chaque champ.

Actions

Les actions sont des opérations que d’autres composants peuvent déclencher sur votre composant. Les actions peuvent avoir des paramètres.

{
"actions": [
{
"id": "setVolume",
"name": "Set volume",
"locale_name": { "fr_FR": "Définir le volume" },
"params": [
{
"id": "level",
"name": "Volume level",
"locale_name": { "fr_FR": "Niveau de volume" },
"type": "Float",
"value": 1.0,
"restrict": { "min": 0, "max": 1 }
}
]
},
{
"id": "reset",
"name": "Reset",
"locale_name": { "fr_FR": "Réinitialiser" }
}
]
}

Ressources

Les ressources sont des fichiers médias que les utilisateurs peuvent attacher à votre composant.

{
"resources": [
{
"id": "backgroundImage",
"name": "Background image",
"locale_name": { "fr_FR": "Image de fond" },
"type": "Image",
"bindable": true,
"localization": true
},
{
"id": "dataArchive",
"name": "Data archive",
"type": "Zip",
"required": true
}
]
}

Types de ressources : Image, Video, Audio, Zip, JSON

Définissez localization: true pour permettre des ressources différentes par langue.

Synchronisation

Les groupes de synchronisation permettent aux composants de partager leur état (comme la position de lecture ou la position de défilement).

{
"synchronization": [
{
"id": "playbackPosition",
"name": "Synchronize playback",
"locale_name": { "fr_FR": "Synchroniser la lecture" }
}
]
}

Données exposées (queryable)

L’objet queryable expose des données auxquelles d’autres composants peuvent accéder via le data binding.

{
"queryable": {
"progress": 0,
"__desc_progress": {
"name": "Progress",
"locale_name": { "fr_FR": "Progression" },
"type": "number"
},
"isPlaying": false,
"__desc_isPlaying": {
"name": "Is playing",
"locale_name": { "fr_FR": "En lecture" }
}
}
}

Configuration système

L’objet system contrôle les comportements avancés.

{
"system": {
"localization": true,
"markers": [
{
"params": [
{
"id": "timestamp",
"name": "Time",
"type": "Float"
}
]
}
],
"actions": [
{
"id": "toMarker",
"name": "Go to marker"
}
],
"events": [
{
"id": "triggerMarker",
"name": "Marker reached"
}
]
}
}

Définissez "markers": false pour désactiver entièrement le système de marqueurs.

API JavaScript PandaBridge

La librairie JavaScript gère la communication entre votre composant et PandaSuite.

Installation

Fenêtre de terminal
npm install pandasuite-bridge

Initialisation

import PandaBridge from 'pandasuite-bridge';
PandaBridge.init(() => {
console.log('Bridge prêt');
});

Recevoir les propriétés et données

// Appelé une fois au chargement du composant
PandaBridge.onLoad(({ properties, markers, resources }) => {
console.log('Properties:', properties);
console.log('Markers:', markers);
console.log('Resources:', resources);
// Initialisez votre composant avec ces valeurs
initComponent(properties);
});
// Appelé quand les propriétés changent
PandaBridge.onUpdate(({ properties, markers, resources }) => {
console.log('Properties mises à jour:', properties);
// Mettez à jour votre composant
updateComponent(properties);
});

Envoyer des événements

Utilisez PandaBridge.send() pour émettre des événements définis dans votre manifeste :

// Déclencher un événement
PandaBridge.send('onItemSelected', {
itemId: 'item-123',
itemName: 'Selected Item'
});
// Déclencher un événement de marqueur
PandaBridge.send(PandaBridge.SYNCHRONIZE, [markerData, 'markerName']);

Écouter les actions

// Écouter une action spécifique
PandaBridge.listen('setVolume', ([level]) => {
setVolume(level);
});
// Écouter toutes les actions
PandaBridge.listen((action, args) => {
console.log('Action reçue:', action, args);
});

Synchronisation

// Envoyer des données de synchronisation
PandaBridge.send(PandaBridge.SYNCHRONIZE, [currentValue, 'syncGroupId']);
// Recevoir des données de synchronisation
PandaBridge.synchronize('syncGroupId', (value) => {
updateFromSync(value);
});

Marqueurs (snapshots)

// Fournir les données de snapshot quand demandé
PandaBridge.getSnapshotData(() => {
return {
timestamp: getCurrentTime(),
customData: getComponentState()
};
});
// Restaurer depuis les données de snapshot
PandaBridge.setSnapshotData(({ data }) => {
if (data) {
setCurrentTime(data.timestamp);
restoreState(data.customData);
}
});

Ressources

// Résoudre un chemin de ressource
const imagePath = PandaBridge.resolvePath('backgroundImage', '/default.png');
// Obtenir l'objet ressource complet
const resource = PandaBridge.resolveResource('backgroundImage');
if (resource) {
// Accéder aux variantes responsives
const largePath = resource.srcsets?.['1280w'] || resource.path;
}

Propriétés utilitaires

// Vérifier si on est dans le Studio (vs. app publiée)
if (PandaBridge.isStudio) {
// Afficher un placeholder ou mode preview
}
// Obtenir la langue actuelle
const language = PandaBridge.currentLanguage;

Exemple complet

import PandaBridge from 'pandasuite-bridge';
let state = { count: 0 };
PandaBridge.init(() => {
// Charger les données initiales
PandaBridge.onLoad(({ properties }) => {
state.count = properties.initialCount || 0;
render();
});
// Gérer les mises à jour
PandaBridge.onUpdate(({ properties }) => {
if (properties.initialCount !== undefined) {
state.count = properties.initialCount;
render();
}
});
// Gérer les actions
PandaBridge.listen('increment', () => {
state.count++;
render();
PandaBridge.send('onCountChanged', { count: state.count });
});
PandaBridge.listen('reset', () => {
state.count = 0;
render();
PandaBridge.send('onCountChanged', { count: state.count });
});
// Support des snapshots
PandaBridge.getSnapshotData(() => ({ count: state.count }));
PandaBridge.setSnapshotData(({ data }) => {
if (data) {
state.count = data.count;
render();
}
});
});
function render() {
document.getElementById('counter').textContent = state.count;
}

API React PandaBridge

La librairie React fournit des hooks pour une intégration plus facile avec les composants React.

Installation

Fenêtre de terminal
npm install pandasuite-bridge-react

Utilisation de base

import { PandaBridgeRoot, usePandaBridge } from 'pandasuite-bridge-react';
function MyComponent() {
const { properties, setProperty, resources } = usePandaBridge({
actions: {
increment: () => console.log('Increment appelé'),
reset: () => console.log('Reset appelé')
}
});
return (
<div>
<p>Compteur : {properties?.count || 0}</p>
<button onClick={() => setProperty('count', (properties?.count || 0) + 1)}>
Incrémenter
</button>
</div>
);
}
export default function App() {
return (
<PandaBridgeRoot>
<MyComponent />
</PandaBridgeRoot>
);
}

Hook usePandaBridge

const {
properties, // Valeurs actuelles des propriétés
markers, // Données des marqueurs
resources, // Ressources résolues (par ID)
setProperty, // Mettre à jour une propriété
setProperties, // Mettre à jour plusieurs propriétés
addActions // Ajouter des gestionnaires d'actions
} = usePandaBridge({
actions: {
actionName: (args) => { /* gérer l'action */ }
},
synchronization: {
syncGroupId: (value) => { /* gérer la sync */ }
},
markers: {
getSnapshotDataHook: () => ({ /* données du snapshot */ }),
setSnapshotDataHook: (data) => { /* restaurer depuis le snapshot */ }
},
component: {
getScreenshotHook: (callback) => { /* capture d'écran personnalisée */ },
onLanguageChanged: (lang) => { /* gérer le changement de langue */ }
}
});

Accéder aux ressources

function ImageDisplay() {
const { resources } = usePandaBridge();
const backgroundImage = resources?.backgroundImage;
if (!backgroundImage) {
return <div>Aucune image sélectionnée</div>;
}
return <img src={backgroundImage.path} alt="Arrière-plan" />;
}

Composants UI intégrés

La librairie React inclut des composants pré-stylés :

import {
Button,
Input,
Dropdown,
Checkbox,
Alert,
Tabs,
Tab,
Loader
} from 'pandasuite-bridge-react';
function SettingsPanel() {
return (
<div>
<Input placeholder="Entrez une valeur" />
<Dropdown>
<Dropdown.Item value="a">Option A</Dropdown.Item>
<Dropdown.Item value="b">Option B</Dropdown.Item>
</Dropdown>
<Checkbox>Activer la fonctionnalité</Checkbox>
<Button primary>Enregistrer</Button>
<Alert type="info">Paramètres enregistrés avec succès</Alert>
</div>
);
}

Test et publication

Configuration de développement

Commencez avec un projet boilerplate :

Développement local

Fenêtre de terminal
# Installer les dépendances
npm install
# Démarrer le serveur de développement
npm start

Cela démarre un serveur local. Dans PandaSuite Studio :

  1. Ajoutez un composant Web
  2. Entrez votre URL locale (ex: http://localhost:3000)
  3. Cliquez sur Rafraîchir les metadata pour charger votre manifeste

Build pour la production

Fenêtre de terminal
# Créer le zip du composant
npm run build

Cela crée pandasuite-component.zip. Glissez ce fichier sur votre projet PandaSuite pour ajouter le composant.

Publication sur GitHub

Fenêtre de terminal
# Créer une release GitHub
npm run release

Cela publie votre composant en tant que release GitHub, le rendant disponible pour d’autres utilisateurs.

Bonnes pratiques

  • Partez d’un boilerplate : utilisez les templates officiels JavaScript ou React pour assurer une structure de projet correcte
  • Gardez les composants focalisés : chaque composant devrait faire une seule chose bien ; divisez les fonctionnalités complexes en plusieurs composants
  • Utilisez des IDs explicites : les IDs de propriétés, événements et actions doivent être descriptifs et cohérents (ex : onItemSelected plutôt que event1)
  • Fournissez la localisation : ajoutez locale_name pour toutes les chaînes visibles par l’utilisateur pour supporter les utilisateurs français et anglais
  • Gérez le mode Studio : utilisez PandaBridge.isStudio pour afficher des aperçus ou placeholders appropriés lors de l’édition dans le Studio
  • Testez sur toutes les plateformes : vérifiez que votre composant fonctionne sur les exports iOS, Android et web

Limitations

  • Les composants personnalisés nécessitent des compétences en développement web (HTML, CSS, JavaScript)
  • Les composants s’exécutent dans une web view, ce qui peut limiter l’accès à certaines APIs natives de l’appareil
  • Les bundles de composants volumineux peuvent impacter les performances de chargement de l’app

Exemples de composants

Explorez les composants personnalisés existants comme référence :

Voir aussi