diff --git a/src/components/Composer.tsx b/src/components/Composer.tsx
index 5ab7e23..16ea114 100644
--- a/src/components/Composer.tsx
+++ b/src/components/Composer.tsx
@@ -1,11 +1,13 @@
-import { StyleSheet, TextInput, View } from "react-native";
+import { StyleSheet, View } from "react-native";
import { Text } from "./primitive/Text";
import { Button } from "./primitive/Button";
-import { useContext, useEffect, useMemo, useState } from "react";
+import { useContext, useEffect, useState } from "react";
import { AuthContext } from "../context/AuthContext";
import { Profile, resolveProfile } from "../lib/profile";
import { RichTextEditor } from "../lib/richtext/editor";
import { useRouter } from "expo-router";
+import { RichTextContent } from "../lib/richtext";
+import { dev } from "../lexicons";
const styles = StyleSheet.create({
composerHeader: {
@@ -61,10 +63,14 @@ function ComposerHeader() {
);
}
-function ComposerBody() {
+function ComposerBody({
+ onChange,
+}: {
+ onChange: (content: RichTextContent) => void;
+}) {
return (
-
+
);
}
@@ -72,34 +78,57 @@ function ComposerBody() {
function ComposerFooter({
onPublish,
onCancel,
+ disabled,
}: {
onPublish: () => void;
onCancel: () => void;
+ disabled?: boolean;
}) {
return (
-
-
+
+
);
}
export default function Composer() {
- const router = useRouter()
+ const router = useRouter();
+ const [publishing, setPublishing] = useState(false);
+ const [content, setContent] = useState([])
+ const authCtx = useContext(AuthContext)
const dismiss = () => {
- router.canDismiss() ? router.dismiss() : router.navigate('/')
- }
+ router.canDismiss() ? router.dismiss() : router.navigate("/");
+ };
- const publish = () => {
- // dismiss()
- }
+ // TODO: Disable modal dismissal (ie by clicking background) when this is true
+ const publish = async () => {
+ setPublishing(true);
+ await authCtx.client?.create(dev.maelstrom.bramblr.post, {
+ content: content,
+ thread: [],
+ createdAt: new Date().toISOString() as any, // TODO: Fix this
+ })
+ dismiss()
+ };
return (
-
-
+
+
+ {/* TODO: Add preview */}
+ {/* */}
);
}
diff --git a/src/components/primitive/Button.tsx b/src/components/primitive/Button.tsx
index 485c245..0ee9574 100644
--- a/src/components/primitive/Button.tsx
+++ b/src/components/primitive/Button.tsx
@@ -15,6 +15,14 @@ const styles = StyleSheet.create({
backgroundColor: "#0084ff",
borderColor: "#0084ff",
},
+ buttonDisabledPrimary: {
+ backgroundColor: "#1e5b95",
+ borderColor: "#1e5b95",
+ },
+ buttonDisabled: {
+ backgroundColor: "#535353",
+ borderColor: "#535353",
+ },
buttonText: {
color: "#fff",
fontSize: 15,
@@ -25,14 +33,17 @@ export function Button({
text,
onPress,
primary,
+ disabled,
}: {
text: string;
onPress?: () => void;
primary?: boolean;
+ disabled?: boolean;
}) {
return (
onPress() : undefined}
>
{text}
diff --git a/src/components/primitive/Select.tsx b/src/components/primitive/Select.tsx
index a76649f..fd349ba 100644
--- a/src/components/primitive/Select.tsx
+++ b/src/components/primitive/Select.tsx
@@ -1,7 +1,6 @@
import React, {
ReactElement,
ReactNode,
- useEffect,
useMemo,
useState,
} from "react";
@@ -37,12 +36,9 @@ export function Select({
const [selected, setSelected] = useState(defaultElement);
const [open, setOpen] = useState(false);
- useEffect(() => {
- onSelected && onSelected((selected.props as any).name);
- }, [selected]);
-
const select = (e: ReactElement) => {
setSelected(e)
+ onSelected && onSelected((e.props as any).name);
setOpen(false)
}
diff --git a/src/lib/richtext/convert.ts b/src/lib/richtext/convert.ts
new file mode 100644
index 0000000..4643a51
--- /dev/null
+++ b/src/lib/richtext/convert.ts
@@ -0,0 +1,63 @@
+import { $Typed } from "@atproto/lex";
+import { RichTextContent, RichTextEmphasis } from ".";
+import { RichTextFacet } from "./richtext";
+
+function facetsFromChildren(children: any[]): [string, RichTextFacet[]] {
+ let text = "";
+ const facets: RichTextFacet[] = [];
+
+ for (const child of children) {
+ const start = new Blob([text]).size;
+ const end = start + new Blob([child.text]).size;
+ text += child.text;
+
+ const features: RichTextFacet["features"] = []
+
+ // Add emphasis facet
+ if (child.bold || child.italic || child.strike || child.small) {
+ const emphasisFacet: $Typed = {
+ "$type": "dev.maelstrom.bramblr.richtext.facet#emphasis",
+ bold: child.bold,
+ italic: child.italic,
+ strike: child.strike,
+ small: child.small,
+ };
+
+ features.push(emphasisFacet)
+ }
+
+ // Add a facet if any features exist
+ if (features.length > 0) {
+ facets.push({
+ $type: "dev.maelstrom.bramblr.richtext.facet",
+ index: {
+ byteStart: start,
+ byteEnd: end,
+ },
+ features: features,
+ });
+ }
+ }
+
+ return [text, facets];
+}
+
+export function slateToLex(value: any[]): RichTextContent {
+ return value.map((block) => {
+ switch (block.type) {
+ case "paragraph":
+ const [text, facets] = facetsFromChildren(block.children);
+ return {
+ $type: "dev.maelstrom.bramblr.richtext.block#text",
+ format: block.format ?? "regular",
+ text: text,
+ facets: facets,
+ };
+ default:
+ throw "Unknown block type";
+ }
+ });
+}
+
+// [{"type":"paragraph","children":[{"text":"A line o"},
+// {"text":"f text in ","bold":true},{"text":"a paragraph."}],"format":"regular"}]
diff --git a/src/lib/richtext/editor-dom.tsx b/src/lib/richtext/editor-dom.tsx
index 52f0078..00b876d 100644
--- a/src/lib/richtext/editor-dom.tsx
+++ b/src/lib/richtext/editor-dom.tsx
@@ -1,12 +1,10 @@
"use dom";
import { Ref, useCallback, useState } from "react";
-import { StyleSheet } from "react-native";
import { createEditor, Editor, Path, Selection, Transforms } from "slate";
import { withHistory } from "slate-history";
import {
Editable,
- ReactEditor,
RenderElementProps,
RenderLeafProps,
Slate,
@@ -18,6 +16,8 @@ import {
useDOMImperativeHandle,
} from "expo/dom";
import { JSONValue } from "expo/build/dom/dom.types";
+import { slateToLex } from "./convert";
+import { RichTextContent } from ".";
const formatStyles = {
default: {
@@ -73,9 +73,11 @@ export interface DOMEditorRef extends DOMImperativeFactory {
export function DOMEditor({
onMoveToolbar,
+ onChange,
ref,
}: {
onMoveToolbar: (pos?: DOMRect) => void;
+ onChange: (content: RichTextContent) => void,
ref?: Ref;
dom?: DOMProps;
}) {
@@ -136,11 +138,16 @@ export function DOMEditor({
}
};
+ const onChangeInner = (value: any) => {
+ onChange(slateToLex(value))
+ }
+
return (
void }) {
const editor = useRef(null);
const [pos, setPos] = useState<[number, number] | undefined>(undefined);
@@ -86,7 +88,7 @@ export function RichTextEditor({
return (
-
+
{pos && }
);
diff --git a/src/lib/richtext/index.ts b/src/lib/richtext/index.ts
new file mode 100644
index 0000000..c7c0e8e
--- /dev/null
+++ b/src/lib/richtext/index.ts
@@ -0,0 +1,2 @@
+export { Content as RichTextContent } from "@/src/lexicons/dev/maelstrom/bramblr/richtext/block.defs";
+export { Emphasis as RichTextEmphasis } from "@/src/lexicons/dev/maelstrom/bramblr/richtext/facet.defs";