lexxy 0.1.2.beta → 0.1.4.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3ea5ece1a6a51744b2372f4540cafb1485fb8347c091baf90a024231d276643
4
- data.tar.gz: d4fa22597f79e0dadb00d4b6d1b1c20ec4e4e79da4e12acb8c4babda494e8916
3
+ metadata.gz: a63dfb829afd1242b6a38e4c9f6511ef717ee81b2a4950b11d486531fdd5b7d0
4
+ data.tar.gz: 78e54bc5f3ce08662c381d8e9dd32995828125da453ba35234b602a368dd65b2
5
5
  SHA512:
6
- metadata.gz: 42f9ca757740fb29bacdb73f668666984925c5a2c747da67b5b4c51bd21e2e5701994f32164df7b394bb490e39f15891dff064e9cf5eada1eeef12a502ebfd67
7
- data.tar.gz: c588ad954bd2f0ae53bdee0a4dcf06a98025f64669738d61856df61fb2c8286227b41f59e97a88c2465985abc6b5818f53ea5e0cd23d85abffae3d761714bb63
6
+ metadata.gz: 69fb8247e66a3242f475c12a66bc3529132d0e41707e173db743fba3d6bc23b98031b8543c3eee44c240113049810f91d445599c6d628a9001236cde863b857b
7
+ data.tar.gz: 07cb12a656a71c6a1e944e59789314eeb9855ccf3583f5f86c29d0c51e77cd520c345aad5712385d9a04315fe13179487bf312bf6aca98aaa837f14b7b44eb12
data/README.md CHANGED
@@ -23,7 +23,7 @@ A modern rich text editor for Rails.
23
23
  Add this line to your application's Gemfile:
24
24
 
25
25
  ```ruby
26
- gem 'lexxy'
26
+ gem 'lexxy', '~> 0.1.3.beta' # Need to specify the version since it's a pre-release
27
27
  ```
28
28
 
29
29
  And then execute:
@@ -32,18 +32,41 @@ And then execute:
32
32
  bundle install
33
33
  ```
34
34
 
35
- Then, you need to import the lexxy source in your app. If you are using [propshaft](https://github.com/rails/propshaft) and [import maps](https://github.com/rails/importmap-rails) you can do:
35
+ ### Import maps
36
+
37
+ If you are using [propshaft](https://github.com/rails/propshaft) and [import maps](https://github.com/rails/importmap-rails):
36
38
 
37
39
  ```ruby
38
40
  # importmap.rb
39
41
  pin "lexxy", to: "lexxy.js"
42
+ pin "@rails/activestorage", to: "activestorage.esm.js" # to support attachments
43
+ ```
44
+
45
+ Then import it in your JavaScript entry point:
46
+
47
+ ```javascript
48
+ // app/javascript/application.js
49
+ import "@37signals/lexxy"
50
+ ```
51
+
52
+ ### JavaScript Bundling (jsbundling-rails, Vite, etc.)
53
+
54
+ If you're using [jsbundling-rails](https://github.com/rails/jsbundling-rails) with esbuild, webpack, or any other JavaScript bundler, you'll need to install the NPM package:
55
+
56
+ ```bash
57
+ yarn add @37signals/lexxy
58
+ yarn add @rails/activestorage # to support attachments
40
59
  ```
41
60
 
61
+ Then import it in your JavaScript entry point:
62
+
42
63
  ```javascript
43
- // application.js
44
- import "lexxy"
64
+ // app/javascript/application.js
65
+ import "@37signals/lexxy"
45
66
  ```
46
67
 
68
+ ### CSS Setup
69
+
47
70
  For the CSS, you can include it with the standard Rails helper:
48
71
 
49
72
  ```erb
@@ -83,9 +106,9 @@ Under the hood, this will insert a `<lexxy-editor>` tag, that will be a first-cl
83
106
 
84
107
  The `<lexxy-editor>` element supports these options:
85
108
 
