From 14d5a7b5a7287f23e375fe4b7a220323b39c9404 Mon Sep 17 00:00:00 2001
From: umaranis <mail@umaranis.com>
Date: Wed, 13 Nov 2024 21:56:41 +1100
Subject: [PATCH] feat: Action bar button to toggle read-only mode and move
 isEditable context into Composer

---
 .../lib/components/actionbar/ActionBar.svelte  |  2 ++
 .../components/actionbar/ReadonlyButton.svelte | 17 +++++++++++++++++
 .../src/lib/components/toolbar/Toolbar.svelte  | 10 ----------
 .../src/lib/core/Composer.svelte               | 18 ++++++++++++------
 4 files changed, 31 insertions(+), 16 deletions(-)
 create mode 100644 packages/svelte-lexical/src/lib/components/actionbar/ReadonlyButton.svelte

diff --git a/packages/svelte-lexical/src/lib/components/actionbar/ActionBar.svelte b/packages/svelte-lexical/src/lib/components/actionbar/ActionBar.svelte
index 77426379..929c94a5 100644
--- a/packages/svelte-lexical/src/lib/components/actionbar/ActionBar.svelte
+++ b/packages/svelte-lexical/src/lib/components/actionbar/ActionBar.svelte
@@ -1,9 +1,11 @@
 <script lang="ts">
   import ImportButton from './ImportButton.svelte';
   import ExportButton from './ExportButton.svelte';
+  import ReadonlyButton from './ReadonlyButton.svelte';
 </script>
 
 <div class="actions">
   <ImportButton />
   <ExportButton />
+  <ReadonlyButton />
 </div>
diff --git a/packages/svelte-lexical/src/lib/components/actionbar/ReadonlyButton.svelte b/packages/svelte-lexical/src/lib/components/actionbar/ReadonlyButton.svelte
new file mode 100644
index 00000000..a1cfcf64
--- /dev/null
+++ b/packages/svelte-lexical/src/lib/components/actionbar/ReadonlyButton.svelte
@@ -0,0 +1,17 @@
+<script lang="ts">
+  import type {LexicalEditor} from 'lexical';
+  import {getEditor, getIsEditable} from '$lib/core/composerContext.js';
+
+  const editor: LexicalEditor = getEditor();
+  const isEditable = getIsEditable();
+</script>
+
+<button
+  class={`action-button ${!$isEditable ? 'unlock' : 'lock'}`}
+  on:click={() => {
+    editor.setEditable(!editor.isEditable());
+  }}
+  title="Read-Only Mode"
+  aria-label={`${!$isEditable ? 'Unlock' : 'Lock'} read-only mode`}>
+  <i class={!$isEditable ? 'unlock' : 'lock'} />
+</button>
diff --git a/packages/svelte-lexical/src/lib/components/toolbar/Toolbar.svelte b/packages/svelte-lexical/src/lib/components/toolbar/Toolbar.svelte
index 20e90621..ff0e4247 100644
--- a/packages/svelte-lexical/src/lib/components/toolbar/Toolbar.svelte
+++ b/packages/svelte-lexical/src/lib/components/toolbar/Toolbar.svelte
@@ -4,14 +4,10 @@
   import StateStoreRichTextUpdator from './StateStoreRichTextUpdator.svelte';
   import {setContext} from 'svelte';
   import {getEditor} from '$lib/core/composerContext.js';
-  import {onMount} from 'svelte';
   import type {NodeKey} from 'lexical';
 
   const editor = getEditor();
 
-  const isEditable = writable(editor.isEditable());
-  setContext('isEditable', isEditable);
-
   const activeEditor = writable(editor);
   setContext('activeEditor', activeEditor);
 
@@ -36,12 +32,6 @@
   setContext('codeLanguage', writable(''));
   setContext('isLink', writable(false));
   setContext('isImageCaption', writable(false));
-
-  onMount(() => {
-    return editor.registerEditableListener((editable) => {
-      $isEditable = editable;
-    });
-  });
 </script>
 
 <StateStoreRichTextUpdator />
diff --git a/packages/svelte-lexical/src/lib/core/Composer.svelte b/packages/svelte-lexical/src/lib/core/Composer.svelte
index 15f6999b..5297be5d 100644
--- a/packages/svelte-lexical/src/lib/core/Composer.svelte
+++ b/packages/svelte-lexical/src/lib/core/Composer.svelte
@@ -29,13 +29,14 @@
     type LexicalNodeReplacement,
     type HTMLConfig,
   } from 'lexical';
-  import {onMount} from 'svelte';
+  import {onMount, setContext} from 'svelte';
   import {initializeEditor} from './initializeEditor.js';
   import {
     createSharedEditorContext,
     setEditor,
     setHistoryStateContext,
   } from './composerContext.js';
+  import {writable} from 'svelte/store';
 
   export let initialConfig: InitialConfigType;
 
@@ -60,16 +61,21 @@
   initializeEditor(editor, initialEditorState);
   setEditor(editor);
 
+  const isEditable = writable(editable !== undefined ? editable : true);
+  setContext('isEditable', isEditable);
+
+  onMount(() => {
+    editor.setEditable($isEditable);
+    return editor.registerEditableListener((editable) => {
+      $isEditable = editable;
+    });
+  });
+
   setHistoryStateContext(createEmptyHistoryState());
 
   // allows sharing context between plugins and decorator nodes
   createSharedEditorContext();
 
-  onMount(() => {
-    const isEditable = initialConfig.editable;
-    editor.setEditable(isEditable !== undefined ? isEditable : true);
-  });
-
   export function getEditor() {
     return editor;
   }