{"id":27938885,"url":"https://github.com/beaconcms/live_monaco_editor","last_synced_at":"2025-05-16T14:04:49.012Z","repository":{"id":164058355,"uuid":"639508952","full_name":"BeaconCMS/live_monaco_editor","owner":"BeaconCMS","description":"Monaco Editor component for Phoenix LiveView","archived":false,"fork":false,"pushed_at":"2025-04-28T16:00:27.000Z","size":3792,"stargazers_count":108,"open_issues_count":5,"forks_count":18,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-05-07T08:58:19.298Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BeaconCMS.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-05-11T15:41:44.000Z","updated_at":"2025-05-06T22:23:31.000Z","dependencies_parsed_at":null,"dependency_job_id":"cb2280de-53e2-46ce-8da7-5287b9b7264a","html_url":"https://github.com/BeaconCMS/live_monaco_editor","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BeaconCMS%2Flive_monaco_editor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BeaconCMS%2Flive_monaco_editor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BeaconCMS%2Flive_monaco_editor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BeaconCMS%2Flive_monaco_editor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BeaconCMS","download_url":"https://codeload.github.com/BeaconCMS/live_monaco_editor/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254544146,"owners_count":22088807,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-07T08:58:17.060Z","updated_at":"2025-05-16T14:04:48.993Z","avatar_url":"https://github.com/BeaconCMS.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LiveMonacoEditor\n\n\u003c!-- MDOC --\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/BeaconCMS/live_monaco_editor/main/assets/images/live_monaco_editor_logo.png\" width=\"512\" alt=\"LiveMonacoEditor logo\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://microsoft.github.io/monaco-editor\"\u003eMonaco Editor\u003c/a\u003e component for Phoenix LiveView.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://hex.pm/packages/live_monaco_editor\"\u003e\n    \u003cimg alt=\"Hex Version\" src=\"https://img.shields.io/hexpm/v/live_monaco_editor\"\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://hexdocs.pm/live_monaco_editor\"\u003e\n    \u003cimg alt=\"Hex Docs\" src=\"http://img.shields.io/badge/hex.pm-docs-green.svg?style=flat\"\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\n    \u003cimg alt=\"MIT\" src=\"https://img.shields.io/hexpm/l/live_monaco_editor\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## Features\n\n- [Lazy load](https://github.com/suren-atoyan/monaco-loader) assets\n- Easily instantiate [single](https://github.com/BeaconCMS/live_monaco_editor#usage) or [multiple](https://github.com/BeaconCMS/live_monaco_editor#multiple-editors) editors\n- Pass any [option available](https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneEditorConstructionOptions.html) to the editor\n- [Interoperability](https://github.com/BeaconCMS/live_monaco_editor#interface) with the underlying editor\n\n## Installation\n\nAdd `:live_monaco_editor` dependency:\n\n```elixir\ndef deps do\n  [\n    {:live_monaco_editor, \"~\u003e 0.2\"}\n  ]\nend\n```\n\nOnce installed, change your `assets/js/app.js` file to load the code editor hook in the live socket:\n\n```javascript\nimport { CodeEditorHook } from \"../../deps/live_monaco_editor/priv/static/live_monaco_editor.esm\"\n\nlet Hooks = {}\nHooks.CodeEditorHook = CodeEditorHook\n\nlet liveSocket = new LiveSocket(\"/live\", Socket, { hooks: Hooks, params: { _csrf_token: csrfToken } })\n```\n\nAnd change your `assets/css/app.css` file to load styling:\n\n```css\n@import \"../../deps/live_monaco_editor/priv/static/live_monaco_editor.min.css\";\n```\n\n## Usage\n\nA new editor using the default options can be created as:\n\n```heex\n\u003cLiveMonacoEditor.code_editor value=\"# My Code Editor\" /\u003e\n```\n\nOr you can customize it as:\n\n```heex\n\u003cLiveMonacoEditor.code_editor\n  style=\"min-height: 250px; width: 100%;\"\n  value={~S{\n  defmodule Math do\n    def sum_list([head | tail], accumulator) do\n      sum_list(tail, head + accumulator)\n    end\n\n    def sum_list([], accumulator) do\n      accumulator\n    end\n  end\n\n  IO.puts Math.sum_list([1, 2, 3], 0)\n  }}\n  opts={\n    Map.merge(\n      LiveMonacoEditor.default_opts(),\n      %{\"language\" =\u003e \"elixir\"}\n    )\n  }\n/\u003e\n```\n\n![Elixir](https://raw.github.com/BeaconCMS/live_monaco_editor/main/assets/elixir.png)\n\n## Interface\n\n### Set editor options\n\nAll [monaco editor options](https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneEditorConstructionOptions.html) are supported by passing a map to `opts`, for example to change the initial language and some other visual options:\n\n```heex\n\u003cLiveMonacoEditor.code_editor\n  value=\"\u003ch1\u003eMy Code Editor\u003c/h1\u003e\"\n  opts={\n    %{\n      \"language\" =\u003e \"html\",\n      \"fontSize\" =\u003e 10,\n      \"minimap\" =\u003e %{\n        \"autohide\" =\u003e true,\n        \"showSlider\" =\u003e \"always\"\n      }\n    }\n  }\n/\u003e\n```\n\n### Merge with default options\n\nThe code editor is created with default options to provide a better UX out-of-the-box, which may not suit your needs, but you can keep the defaults and overwrite some options as you wish:\n\n```heex\n\u003cLiveMonacoEditor.code_editor\n  opts={\n    Map.merge(\n      LiveMonacoEditor.default_opts(),\n      %{\"wordWrap\" =\u003e \"on\"}\n    )\n  }\n/\u003e\n```\n\n### Fetching the editor value\n\nYou can listen to events emitted by the code editor to fetch its current value and send it back to the parent LiveView where the component is used. Firstly, add a event listener:\n\n```javascript\nwindow.addEventListener(\"lme:editor_mounted\", (ev) =\u003e {\n  const hook = ev.detail.hook\n\n  // https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneCodeEditor.html\n  const editor = ev.detail.editor.standalone_code_editor\n\n  // push an event to the parent liveview containing the editor current value when the editor loses focus\n  editor.onDidBlurEditorWidget(() =\u003e {\n    hook.pushEvent(\"code-editor-lost-focus\", { value: editor.getValue() })\n  })\n})\n```\n\nThen you can handle that event on the LiveView to save the editor content or perform any kind of operation you need:\n\n```elixir\ndef handle_event(\"code-editor-lost-focus\", %{\"value\" =\u003e value}, socket) do\n  {:noreply, assign(socket, :source, value)}\nend\n```\n\n### Inside forms\n\nDo not rely on `phx-change` to fetch the editor content because it has known limitations due to how Monaco Editor works:\n\n- Pressing \"backspace\" does not trigger the change event.\n- [Only the last 10 lines](https://github.com/BeaconCMS/live_monaco_editor/issues/14) are sent in the event value.\n\nInstead use the `:change` option in the component:\n\n```heex\n\u003cform\u003e\n  \u003cLiveMonacoEditor.code_editor\n    path=\"my_file.html\"\n    value=\"\u003ch1\u003eTitle\u003c/h1\u003e\"\n    change=\"set_editor_value\"\n  /\u003e\n\u003c/form\u003e\n```\n\nWhich will trigger an event `set_editor_value` in the current LiveView process:\n\n```elixir\ndef handle_event(\"set_editor_value\", %{\"value\" =\u003e value}, socket) do\n  # do something with `value` - it contains the whole editor content\n  {:noreply, socket}\nend\n```\n\nYou'll need to ignore phx-change events for the editor field:\n\n```elixir\ndef handle_event(\"validate\", %{\"_target\" =\u003e [\"live_monaco_editor\", \"my_file.html\"]}, socket) do\n  # ignore change events from the editor field\n  {:noreply, socket}\nend\n```\n\n### Target\n\nBy default, events are pushed to the current LiveView process but you can target a different LiveView or LiveComponent by passing the `target` option:\n\n```heex\n\u003cLiveMonacoEditor.code_editor value={@value} change=\"code_change_event\" target={@myself} /\u003e\n```\n\nThe given target value is passed to the [pushEventTo](https://hexdocs.pm/phoenix_live_view/js-interop.html#client-hooks-via-phx-hook) method.\n\n### Multiple editors\n\nSet an unique `id` and `path` for each one:\n\n```heex\n\u003cLiveMonacoEditor.code_editor id=\"html\" path=\"my_file.html\" /\u003e\n\u003cLiveMonacoEditor.code_editor id=\"css\" path=\"my_file.css\" /\u003e\n```\n\n### Change language and value\n\n```heex\n\u003cbutton phx-click=\"create-file\"\u003emy_file.html\u003c/button\u003e\n```\n\n```elixir\ndef handle_event(\"create-file\", _params, socket) do\n  {:noreply,\n   socket\n   |\u003e LiveMonacoEditor.change_language(\"html\")\n   |\u003e LiveMonacoEditor.set_value(\"\u003ch1\u003eNew File\u003c/h1\u003e\")}\nend\n```\n\n_More operations will be supported in new releases._\n\n### Styling\n\nThe component does not depend on any CSS framework but its parent container has to be large enough to be visible. The default style can be changed and/or classes can be applied:\n\n```heex\n\u003cLiveMonacoEditor.code_editor\n  style=\"height: 100%; width: 100%; min-height: 1000px; min-width: 600px;\"\n  class=\"my-2\"\n/\u003e\n```\n\n## Status\n\nEarly-stage, you can expect incomplete features and breaking changes.\n\n## Contributing\n\nYou can use the file `dev.exs` which is a self-contained Phoenix application running LiveMonacoEditor. Execute:\n\n```sh\nmix setup\niex dev.exs\n```\n\nVisit http://localhost:4000\n\n## Looking for help with your Elixir project?\n\n\u003cimg src=\"https://raw.githubusercontent.com/BeaconCMS/live_monaco_editor/main/assets/images/dockyard_logo.png\" width=\"256\" alt=\"DockYard logo\"\u003e\n\nAt DockYard we are [ready to help you build your next Elixir project](https://dockyard.com/phoenix-consulting).\nWe have a unique expertise in Elixir and Phoenix development that is unmatched and we love to [write about Elixir](https://dockyard.com/blog/categories/elixir).\n\nHave a project in mind? [Get in touch](https://dockyard.com/contact/hire-us)!\n\n## Acknowledgements\n\n* [Jonatan Kłosko](https://github.com/jonatanklosko) for his amazing work with [Livebook Editor](https://github.com/livebook-dev/livebook/blob/main/assets/js/hooks/cell_editor.js)\n* [Logo](https://www.flaticon.com/free-icons/script) created by kerismaker - Flaticon\n* [Logo font](https://fonts.google.com/specimen/Source+Code+Pro) designed by Paul D. hunt\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeaconcms%2Flive_monaco_editor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbeaconcms%2Flive_monaco_editor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeaconcms%2Flive_monaco_editor/lists"}