86
- - `placeholder` - Text displayed when the editor is empty.
87
- - `toolbar` - Pass `"false"` to disable the toolbar entirely, or pass an element ID to render the toolbar in an external element. By default, the toolbar is bootstrapped and displayed above the editor.
88
- - `attachments` - Pass `"false"` to disable attachments completely. By default, attachments are supported, including paste and Drag & Drop support.
109
+ - `placeholder`: Text displayed when the editor is empty.
110
+ - `toolbar`: Pass `"false"` to disable the toolbar entirely, or pass an element ID to render the toolbar in an external element. By default, the toolbar is bootstrapped and displayed above the editor.
111
+ - `attachments`: Pass `"false"` to disable attachments completely. By default, attachments are supported, including paste and Drag & Drop support.
89
112
 
90
113
  Lexxy uses the `ElementInternals` API to participate in HTML forms as any standard control. This means that you can use standard HTML attributes like `name`, `value`, `required`, `disabled`, etc.
91
114
 
@@ -103,7 +126,7 @@ Lexxy also lets you configure how to load the items: inline or remotely, and how
103
126
  The first thing to do is to add a `<lexxy-prompt>` element to the editor:
104
127
 
105
128
  ```erb
106
- <%= form_with model: @post do |form| %>
129
+ <%= form.rich_text_area :body do %>
107
130
  <lexxy-prompt trigger="@">
108
131
  </lexxy-prompt>
109
132
  <% end %>
@@ -238,30 +261,31 @@ By default, the `SPACE` key will select the current item in the prompt. If you w
238
261
 
239
262
  #### `<lexxy-prompt>`
240
263
 
241
- - `trigger` - The character that activates the prompt (e.g., "@", "#", "/").
242
- - `src` - Path or URL to load items remotely.
243
- - `name` - Identifier for the prompt type (determines attachment content type, e.g., `name= "mention"` creates `application/vnd.actiontext.mention`). Mandatory unless using `insert-editable-text`.
244
- - `empty-results` - Message shown when no matches found. By default it is "Nothing found".
245
- - `remote-filtering` - Enable server-side filtering instead of loading all options at once.
246
- - `insert-editable-text` - Insert prompt item HTML directly as editable text instead of Action Text attachments.
247
- - `supports-space-in-searches` - Allow spaces in search queries (useful with remote filtering for full name searches).
264
+ - `trigger`: The character that activates the prompt (e.g., "@", "#", "/").
265
+ - `src`: Path or URL to load items remotely.
266
+ - `name`: Identifier for the prompt type (determines attachment content type, e.g., `name= "mention"` creates `application/vnd.actiontext.mention`). Mandatory unless using `insert-editable-text`.
267
+ - `empty-results`: Message shown when no matches found. By default it is "Nothing found".
268
+ - `remote-filtering`: Enable server-side filtering instead of loading all options at once.
269
+ - `insert-editable-text`: Insert prompt item HTML directly as editable text instead of Action Text attachments.
270
+ - `supports-space-in-searches`: Allow spaces in search queries (useful with remote filtering for full name searches).
248
271
 
249
272
  #### `<lexxy-prompt-item>`
250
273
 
251
- - `search` - The text to match against when filtering (can include multiple fields for better search).
252
- - `sgid` - The signed GlobalID for Action Text attachments (use `attachable_sgid` helper). Mandatory unless using `insert-editable-text`.
274
+ - `search`: The text to match against when filtering (can include multiple fields for better search).
275
+ - `sgid`: The signed GlobalID for Action Text attachments (use `attachable_sgid` helper). Mandatory unless using `insert-editable-text`.
253
276
 
254
277
  ## Roadmap
255
278
 
256
279
  This is an early beta. Here's what's coming next:
257
280
 
258
- - Configurable editors in Action Text - Choose your editor like you choose your database.
281
+ - Configurable editors in Action Text: Choose your editor like you choose your database.
259
282
  - More editing features:
260
283
  - Tables
261
284
  - Text highlighting
262
- - Image galleries - The only remaining feature for full Action Text compatibility
285
+ - Image galleries: The only remaining feature for full Action Text compatibility
263
286
  - Install task that generates the necessary JS and adds stylesheets.
264
- - Standalone JS package - to use in non-Rails environments.
287
+ - Configuration hooks.
288
+ - Standalone JS package: to use in non-Rails environments.
265
289
 
266
290
  ## Development
267
291
 
@@ -279,6 +303,10 @@ bin/rails server
279
303
 
280
304
  The sandbox app is available at http://localhost:3000. There is also a CRUD example at http://localhost:3000/posts.
281
305
 
306
+ ## Events
307
+
308
+ * `lexxy:change`: Fired whenever the editor content changes.
309
+
282
310
  ## Contributing
283
311
 
284
312
  - Bug reports and pull requests are welcome on [GitHub Issues](https://github.com/basecamp/lexxy/issues). Help is especially welcome with [those tagged as "Help Wanted"](https://github.com/basecamp/lexxy/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22help%20wanted%22).
@@ -3746,6 +3746,21 @@ function getListType(node) {
3746
3746
  }
3747
3747
 
3748
3748
  class LexicalToolbarElement extends HTMLElement {
3749
+ constructor() {
3750
+ super();
3751
+ this.internals = this.attachInternals();
3752
+ this.internals.role = "toolbar";
3753
+ }
3754
+
3755
+ connectedCallback() {
3756
+ this.#refreshToolbarOverflow();
3757
+ window.addEventListener("resize", this.#refreshToolbarOverflow);
3758
+ }
3759
+
3760
+ disconnectedCallback() {
3761
+ window.removeEventListener("resize", this.#refreshToolbarOverflow);
3762
+ }
3763
+
3749
3764
  setEditor(editorElement) {
3750
3765
  this.editorElement = editorElement;
3751
3766
  this.editor = editorElement.editor;
@@ -3810,13 +3825,12 @@ class LexicalToolbarElement extends HTMLElement {
3810
3825
  event.shiftKey ? 'shift' : null,
3811
3826
  ].filter(Boolean);
3812
3827
 
3813
- return [...modifiers, pressedKey].join('+')
3828
+ return [ ...modifiers, pressedKey ].join('+')
3814
3829
  }
3815
3830
 
3816
3831
  #assignButtonTabindex() {
3817
3832
  const baseTabIndex = parseInt(this.editorElement.editorContentElement.getAttribute("tabindex") ?? "0");
3818
- const buttons = this.querySelectorAll("button");
3819
- buttons.forEach((button, index) => {
3833
+ this.#buttons.forEach((button, index) => {
3820
3834
  button.setAttribute("tabindex", `${baseTabIndex + index + 1}`);
3821
3835
  });
3822
3836
  }
@@ -3895,16 +3909,60 @@ class LexicalToolbarElement extends HTMLElement {
3895
3909
  }
3896
3910
  }
3897
3911
 
3912
+ #toolbarIsOverflowing() {
3913
+ return this.scrollWidth > this.clientWidth
3914
+ }
3915
+
3916
+ #refreshToolbarOverflow = () => {
3917
+ this.#resetToolbar();
3918
+ this.#compactMenu();
3919
+
3920
+ this.#overflow.style.display = this.#overflowMenu.children.length ? "block" : "none";
3921
+ }
3922
+
3923
+ get #overflow() {
3924
+ return this.querySelector(".lexxy-editor__toolbar-overflow")
3925
+ }
3926
+
3927
+ get #overflowMenu() {
3928
+ return this.querySelector(".lexxy-editor__toolbar-overflow-menu")
3929
+ }
3930
+
3931
+ #resetToolbar() {
3932
+ while (this.#overflowMenu.children.length > 0) {
3933
+ this.insertBefore(this.#overflowMenu.children[0], this.#overflow);
3934
+ }
3935
+ }
3936
+
3937
+ #compactMenu() {
3938
+ const buttons = this.#buttons.reverse();
3939
+ let movedToOverflow = false;
3940
+
3941
+ for (const button of buttons) {
3942
+ if (this.#toolbarIsOverflowing()) {
3943
+ this.#overflowMenu.appendChild(button);
3944
+ movedToOverflow = true;
3945
+ } else {
3946
+ if (movedToOverflow) this.#overflowMenu.appendChild(button);
3947
+ break
3948
+ }
3949
+ }
3950
+ }
3951
+
3952
+ get #buttons() {
3953
+ return Array.from(this.querySelectorAll(":scope > button"))
3954
+ }
3955
+
3898
3956
  static get defaultTemplate() {
3899
3957
  return `
