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": {}}| Champ | Description |
|---|---|
version | Version du manifeste (actuelle : "2.0.0") |
main | URL du point d’entrée (généralement vide "" pour les composants PandaBridge) |
properties | Options de configuration affichées dans le panneau de propriétés |
events | Déclencheurs qui peuvent activer des actions sur d’autres composants |
actions | Opérations que d’autres composants peuvent appeler |
resources | Emplacements pour les médias (images, vidéos, audio, fichiers zip) |
markers | Points de données définis par l’utilisateur |
synchronization | Groupes pour la synchronisation d’état entre composants |
queryable | Données exposées pour le data binding |
system | Paramè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
| Type | Description | Contrôle UI |
|---|---|---|
String | Valeur texte | Champ de texte |
Boolean | Vrai/faux | Case à cocher |
Integer | Nombre entier | Champ numérique |
Float | Nombre décimal | Champ numérique |
Color | Valeur couleur | Sélecteur de couleur |
Dropdown | Sélection dans une liste | Menu déroulant |
Image, Video, Audio | Ressource média | Sélecteur de fichier |
Bind | Expression de data binding | Éditeur de binding |
JSON | Données structurées | Éditeur JSON |
Code | Code avec coloration syntaxique | Éditeur de code |
Selection | Référence à un autre composant | Sélecteur de composant |
Options des propriétés
| Option | Type | Description |
|---|---|---|
id | string | Identifiant unique (utilisé dans le code) |
name | string | Nom affiché dans le Studio |
locale_name | object | Noms localisés (ex: { "fr_FR": "Nom" }) |
type | string | Type de propriété |
value | any | Valeur par défaut |
bindable | boolean | Autoriser le data binding |
required | boolean | Marquer comme requis |
hidden | string | boolean | Expression de visibilité conditionnelle |
placeholder | string | Texte indicatif pour les champs |
separator | boolean | Afficher 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
npm install pandasuite-bridgeInitialisation
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 composantPandaBridge.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 changentPandaBridge.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énementPandaBridge.send('onItemSelected', { itemId: 'item-123', itemName: 'Selected Item'});
// Déclencher un événement de marqueurPandaBridge.send(PandaBridge.SYNCHRONIZE, [markerData, 'markerName']);Écouter les actions
// Écouter une action spécifiquePandaBridge.listen('setVolume', ([level]) => { setVolume(level);});
// Écouter toutes les actionsPandaBridge.listen((action, args) => { console.log('Action reçue:', action, args);});Synchronisation
// Envoyer des données de synchronisationPandaBridge.send(PandaBridge.SYNCHRONIZE, [currentValue, 'syncGroupId']);
// Recevoir des données de synchronisationPandaBridge.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 snapshotPandaBridge.setSnapshotData(({ data }) => { if (data) { setCurrentTime(data.timestamp); restoreState(data.customData); }});Ressources
// Résoudre un chemin de ressourceconst imagePath = PandaBridge.resolvePath('backgroundImage', '/default.png');
// Obtenir l'objet ressource completconst 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 actuelleconst 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
npm install pandasuite-bridge-reactUtilisation 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 :
- JavaScript : js-boilerplate-component
- React : react-boilerplate-component
Développement local
# Installer les dépendancesnpm install
# Démarrer le serveur de développementnpm startCela démarre un serveur local. Dans PandaSuite Studio :
- Ajoutez un composant Web
- Entrez votre URL locale (ex:
http://localhost:3000) - Cliquez sur Rafraîchir les metadata pour charger votre manifeste
Build pour la production
# Créer le zip du composantnpm run buildCela crée pandasuite-component.zip. Glissez ce fichier sur votre projet PandaSuite pour ajouter le composant.
Publication sur GitHub
# Créer une release GitHubnpm run releaseCela 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 :
onItemSelectedplutôt queevent1) - Fournissez la localisation : ajoutez
locale_namepour toutes les chaînes visibles par l’utilisateur pour supporter les utilisateurs français et anglais - Gérez le mode Studio : utilisez
PandaBridge.isStudiopour 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 :
- react-media-player-component : lecteur média par URL
- react-qr-reader-component : scanner de QR code
- after-effects-component : animations Lottie
- Plus de composants sur GitHub
Voir aussi
- Composant Web : intégrer du contenu web sans PandaBridge
- Data binding : connecter des données aux propriétés des composants
- Actions interactives : déclencher des comportements entre composants
- Déclencheurs : événements qui activent des actions