diff --git a/packages/bbui/package.json b/packages/bbui/package.json
index c9e8c8873c..0fdd23f349 100644
--- a/packages/bbui/package.json
+++ b/packages/bbui/package.json
@@ -79,6 +79,7 @@
"@spectrum-css/underlay": "^2.0.9",
"@spectrum-css/vars": "^3.0.1",
"dayjs": "^1.10.4",
+ "easymde": "^2.16.1",
"svelte-flatpickr": "^3.2.3",
"svelte-portal": "^1.0.0"
},
diff --git a/packages/bbui/src/Form/Core/RichTextField.svelte b/packages/bbui/src/Form/Core/RichTextField.svelte
new file mode 100644
index 0000000000..f964405f0d
--- /dev/null
+++ b/packages/bbui/src/Form/Core/RichTextField.svelte
@@ -0,0 +1,42 @@
+
+
+
+ import Field from "./Field.svelte"
+ import RichTextField from "./Core/RichTextField.svelte"
+ import { createEventDispatcher } from "svelte"
+
+ export let value = null
+ export let label = null
+ export let labelPosition = "above"
+ export let placeholder = null
+ export let disabled = false
+ export let error = null
+ export let height = null
+ export let id = null
+ export let fullScreenOffset = null
+ export let easyMDEOptions = null
+
+ const dispatch = createEventDispatcher()
+ const onChange = e => {
+ value = e.detail
+ dispatch("change", e.detail)
+ }
+
+
+
+
+
diff --git a/packages/bbui/src/Markdown/MarkdownEditor.svelte b/packages/bbui/src/Markdown/MarkdownEditor.svelte
new file mode 100644
index 0000000000..7fb6414ad8
--- /dev/null
+++ b/packages/bbui/src/Markdown/MarkdownEditor.svelte
@@ -0,0 +1,60 @@
+
+
+{#key height}
+
+{/key}
diff --git a/packages/bbui/src/Markdown/MarkdownViewer.svelte b/packages/bbui/src/Markdown/MarkdownViewer.svelte
new file mode 100644
index 0000000000..5705020f45
--- /dev/null
+++ b/packages/bbui/src/Markdown/MarkdownViewer.svelte
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
diff --git a/packages/bbui/src/Markdown/SpectrumMDE.svelte b/packages/bbui/src/Markdown/SpectrumMDE.svelte
new file mode 100644
index 0000000000..9b0832c91f
--- /dev/null
+++ b/packages/bbui/src/Markdown/SpectrumMDE.svelte
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
diff --git a/packages/bbui/src/index.js b/packages/bbui/src/index.js
index 16f069f4e7..ea5486aadc 100644
--- a/packages/bbui/src/index.js
+++ b/packages/bbui/src/index.js
@@ -60,6 +60,9 @@ export { default as StatusLight } from "./StatusLight/StatusLight.svelte"
export { default as ColorPicker } from "./ColorPicker/ColorPicker.svelte"
export { default as InlineAlert } from "./InlineAlert/InlineAlert.svelte"
export { default as Banner } from "./Banner/Banner.svelte"
+export { default as MarkdownEditor } from "./Markdown/MarkdownEditor.svelte"
+export { default as MarkdownViewer } from "./Markdown/MarkdownViewer.svelte"
+export { default as RichTextField } from "./Form/RichTextField.svelte"
// Renderers
export { default as BoldRenderer } from "./Table/BoldRenderer.svelte"
diff --git a/packages/bbui/yarn.lock b/packages/bbui/yarn.lock
index 42c88af5a4..1a4f5e4417 100644
--- a/packages/bbui/yarn.lock
+++ b/packages/bbui/yarn.lock
@@ -271,6 +271,13 @@
resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.2.tgz#ea9062c3c98dfc6ba59e5df14a03025ad8969999"
integrity sha512-vzS9KqYXot4J3AEER/u618MXWAS+IoMvYMNrOoscKiLLKYQWenaueakUWulFonToPd/9vIpqtdbwxznqrK5qDw==
+"@types/codemirror@^5.60.4":
+ version "5.60.5"
+ resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-5.60.5.tgz#5b989a3b4bbe657458cf372c92b6bfda6061a2b7"
+ integrity sha512-TiECZmm8St5YxjFUp64LK0c8WU5bxMDt9YaAek1UqUb9swrSCoJhh92fWu1p3mTEqlHjhB5sY7OFBhWroJXZVg==
+ dependencies:
+ "@types/tern" "*"
+
"@types/estree@*":
version "0.0.47"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.47.tgz#d7a51db20f0650efec24cd04994f523d93172ed4"
@@ -281,6 +288,11 @@
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
+"@types/marked@^4.0.1":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.2.tgz#cb2dbf10da2f41cf20bd91fb5f89b67540c282f7"
+ integrity sha512-auNrZ/c0w6wsM9DccwVxWHssrMDezHUAXNesdp2RQrCVCyrQbOiSq7yqdJKrUQQpw9VTm7CGYJH2A/YG7jjrjQ==
+
"@types/node@*":
version "14.14.41"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.41.tgz#d0b939d94c1d7bd53d04824af45f1139b8c45615"
@@ -303,6 +315,13 @@
dependencies:
"@types/node" "*"
+"@types/tern@*":
+ version "0.23.4"
+ resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.4.tgz#03926eb13dbeaf3ae0d390caf706b2643a0127fb"
+ integrity sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==
+ dependencies:
+ "@types/estree" "*"
+
accepts@~1.3.7:
version "1.3.7"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
@@ -525,6 +544,18 @@ coa@^2.0.2:
chalk "^2.4.1"
q "^1.1.2"
+codemirror-spell-checker@1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/codemirror-spell-checker/-/codemirror-spell-checker-1.1.2.tgz#1c660f9089483ccb5113b9ba9ca19c3f4993371e"
+ integrity sha1-HGYPkIlIPMtRE7m6nKGcP0mTNx4=
+ dependencies:
+ typo-js "*"
+
+codemirror@^5.63.1:
+ version "5.65.1"
+ resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.1.tgz#5988a812c974c467f964bcc1a00c944e373de502"
+ integrity sha512-s6aac+DD+4O2u1aBmdxhB7yz2XU7tG3snOyQ05Kxifahz7hoxnfxIRHxiCSEv3TUC38dIVH8G+lZH9UWSfGQxA==
+
color-convert@^1.9.0, color-convert@^1.9.1:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@@ -861,6 +892,17 @@ dot-prop@^5.2.0:
dependencies:
is-obj "^2.0.0"
+easymde@^2.16.1:
+ version "2.16.1"
+ resolved "https://registry.yarnpkg.com/easymde/-/easymde-2.16.1.tgz#f4c2380312615cb33826f1a1fecfaa4022ff551a"
+ integrity sha512-FihYgjRsKfhGNk89SHSqxKLC4aJ1kfybPWW6iAmtb5GnXu+tnFPSzSaGBmk1RRlCuhFSjhF0SnIMGVPjEzkr6g==
+ dependencies:
+ "@types/codemirror" "^5.60.4"
+ "@types/marked" "^4.0.1"
+ codemirror "^5.63.1"
+ codemirror-spell-checker "1.1.2"
+ marked "^4.0.10"
+
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -1472,6 +1514,11 @@ magic-string@^0.25.7:
dependencies:
sourcemap-codec "^1.4.4"
+marked@^4.0.10:
+ version "4.0.12"
+ resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.12.tgz#2262a4e6fd1afd2f13557726238b69a48b982f7d"
+ integrity sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==
+
mdn-data@2.0.14:
version "2.0.14"
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
@@ -2490,6 +2537,11 @@ type-is@~1.6.17, type-is@~1.6.18:
media-typer "0.3.0"
mime-types "~2.1.24"
+typo-js@*:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/typo-js/-/typo-js-1.2.1.tgz#334a0d8c3f6c56f2f1e15fdf6c31677793cbbe9b"
+ integrity sha512-bTGLjbD3WqZDR3CgEFkyi9Q/SS2oM29ipXrWfDb4M74ea69QwKAECVceYpaBu0GfdnASMg9Qfl67ttB23nePHg==
+
unbox-primitive@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471"
diff --git a/packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js b/packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js
index ae45b4f25d..9fe8cc9563 100644
--- a/packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js
+++ b/packages/builder/src/builderStore/store/screenTemplates/utils/commonComponents.js
@@ -169,6 +169,11 @@ export function makeDatasourceFormComponents(datasource) {
optionsSource: "schema",
})
}
+ if (fieldType === "longform") {
+ component.customProps({
+ format: "auto",
+ })
+ }
if (fieldType === "array") {
component.customProps({
placeholder: "Choose an option",
diff --git a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte
index 0d9ca3644b..8ab6d75c5d 100644
--- a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte
+++ b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte
@@ -4,9 +4,10 @@
Select,
DatePicker,
Toggle,
- TextArea,
Multiselect,
Label,
+ RichTextField,
+ TextArea,
} from "@budibase/bbui"
import Dropzone from "components/common/Dropzone.svelte"
import { capitalise } from "helpers"
@@ -43,7 +44,11 @@
{:else if type === "link"}
{:else if type === "longform"}
-
+ {#if meta.useRichText}
+
+ {:else}
+
+ {/if}
{:else if type === "json"}
{label}
- Search Indexes
+ Search Indexes
+ {:else if field.type === "longform"}
+
+
+ Formatting
+
+
+
{:else if field.type === "array"}
- import { getContext } from "svelte"
+ import { getContext, setContext } from "svelte"
+ import { writable } from "svelte/store"
import { Heading, Icon } from "@budibase/bbui"
import { FieldTypes } from "../../constants"
import active from "svelte-spa-router/active"
@@ -29,6 +30,16 @@
Small: "s",
}
+ // Set some layout context. This isn't used in bindings but can be used
+ // determine things about the current app layout.
+ $: mobile = $context.device.mobile
+ const store = writable({ headerHeight: 0 })
+ $: store.set({
+ screenXOffset: getScreenXOffset(navigation, mobile),
+ screenYOffset: getScreenYOffset(navigation, mobile),
+ })
+ setContext("layout", store)
+
// Permanently go into peek mode if we ever get the peek flag
let isPeeking = false
$: {
@@ -58,13 +69,27 @@
if ($builderStore.inBuilder) return
window.location.href = "/builder/apps"
}
+
+ const getScreenXOffset = (navigation, mobile) => {
+ if (navigation !== "Left") {
+ return 0
+ }
+ return mobile ? "0px" : "250px"
+ }
+ const getScreenYOffset = (navigation, mobile) => {
+ if (mobile) {
+ return !navigation || navigation === "None" ? 0 : "61px"
+ } else {
+ return navigation === "Top" ? "137px" : "0px"
+ }
+ }
{#if typeClass !== "none"}
+ import { MarkdownViewer } from "@budibase/bbui"
+ import { getContext } from "svelte"
+ import Placeholder from "./Placeholder.svelte"
+
+ export let value
+
+ const component = getContext("component")
+ const { builderStore, styleable } = getContext("sdk")
+ const height = $component.styles?.normal?.height
+
+
+
+ {#if value}
+
+ {:else if $builderStore.inBuilder}
+
+ {/if}
+
diff --git a/packages/client/src/components/app/forms/LongFormField.svelte b/packages/client/src/components/app/forms/LongFormField.svelte
index 888992f6b3..15a10827b2 100644
--- a/packages/client/src/components/app/forms/LongFormField.svelte
+++ b/packages/client/src/components/app/forms/LongFormField.svelte
@@ -1,7 +1,8 @@
{#if fieldState}
-
+ {#if useRichText}
+ fieldApi.setValue(e.detail)}
+ disabled={fieldState.disabled}
+ error={fieldState.error}
+ id={fieldState.fieldId}
+ {placeholder}
+ {height}
+ fullScreenOffset={{
+ x: $layout.screenXOffset,
+ y: $layout.screenYOffset,
+ }}
+ easyMDEOptions={{
+ hideIcons: $context.device.mobile ? ["side-by-side", "guide"] : [],
+ }}
+ />
+ {:else}
fieldApi.setValue(e.detail)}
disabled={fieldState.disabled}
error={fieldState.error}
id={fieldState.fieldId}
- {align}
{placeholder}
+ minHeight={height}
/>
-
+ {/if}
{/if}
-
-
diff --git a/packages/client/src/components/app/index.js b/packages/client/src/components/app/index.js
index ef0f96ce59..5af62201e5 100644
--- a/packages/client/src/components/app/index.js
+++ b/packages/client/src/components/app/index.js
@@ -30,6 +30,7 @@ export { default as daterangepicker } from "./DateRangePicker.svelte"
export { default as cardstat } from "./CardStat.svelte"
export { default as spectrumcard } from "./SpectrumCard.svelte"
export { default as tag } from "./Tag.svelte"
+export { default as markdownviewer } from "./MarkdownViewer.svelte"
export * from "./charts"
export * from "./forms"
export * from "./table"