3900
3958
  <button type="button" name="bold" data-command="bold" title="Bold">
3901
3959
  <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <path d="m4.1 23c-.5 0-.7-.4-.7-.7v-20.6c0-.4.4-.7.7-.7h8.9c2 0 3.8.6 4.9 1.5 1.2 1 1.8 2.4 1.8 4.1s-.9 3.2-2.3 4.1c-.2 0-.3.3-.3.5s0 .4.3.5c1.9.8 3.2 2.7 3.2 5s-.7 3.6-2.1 4.7-3.3 1.7-5.6 1.7h-8.8zm4.2-18.1v5.1h3c1.2 0 2-.3 2.7-.7.6-.5.9-1.1.9-1.9s-.3-1.4-.8-1.8-1.3-.6-2.3-.6-2.4 0-3.5 0zm0 8.5v5.8h3.7c1.3 0 2.2-.3 2.8-.7s.9-1.2.9-2.2-.4-1.7-1-2.1-1.7-.7-2.9-.7-2.4 0-3.5 0z" fill-rule="evenodd"/> </svg>
3902
3960
  </button>
3903
-
3961
+
3904
3962
  <button type="button" name="italic" data-command="italic" title="Italic">
3905
3963
  <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m18.3 1.7c-1.7.4-2.5 1.3-2.7 2.6l-2.4 15.6c-.2 1.1.5 2.1 1.6 2.4.2 0 .2.2.2.3v.7h-.1c0 .1-.2.3-.3.3h-9c-.2 0-.3-.1-.3-.3v-.7h.1c0-.1.1-.2.2-.2 1.7-.4 2.5-1.3 2.7-2.6l2.4-15.6c.2-1.1-.5-2.1-1.6-2.4-.2 0-.2-.2-.2-.3v-.7h.1c0-.1.2-.3.3-.3h9c.2 0 .3.1.3.3v.7h-.1c0 .1-.1.2-.2.2z" fill-rule="evenodd"/></svg>
