diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..afaa6dc
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,30 @@
+name: Release
+
+on:
+ push:
+ branches:
+ - master
+ - main
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v1
+ with:
+ node-version: 16
+ - name: Make the production plugin bundle
+ run: |
+ release_version=$(cat package.json | jq -r '.version')
+ echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV
+ yarn
+ yarn build
+ - name: Perform Github Release
+ uses: softprops/action-gh-release@v1
+ with:
+ name: v${{ env.RELEASE_VERSION }}
+ tag_name: v${{ env.RELEASE_VERSION }}
+ generate_release_notes: true
+ files: |
+ dist/*.tar.gz
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6706b91
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,106 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+
+# Next.js build output
+.next
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and *not* Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+.idea/
diff --git a/.npmignore b/.npmignore
new file mode 100644
index 0000000..aeff293
--- /dev/null
+++ b/.npmignore
@@ -0,0 +1,3 @@
+node_modules
+.github
+rollup.config.js
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d43108e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,20 @@
+# Budibase-component
+This is a readme for your new Budibase plugin.
+
+# Description
+An amazing Budibase component!
+
+Find out more about [Budibase](https://github.com/Budibase/budibase).
+
+## Instructions
+
+To build your new plugin run the following in your Budibase CLI:
+```
+budi plugins --build
+```
+
+You can also re-build everytime you make a change to your plugin with the command:
+```
+budi plugins --watch
+```
+
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..91535e1
--- /dev/null
+++ b/index.js
@@ -0,0 +1,18 @@
+import Wrapper from "./lib/Wrapper.svelte"
+import schema from "./schema.json"
+import pkg from "./package.json"
+
+if (window) {
+ const plugin = { Component: Wrapper, schema, version: pkg.version }
+ if (!window["##BUDIBASE_CUSTOM_COMPONENTS##"]) {
+ window["##BUDIBASE_CUSTOM_COMPONENTS##"] = []
+ }
+ window["##BUDIBASE_CUSTOM_COMPONENTS##"].push(plugin)
+ if (window.registerCustomComponent) {
+ window.registerCustomComponent(plugin)
+ }
+}
+
+export const Component = Wrapper
+export const version = pkg.version
+export { schema }
diff --git a/lib/Boundary.js b/lib/Boundary.js
new file mode 100644
index 0000000..0e75577
--- /dev/null
+++ b/lib/Boundary.js
@@ -0,0 +1,4 @@
+import Boundary from "./Boundary.svelte"
+import { createBoundary } from "@crownframework/svelte-error-boundary"
+
+export default createBoundary(Boundary);
\ No newline at end of file
diff --git a/lib/Boundary.svelte b/lib/Boundary.svelte
new file mode 100644
index 0000000..64e2cc9
--- /dev/null
+++ b/lib/Boundary.svelte
@@ -0,0 +1,51 @@
+
+
+
+{#if $error}
+
+
There was an error running the "{pkg.name}" plugin:
+
+ {$error}
+
+
+{:else}
+
+{/if}
+
+
\ No newline at end of file
diff --git a/lib/Wrapper.svelte b/lib/Wrapper.svelte
new file mode 100644
index 0000000..2c50d40
--- /dev/null
+++ b/lib/Wrapper.svelte
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..0d93c8c
--- /dev/null
+++ b/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "budibase-component-dropdown-list",
+ "version": "1.0.0",
+ "description": "A dropdown list Budibase component",
+ "license": "MIT",
+ "svelte": "index.js",
+ "module": "dist/plugin.min.js",
+ "scripts": {
+ "build": "rollup -c",
+ "watch": "rollup -cw"
+ },
+ "dependencies": {
+ "@crownframework/svelte-error-boundary": "^1.0.3",
+ "svelte": "^3.49.0",
+ "svelte-outclick": "^3.3.3"
+ },
+ "devDependencies": {
+ "@budibase/backend-core": "^2.0.13",
+ "@rollup/plugin-commonjs": "^18.0.0",
+ "@rollup/plugin-node-resolve": "^11.2.1",
+ "npm-run-all": "^4.1.5",
+ "postcss": "^8.2.10",
+ "rollup": "^2.44.0",
+ "rollup-plugin-copy2": "^0.3.1",
+ "rollup-plugin-json": "^4.0.0",
+ "rollup-plugin-polyfill-node": "^0.8.0",
+ "rollup-plugin-postcss": "^4.0.0",
+ "rollup-plugin-svelte": "^7.1.0",
+ "rollup-plugin-svg": "^2.0.0",
+ "rollup-plugin-terser": "^7.0.2",
+ "tar": "^6.1.11"
+ }
+}
diff --git a/rollup.config.js b/rollup.config.js
new file mode 100644
index 0000000..ddb2b4c
--- /dev/null
+++ b/rollup.config.js
@@ -0,0 +1,122 @@
+import commonjs from "@rollup/plugin-commonjs"
+import resolve from "@rollup/plugin-node-resolve"
+import svelte from "rollup-plugin-svelte"
+import { terser } from "rollup-plugin-terser"
+import postcss from "rollup-plugin-postcss"
+import svg from "rollup-plugin-svg"
+import json from "rollup-plugin-json"
+import nodePolyfills from "rollup-plugin-polyfill-node"
+import copy from "rollup-plugin-copy2"
+import tar from "tar"
+import fs from "fs"
+import pkg from "./package.json"
+import crypto from "crypto"
+import { validate } from "@budibase/backend-core/plugins"
+
+const ignoredWarnings = [
+ "unused-export-let",
+ "css-unused-selector",
+ "module-script-reactive-declaration",
+ "a11y-no-onchange",
+]
+
+// Custom plugin to clean the dist folder before building
+const clean = () => ({
+ buildStart() {
+ const dist = "./dist/"
+ if (fs.existsSync(dist)) {
+ fs.readdirSync(dist).forEach(path => {
+ if (path.endsWith(".tar.gz")) {
+ fs.unlinkSync(dist + path)
+ }
+ })
+ }
+ },
+})
+
+// Custom plugin to hash the JS bundle and write it in the schema
+const hash = () => ({
+ writeBundle() {
+ // Generate JS hash
+ const fileBuffer = fs.readFileSync("dist/plugin.min.js")
+ const hashSum = crypto.createHash("sha1")
+ hashSum.update(fileBuffer)
+ const hex = hashSum.digest("hex")
+
+ // Read and parse existing schema from dist folder
+ const schema = JSON.parse(fs.readFileSync("./dist/schema.json", "utf8"))
+
+ // Write updated schema to dist folder, pretty printed as JSON again
+ const newSchema = {
+ ...schema,
+ hash: hex,
+ version: pkg.version,
+ }
+ fs.writeFileSync("./dist/schema.json", JSON.stringify(newSchema, null, 2))
+ },
+})
+
+// Custom plugin to bundle up our files after building
+const bundle = () => ({
+ async writeBundle() {
+ const bundleName = `${pkg.name}-${pkg.version}.tar.gz`
+ return tar
+ .c({ gzip: true, cwd: "dist" }, [
+ "plugin.min.js",
+ "schema.json",
+ "package.json",
+ ])
+ .pipe(fs.createWriteStream(`dist/${bundleName}`))
+ },
+})
+
+const validateSchema = () => ({
+ buildStart() {
+ const schema = fs.readFileSync("schema.json", "utf8")
+ validate(JSON.parse(schema))
+ }
+})
+
+export default {
+ input: "index.js",
+ output: {
+ sourcemap: process.env.ROLLUP_WATCH ? "inline" : false,
+ format: "iife",
+ file: "dist/plugin.min.js",
+ name: "plugin",
+ globals: {
+ svelte: "svelte",
+ "svelte/internal": "svelte_internal",
+ },
+ },
+ external: ["svelte", "svelte/internal"],
+ plugins: [
+ validateSchema(),
+ clean(),
+ svelte({
+ emitCss: true,
+ onwarn: (warning, handler) => {
+ // Ignore some warnings
+ if (!ignoredWarnings.includes(warning.code)) {
+ handler(warning)
+ }
+ },
+ }),
+ postcss(),
+ commonjs(),
+ nodePolyfills(),
+ resolve({
+ preferBuiltins: true,
+ browser: true,
+ skip: ["svelte", "svelte/internal"],
+ }),
+ svg(),
+ json(),
+ terser(),
+ copy({
+ assets: ["schema.json", "package.json"],
+ }),
+ hash(),
+ bundle(),
+ ],
+}
diff --git a/schema.json b/schema.json
new file mode 100644
index 0000000..ccdeaa1
--- /dev/null
+++ b/schema.json
@@ -0,0 +1,14 @@
+{
+ "type": "component",
+ "metadata": {},
+ "schema": {
+ "name": "dropdown-list",
+ "friendlyName": "Dropdown List",
+ "description": "A dropdown list Budibase component",
+ "icon": "Button",
+ "hasChildren": true,
+ "illegalChildren": ["section"],
+ "showSettingsBar": true,
+ "settings": []
+ }
+}
diff --git a/screenshots/1.jpg b/screenshots/1.jpg
new file mode 100644
index 0000000..efc8abe
Binary files /dev/null and b/screenshots/1.jpg differ
diff --git a/screenshots/2.gif b/screenshots/2.gif
new file mode 100644
index 0000000..e8a2588
Binary files /dev/null and b/screenshots/2.gif differ
diff --git a/src/Component.svelte b/src/Component.svelte
new file mode 100644
index 0000000..ce1986b
--- /dev/null
+++ b/src/Component.svelte
@@ -0,0 +1,48 @@
+
+
+
+
(active = false)}>
+
+
+ {#if active === true}
+
+
+
+ {/if}
+
+
+
+