Bubble Plugin: ${REPO_NAME}
About:
${REPO_DESCRIPTION}
Features:
- Basic template for building Preact based elements.
- Basic template for building functional elements.
How does it work?
For Preact based element, we register a Preact component as a web component. This resolve the issue of race-condition between Bubble element initialization and code loading.
For Functional elements, we would register a retry pattern until the plugin's code is fully loaded.
How to set up:
Clone and prepare:
Clone this repository, run yarn
to install dependencies.
Add plugin & setup glue code:
Create a Bubble plugin. You can also fork this plugin for a basic template. Remember that you will still have to review and replace the appropriate variables.
For Preact based elements:
-
Create a new Bubble plugin element
-
Add this piece of code into the element header
<script src="https://www.unpkg.com/preact@^10.19.3/dist/preact.umd.js"></script> <script src="https://www.unpkg.com/preact@^10.19.3/hooks/dist/hooks.umd.js"></script> <script src="https://www.unpkg.com/preact@^10.19.3/compat/dist/compat.umd.js"></script> <script src="https://www.unpkg.com/preact-custom-element@^4.3.0/dist/preact-custom-element.umd.js"></script> <script src="https://www.unpkg.com/@preact/signals-core@^1.5.1/dist/signals-core.min.js"></script> <script src="https://www.unpkg.com/@preact/signals@^1.2.2/dist/signals.min.js"></script> <!-- Uncomment this section when you want to develop the plugin. Add a space in between the next arrow to quickly comment the section below --> <script src="http://localhost:5173/@vite/client" type="module"></script> <script src="http://localhost:5173/src/index.ts" type="module"></script> <!-- END_DEV_SCRIPT --> <!-- Uncomment the next lines when you want to deploy to live. Also make sure to update the version of the library. Add a space in between the next arrow to quickly comment the section below -- > <script src="https://www.unpkg.com/@citizendev/${REPO_NAME}@0.0.1/dist/index.umd.js"></script> <link href="https://www.unpkg.com/@citizendev/${REPO_NAME}@0.0.1/dist/style.css" rel="stylesheet" /> <!-- END_PROD_SCRIPT -->
-
Set the
initialize
function content. You would want to match this with the web component names. The example file has this ascounter
, as shown in PasswordInput.tsxfunction(instance, context) { /* SETUP: replace this variable accordingly. Make sure this matches the other instances. */ const ELEMENT_NAME = "counter"; instance.data._elementReady = false; instance.data._element = document.createElement(ELEMENT_NAME); instance.canvas.append(instance.data._element); instance.data._tryInject = function tryInject(retryLeft, properties) { const element = instance.data._element; if (!retryLeft || retryLeft <= 0 || !element) { return; } if (!element._vdom) { setTimeout(() => tryInject(retryLeft - 1, properties), 200); return; } element.properties = properties; if (!element.instance) { element.instance = instance; } if (!element.bubbleContext) { element.bubbleContext = context; } }
-
Set the
update
function content.function(instance, properties, context) { instance.data._tryInject(50, properties); }
-
Set the
preview
function content. Because the preview environment is isolated from the Bubble Editor environment, we have to do a full in script loading of the resourcesfunction(instance, properties) { function loadJS(url, module = false) { return new Promise((resolve, reject) => { let scriptEle = document.createElement("script"); document.head.appendChild(scriptEle); scriptEle.onload = function () { resolve(); } scriptEle.setAttribute("type", module ? "module" : "text/javascript" ); scriptEle.setAttribute("src", url); }); } /* Make the appropriate changes to the following lines */ const DEV = false; const ELEMENT_NAME = "counter"; const PACKAGE_LINK = "https://www.unpkg.com/@citizendev/bubble-file-uploader@0.1.2"; let jsLink, cssLink; if (DEV) { cssLink = "http://localhost:5173/src/style.css" jsLink = "http://localhost:5173/src/index.ts"; } else { cssLink = `${PACKAGE_LINK}/dist/style.css`; jsLink = `${PACKAGE_LINK}/dist/index.umd.js`; } jQuery("html").height("100%"); jQuery("body").height("100%"); jQuery("head").append(`<link rel="stylesheet" href="${cssLink}" />`); (async () => { if (DEV) { await loadJS("http://localhost:5173/@vite/client", true); } await loadJS("https://www.unpkg.com/preact@^10.19.3/dist/preact.umd.js"); await loadJS("https://www.unpkg.com/preact@^10.19.3/hooks/dist/hooks.umd.js"); await loadJS("https://www.unpkg.com/preact@^10.19.3/compat/dist/compat.umd.js"); await loadJS("https://www.unpkg.com/preact-custom-element@^4.3.0/dist/preact-custom-element.umd.js"); await loadJS("https://www.unpkg.com/@preact/signals-core@^1.5.1/dist/signals-core.min.js"); await loadJS("https://www.unpkg.com/@preact/signals@^1.2.2/dist/signals.min.js"); await loadJS(jsLink, DEV); const element = document.createElement(ELEMENT_NAME); instance.canvas.append(element); function tryInject(retryLeft, properties) { if (!retryLeft || retryLeft <= 0 || !element) { return; } if (!element._vdom) { setTimeout(() => tryInject(retryLeft - 1, properties), 200); return; } element.properties = properties; if (!element.instance) { element.instance = instance; element.isPreview = true; } } tryInject(25, properties); })(); }
-
Open test app.