3906
3964
  </button>
3907
-
3965
+
3908
3966
  <button type="button" name="link" title="Link" data-dialog-target="link-dialog" data-hotkey="cmd+k ctrl+k">
3909
3967
  <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m22.2 1.8c-1.1-1.2-2.5-1.8-4.3-1.8s-3.1.6-4.4 1.8l-4.4 4.4c-1.2 1.2-1.8 2.7-1.8 4.3s.6 3.1 1.8 4.3h.2c.2.3.5.4 1 .4.7 0 1.1-.3 1.2-.6.3-.3.4-.7.4-1.1s-.2-.8-.5-1.2c-.5-.5-.8-1.2-.8-1.9s.3-1.4.8-1.9l4.4-4.2c.6-.5 1.5-.8 2.1-.8s1.4.2 1.9.7.8 1.2.8 1.9-.3 1.4-.8 1.9l-2.6 2.2c-.3.3-.5.7-.5 1.2s.2.8.5 1.2c.8.6 1.7.6 2.4 0l2.6-2.2c2.4-2.4 2.4-6.1 0-8.5z"/><path d="m12.3 9.3c-.3.3-.5.8-.5 1.3 0 .4.2.8.5 1.1.5.5.8 1.2.8 1.9s-.3 1.4-.9 1.9l-4.4 4.4c-.4.4-1.2.7-1.8.7s-1.4-.2-1.9-.7-.8-1.2-.8-1.9.3-1.4.8-1.9l2.5-2.4c.7-.7.7-1.7 0-2.4-.8-.6-1.7-.6-2.4 0l-2.5 2.4c-1 1.1-1.7 2.6-1.7 4.2s.6 3.1 1.8 4.3c1.3 1.2 2.7 1.8 4.2 1.8s3.2-.7 4.3-1.8l4.4-4.4c2.4-2.4 2.4-6.1 0-8.6-.8-.6-1.7-.6-2.4 0z"/></svg>
3910
3968
  </button>
@@ -3916,33 +3974,38 @@ class LexicalToolbarElement extends HTMLElement {
3916
3974
  <button type="submit" class="btn" value="link">Link</button>
3917
3975
  <button type="button" class="btn" value="unlink">Unlink</button>
3918
3976
  </div>
3919
- </form>
3920
- </dialog>
3977
+ </form>
3978
+ </dialog>
3921
3979
  </lexxy-link-dialog>
3922
-
3980
+
3923
3981
  <button type="button" name="quote" data-command="insertQuoteBlock" title="Quote">
3924
3982
  <svg viewBox="0 0 24 22" xmlns="http://www.w3.org/2000/svg"> <path d="m1.1 5.2c.6-.7 1.4-1.3 2.4-1.4 2.6-.4 4.2.4 5.3 1.9 2 2.3 1.9 5.1.6 7.6-1.3 2.4-4 4.6-7.2 5.1-.4 0-.7-.1-1-.4-.1-.3-.1-.7.3-1.1l1.1-1.1c.3-.4.6-.7.7-1.1s.3-.9 0-1.3c0-.4-.6-.7-1-1-1.2-.8-2.3-2.2-2.3-4.1.1-1.4.4-2.4 1.1-3.1z"/> <path d="m14.6 5.2c.6-.7 1.6-1.1 2.6-1.4 2.4-.4 4.2.4 5.3 1.9 2 2.3 1.9 5.1.6 7.6-1.3 2.4-4 4.6-7.2 5.1-.4 0-.7-.1-1-.4-.1-.3-.1-.7.3-1.1l1.1-1.1c.3-.4.6-.7.7-1.1s.3-.9 0-1.3c-.1-.4-.6-.7-1-1-1.3-.6-2.4-2-2.4-3.9s.4-2.6 1-3.3z"/> </svg>
3925
3983
  </button>
3926
-
3984
+
3927
3985
  <button type="button" name="heading" data-command="rotateHeadingFormat" title="Heading">
3928
3986
  <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m5.7 6.2v16.3h3.8v-16.3h5.7v-3.8h-15.2v3.8zm10.1 16.4h3.8v-8.8h4.4v-3.8h-12.6v3.8h4.4z" fill-rule="evenodd"/></svg>
3929
3987
  </button>
3930
-
3988
+
3931
3989
  <button type="button" name="code" data-command="insertCodeBlock" title="Code">
3932
3990
  <svg viewBox="0 0 24 22" xmlns="http://www.w3.org/2000/svg"><path d="m8 4.7c-.6-.6-1.6-.6-2.4 0l-5.1 5.2c-.3.3-.5.7-.5 1.2s.2.9.5 1.2l5.1 5.1c.3.3.7.5 1.2.5s.9-.2 1.2-.5c.6-.6.6-1.7 0-2.4l-4-4 4-4c.6-.6.6-1.7 0-2.4z"/><path d="m23.5 9.9-5.1-5.1c-.6-.6-1.8-.6-2.4 0-.3.3-.5.7-.5 1.2s.2.9.5 1.2l4 4-4 4c-.3.3-.5.7-.5 1.2s.2.9.5 1.2c.3.2.7.4 1.1.4s.9-.2 1.2-.5l5.1-5.1c.3-.3.5-.7.5-1.2s-.2-.9-.5-1.2z"/></svg>
3933
3991
  </button>
3934
-
3992
+
3935
3993
  <button type="button" name="unordered-list" data-command="insertUnorderedList" title="Bullet list">
3936
- <svg viewBox="0 0 24 22" xmlns="http://www.w3.org/2000/svg"> <path d="m2.1 4.8c1.1 0 2.1-.9 2.1-2.1s-1-2-2.1-2-2.1.9-2.1 2.1.9 2 2.1 2zm4.1-2c0-.8.6-1.4 1.4-1.4h15.1c.7 0 1.3.6 1.3 1.4s-.6 1.4-1.4 1.4h-15.1c-.7 0-1.3-.7-1.3-1.4zm1.3 6.8c-.8 0-1.4.6-1.4 1.4s.6 1.4 1.4 1.4h15.1c.8 0 1.4-.6 1.4-1.4s-.6-1.4-1.4-1.4zm0 8.3c-.8 0-1.4.6-1.4 1.4s.6 1.4 1.4 1.4h15.1c.8 0 1.4-.6 1.4-1.4s-.6-1.4-1.4-1.4zm-3.4-6.9c0 1.1-.9 2.1-2.1 2.1s-2-1-2-2.1.9-2.1 2.1-2.1 2 1 2 2.1zm-2 10.3c1.1 0 2.1-.9 2.1-2.1s-.9-2.1-2.1-2.1-2.1 1-2.1 2.1.9 2.1 2.1 2.1z" fill-rule="evenodd"/> </svg>
3994
+ <svg viewBox="0 0 24 22" xmlns="http://www.w3.org/2000/svg"> <path d="m2.1 4.8c1.1 0 2.1-.9 2.1-2.1s-1-2-2.1-2-2.1.9-2.1 2.1.9 2 2.1 2zm4.1-2c0-.8.6-1.4 1.4-1.4h15.1c.7 0 1.3.6 1.3 1.4s-.6 1.4-1.4 1.4h-15.1c-.7 0-1.3-.7-1.3-1.4zm1.3 6.8c-.8 0-1.4.6-1.4 1.4s.6 1.4 1.4 1.4h15.1c.8 0 1.4-.6 1.4-1.4s-.6-1.4-1.4-1.4zm0 8.3c-.8 0-1.4.6-1.4 1.4s.6 1.4 1.4 1.4h15.1c.8 0 1.4-.6 1.4-1.4s-.6-1.4-1.4-1.4zm-3.4-6.9c0 1.1-.9 2.1-2.1 2.1s-2-1-2-2.1.9-2.1 2.1-2.1 2 1 2 2.1zm-2 10.3c1.1 0 2.1-.9 2.1-2.1s-.9-2.1-2.1-2.1-2.1 1-2.1 2.1.9 2.1 2.1 2.1z" fill-rule="evenodd"/> </svg>
3937
3995
  </button>
3938
-
3996
+
3939
3997
  <button type="button" name="ordered-list" data-command="insertOrderedList" title="Numbered list">
3940
3998
  <svg viewBox="0 0 24 22" xmlns="http://www.w3.org/2000/svg"><path d="m6.7 3c0-.7.6-1.3 1.3-1.3h14.7c.7 0 1.3.6 1.3 1.3s-.6 1.3-1.3 1.3h-14.7c-.7 0-1.3-.6-1.3-1.3zm1.3 6.7c-.7 0-1.3.6-1.3 1.3s.6 1.3 1.3 1.3h14.7c.7 0 1.3-.6 1.3-1.3s-.6-1.3-1.3-1.3zm0 8c-.7 0-1.3.6-1.3 1.3s.6 1.3 1.3 1.3h14.7c.7 0 1.3-.6 1.3-1.3s-.6-1.3-1.3-1.3z" fill-rule="evenodd"/><path d="m1.5 19.6v-.9h.5c.4 0 .8-.3.8-.7s-.3-.7-.8-.7-.8.3-.8.7h-1.2c0-.9.8-1.6 2-1.6s2 .5 2 1.5-.4 1.1-1.1 1.2c.7 0 1.2.7 1.2 1.3 0 1.1-1.1 1.6-2.1 1.6s-2-.8-2-1.6h1.2c0 .4.4.7.8.7s.8-.3.8-.7-.3-.7-.8-.7h-.7.1zm0-9.7h-1.2c0-.9.7-1.7 2-1.7s2 .7 2 1.6-.5 1.2-.9 1.7l-1.1 1.2h2.1v1.1h-3.9v-.8l2-2c.3-.3.5-.7.5-1.1s-.3-.7-.7-.7-.7.3-.7.7h-.3zm1.7-4.4h-1.3v-4.3l-1.2.8v-1.2l1.3-.8h1.3v5.5z"/></svg>
3941
3999
  </button>
3942
-
4000
+
3943
4001
  <button type="button" name="upload" data-command="uploadAttachments" title="Upload file">
3944
4002
  <svg viewBox="0 0 24 20" xmlns="http://www.w3.org/2000/svg"> <path d="m22 20h-20c-1.1 0-2-.9-2-2.1v-15.8c0-1.2.9-2.1 2-2.1h20c1.1 0 2 .9 2 2.1v15.8c0 1.1-.9 2.1-2 2.1zm0-2.9v-14.5c0-.3-.2-.5-.5-.5h-19c-.3 0-.5.2-.5.5v14.5c0 .1.1.2.2.2s.2 0 .2-.1l2.2-3.3c.1-.2.3-.3.5-.3h.7l2.6-4c.1-.2.3-.3.5-.3h.7c.2 0 .4.1.5.3l5.3 8c0 .1.2.2.3.2h.3c.2 0 .4-.2.4-.4s0-.2 0-.2l-1.3-1.9c-.2-.2-.2-.6 0-.8l1.2-1.6c.1-.2.3-.3.5-.3h1.1c.2 0 .4 0 .5.3l3.2 4.4c0 .1.3.2.4 0 .2 0 .2 0 .2-.2zm-5.5-7.6c-1.4 0-2.5-1.2-2.5-2.6s1.1-2.6 2.5-2.6 2.5 1.2 2.5 2.6-1.1 2.6-2.5 2.6z" fill-rule="evenodd"/> </svg>
3945
4003
  </button>
4004
+
4005
+ <details class="lexxy-editor__toolbar-overflow">
4006
+ <summary aria-label="Show more toolbar buttons">•••</summary>
4007
+ <div class="lexxy-editor__toolbar-overflow-menu" aria-label="More toolbar buttons"></div>
4008
+ </details>
3946
4009
  `
3947
4010
  }
3948
4011
  }
@@ -7264,7 +7327,7 @@ class LexicalEditorElement extends HTMLElement {
7264
7327
  constructor() {
7265
7328
  super();
7266
7329
  this.internals = this.attachInternals();
7267
- this.internals.role = "textbox";
7330
+ this.internals.role = "presentation";
7268
7331
  }
7269
7332
 
7270
7333
  connectedCallback() {
@@ -7416,12 +7479,20 @@ class LexicalEditorElement extends HTMLElement {
7416
7479
  }
7417
7480
 
7418
7481
  #createEditorContentElement() {
7419
- const editorContentElement = createElement("div", { classList: "lexxy-editor__content", contenteditable: true, placeholder: this.getAttribute("placeholder") });
7482
+ const editorContentElement = createElement("div", {
7483
+ classList: "lexxy-editor__content",
7484
+ contenteditable: true,
7485
+ role: "textbox",
7486
+ "aria-multiline": true,
7487
+ "aria-label": this.#labelText,
7488
+ placeholder: this.getAttribute("placeholder")
7489
+ });
7420
7490
  editorContentElement.id = `${this.id}-content`;
7491
+ this.#ariaAttributes.forEach(attribute => editorContentElement.setAttribute(attribute.name, attribute.value));
7421
7492
  this.appendChild(editorContentElement);
7422
7493
 
7423
7494
  if (this.getAttribute("tabindex")) {
7424
- this.editorContentElement.setAttribute("tabindex", this.getAttribute("tabindex"));
7495
+ editorContentElement.setAttribute("tabindex", this.getAttribute("tabindex"));
7425
7496
  this.removeAttribute("tabindex");
7426
7497
  } else {
7427
7498
  editorContentElement.setAttribute("tabindex", 0);
@@ -7430,6 +7501,14 @@ class LexicalEditorElement extends HTMLElement {
7430
7501
  return editorContentElement
7431
7502
  }
7432
7503
 
7504
+ get #labelText() {
7505
+ return Array.from(this.internals.labels).map(label => label.textContent).join(" ")
7506
+ }
7507
+
7508
+ get #ariaAttributes() {
7509
+ return Array.from(this.attributes).filter(attribute => attribute.name.startsWith("aria-"))
7510
+ }
7511
+
7433
7512
  set #internalFormValue(html) {
7434
7513
  const changed = this.#internalFormValue !== undefined && this.#internalFormValue !== this.value;
7435
7514
 
Binary file
Binary file