@nerd-bible/wordgard 0.5.3-beta7 → 0.6.2-beta2

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.
package/dist/schema.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { ChangeSet, Leaf, Plot, Elt } from 'wordgard/doc';
2
2
  import { GardState, GardSelection, BidiSpan, Transaction } from 'wordgard/state';
3
- import { Paragraph, Heading, Direction, Blockquote, HorizontalRule, Alignment, Doc, InlineDoc, BulletList, OrderedList, InlineListItem, ListItem, CodeBlock, CodeBlockLanguage, Strong, Emphasis, Code, Underline, Strikethrough, Superscript, Subscript, ImageSize, ImageAlt, Image, Figure, CaptionedFigure, Color, BackgroundColor, Link, LineBreak } from 'wordgard/types';
3
+ import { Paragraph, Heading, Direction, Blockquote, HorizontalRule, Alignment, Doc, InlineDoc, BulletList, OrderedList, InlineListItem, ListItem, CodeBlock, CodeBlockLanguage, Strong, Emphasis, Code, Underline, Strikethrough, Superscript, Subscript, Image, Figure, CaptionedFigure, ImageSize, ImageAlt, Color, BackgroundColor, Link, LineBreak } from 'wordgard/types';
4
4
  import { phrases, imagePhrases, colorNames } from 'wordgard/phrases';
5
5
  import { Command, setTextblockType, Menu, setAlignment, setDirection, toggleBlock, listIsActive, toggleList, enter, toggleMark } from 'wordgard/command';
6
6
  import { history } from 'wordgard/history';
7
- import { KeyBinding, InputRule, Wordgard, Widget, Decoration, Panel, Dialog, Tooltip } from 'wordgard/editor';
7
+ import { KeyBinding, InputRule, Wordgard, Widget, Decoration, Dialog, Tooltip } from 'wordgard/editor';
8
8
  import cr from 'crelt';
9
9
 
10
10
  function blockDoc() {
@@ -25,6 +25,8 @@ function paragraph() {
25
25
  ;paragraph = /*@__PURE__*/(function (paragraph) {
26
26
  paragraph.keyBinding = KeyBinding.of({
27
27
  key: "Ctrl-Shift-0",
28
+ description: phrases.ref("paragraph"),
29
+ group: KeyBinding.Group.Block,
28
30
  run: Command.bind(setTextblockType, Paragraph)
29
31
  });
30
32
  paragraph.button = Menu.Button.define({
@@ -43,12 +45,18 @@ function heading() {
43
45
  }
44
46
  ;heading = /*@__PURE__*/(function (heading) {
45
47
  heading.keyBindings = [
46
- KeyBinding.of({ key: "Ctrl-Shift-1", run: Command.bind(setTextblockType, Heading.of(1)) }),
47
- KeyBinding.of({ key: "Ctrl-Shift-2", run: Command.bind(setTextblockType, Heading.of(2)) }),
48
- KeyBinding.of({ key: "Ctrl-Shift-3", run: Command.bind(setTextblockType, Heading.of(3)) }),
49
- KeyBinding.of({ key: "Ctrl-Shift-4", run: Command.bind(setTextblockType, Heading.of(4)) }),
50
- KeyBinding.of({ key: "Ctrl-Shift-5", run: Command.bind(setTextblockType, Heading.of(5)) }),
51
- KeyBinding.of({ key: "Ctrl-Shift-6", run: Command.bind(setTextblockType, Heading.of(6)) })
48
+ KeyBinding.of({ key: "Ctrl-Shift-1", run: Command.bind(setTextblockType, Heading.of(1)),
49
+ description: phrases.ref("heading_1"), group: KeyBinding.Group.Block }),
50
+ KeyBinding.of({ key: "Ctrl-Shift-2", run: Command.bind(setTextblockType, Heading.of(2)),
51
+ description: phrases.ref("heading_2"), group: KeyBinding.Group.Block }),
52
+ KeyBinding.of({ key: "Ctrl-Shift-3", run: Command.bind(setTextblockType, Heading.of(3)),
53
+ description: phrases.ref("heading_3"), group: KeyBinding.Group.Block }),
54
+ KeyBinding.of({ key: "Ctrl-Shift-4", run: Command.bind(setTextblockType, Heading.of(4)),
55
+ description: phrases.ref("heading_4"), group: KeyBinding.Group.Block }),
56
+ KeyBinding.of({ key: "Ctrl-Shift-5", run: Command.bind(setTextblockType, Heading.of(5)),
57
+ description: phrases.ref("heading_5"), group: KeyBinding.Group.Block }),
58
+ KeyBinding.of({ key: "Ctrl-Shift-6", run: Command.bind(setTextblockType, Heading.of(6)),
59
+ description: phrases.ref("heading_6"), group: KeyBinding.Group.Block })
52
60
  ];
53
61
  heading.button1 = Menu.Button.define({
54
62
  run: Command.bind(setTextblockType, Heading.of(1)),
@@ -85,9 +93,12 @@ function alignmentAtCursor(state) {
85
93
  }
86
94
  ;alignment = /*@__PURE__*/(function (alignment) {
87
95
  alignment.keyBindings = [
88
- KeyBinding.of({ key: "Mod-Shift-l", run: Command.bind(setAlignment, "left") }),
89
- KeyBinding.of({ key: "Mod-Shift-r", run: Command.bind(setAlignment, "right") }),
90
- KeyBinding.of({ key: "Mod-Shift-e", run: Command.bind(setAlignment, "center") })
96
+ KeyBinding.of({ key: "Mod-Shift-l", run: Command.bind(setAlignment, "left"),
97
+ description: phrases.ref("align_left"), group: KeyBinding.Group.Block }),
98
+ KeyBinding.of({ key: "Mod-Shift-r", run: Command.bind(setAlignment, "right"),
99
+ description: phrases.ref("align_right"), group: KeyBinding.Group.Block }),
100
+ KeyBinding.of({ key: "Mod-Shift-e", run: Command.bind(setAlignment, "center"),
101
+ description: phrases.ref("align_center"), group: KeyBinding.Group.Block })
91
102
  ];
92
103
  alignment.buttonStart = Menu.Button.define({
93
104
  run: Command.bind(setAlignment, null),
@@ -277,13 +288,20 @@ function orderedList(config = {}) {
277
288
  ;return orderedList})(orderedList);
278
289
 
279
290
  function codeBlock() {
280
- return [GardState.schemaElement.of(CodeBlock),
281
- codeBlock.button, codeBlock.keyBinding, codeBlock.createOnBackticks];
291
+ return [
292
+ GardState.schemaElement.of(CodeBlock),
293
+ codeBlock.button,
294
+ codeBlock.keyBinding,
295
+ codeBlock.createOnBackticks,
296
+ codeBlock.theme
297
+ ];
282
298
  }
283
299
  ;codeBlock = /*@__PURE__*/(function (codeBlock) {
284
300
  codeBlock.keyBinding = KeyBinding.of({
285
301
  key: "Ctrl-Shift-\\",
286
- run: Command.bind(setTextblockType, CodeBlock)
302
+ run: Command.bind(setTextblockType, CodeBlock),
303
+ description: phrases.ref("code_block"),
304
+ group: KeyBinding.Group.Block
287
305
  });
288
306
  codeBlock.button = Menu.Button.define({
289
307
  run: Command.bind(setTextblockType, CodeBlock),
@@ -312,6 +330,13 @@ function codeBlock() {
312
330
  scrollIntoView: true
313
331
  };
314
332
  }));
333
+ codeBlock.theme = Wordgard.theme({
334
+ pre: {
335
+ padding: "8px 12px",
336
+ borderRadius: "4px",
337
+ background: "#88888819"
338
+ }
339
+ });
315
340
  ;return codeBlock})(codeBlock);
316
341
  function codeBlockLanguage(options = {}) {
317
342
  return [
@@ -331,15 +356,23 @@ const languageStyles = /*@__PURE__*/Wordgard.styles({
331
356
  font: "var(--wg-dialog-font)",
332
357
  fontSize: "70%",
333
358
  position: "absolute",
334
- top: "2px",
335
- right: "4px",
359
+ top: "5px",
360
+ right: "5px",
336
361
  border: "none",
337
- borderRadius: "4px"
362
+ borderRadius: "4px",
363
+ background: "#88888827"
338
364
  }
339
365
  }
340
366
  });
341
367
  const languageOptions = /*@__PURE__*/GardState.Facet.define({
342
- combine: input => input.reduce((a, b) => a.concat(b), [])
368
+ combine: input => {
369
+ let options = [];
370
+ for (let arr of input)
371
+ for (let opt of arr)
372
+ if (!options.includes(opt))
373
+ options.push(opt);
374
+ return options;
375
+ }
343
376
  });
344
377
  function option(text, selected, value) {
345
378
  let node = document.createElement("option");
@@ -381,7 +414,7 @@ const languageWidget = /*@__PURE__*/Widget.define({
381
414
  },
382
415
  inFlow: false
383
416
  });
384
- const languageSelect = /*@__PURE__*/Decoration.Tag.widget.dynamic(CodeBlock, "end", state => {
417
+ const languageSelect = /*@__PURE__*/Decoration.Tag.widget.derived(CodeBlock, "end", state => {
385
418
  let options = state.facet(languageOptions);
386
419
  return tag => {
387
420
  return languageWidget.of({ options, value: tag.mark(CodeBlockLanguage) });
@@ -401,8 +434,11 @@ const languageSelect = /*@__PURE__*/Decoration.Tag.widget.dynamic(CodeBlock, "en
401
434
  };
402
435
  codeBlockLanguage.selectLanguageBinding = KeyBinding.of({
403
436
  key: "Shift-Mod-l",
404
- run: codeBlockLanguage.selectLanguage
437
+ run: codeBlockLanguage.selectLanguage,
438
+ description: phrases.ref("code_block_language"),
439
+ group: KeyBinding.Group.Block
405
440
  });
441
+ codeBlockLanguage.options = languageOptions;
406
442
  ;return codeBlockLanguage})(codeBlockLanguage);
407
443
 
408
444
  function strong() {
@@ -412,6 +448,8 @@ function strong() {
412
448
  strong.keyBinding = KeyBinding.of({
413
449
  key: "Mod-b",
414
450
  run: Command.bind(toggleMark, Strong),
451
+ description: phrases.ref("toggle_strong"),
452
+ group: KeyBinding.Group.Inline
415
453
  });
416
454
  strong.button = Menu.Button.toggleMark({
417
455
  mark: Strong,
@@ -430,6 +468,8 @@ function emphasis() {
430
468
  emphasis.keyBinding = KeyBinding.of({
431
469
  key: "Mod-i",
432
470
  run: Command.bind(toggleMark, Emphasis),
471
+ description: phrases.ref("toggle_em"),
472
+ group: KeyBinding.Group.Inline
433
473
  });
434
474
  emphasis.button = Menu.Button.toggleMark({
435
475
  mark: Emphasis,
@@ -448,6 +488,8 @@ function code() {
448
488
  code.keyBinding = KeyBinding.of({
449
489
  key: "Mod-`",
450
490
  run: Command.bind(toggleMark, Code),
491
+ description: phrases.ref("toggle_code"),
492
+ group: KeyBinding.Group.Inline
451
493
  });
452
494
  code.button = Menu.Button.toggleMark({
453
495
  mark: Code,
@@ -465,7 +507,9 @@ function underline() {
465
507
  ;underline = /*@__PURE__*/(function (underline) {
466
508
  underline.keyBinding = KeyBinding.of({
467
509
  key: "Mod-u",
468
- run: Command.bind(toggleMark, Underline)
510
+ run: Command.bind(toggleMark, Underline),
511
+ description: phrases.ref("toggle_underline"),
512
+ group: KeyBinding.Group.Inline
469
513
  });
470
514
  underline.button = Menu.Button.toggleMark({
471
515
  mark: Underline,
@@ -484,6 +528,8 @@ function strikethrough() {
484
528
  strikethrough.keyBinding = KeyBinding.of({
485
529
  key: "Mod-/",
486
530
  run: Command.bind(toggleMark, Strikethrough),
531
+ description: phrases.ref("toggle_strikethrough"),
532
+ group: KeyBinding.Group.Inline
487
533
  });
488
534
  strikethrough.button = Menu.Button.toggleMark({
489
535
  mark: Strikethrough,
@@ -502,6 +548,8 @@ function superscript() {
502
548
  superscript.keyBinding = KeyBinding.of({
503
549
  key: "Mod-.",
504
550
  run: Command.bind(toggleMark, Superscript),
551
+ description: phrases.ref("toggle_super"),
552
+ group: KeyBinding.Group.Inline
505
553
  });
506
554
  superscript.button = Menu.Button.toggleMark({
507
555
  mark: Superscript,
@@ -520,6 +568,8 @@ function subscript() {
520
568
  subscript.keyBinding = KeyBinding.of({
521
569
  key: "Mod-,",
522
570
  run: Command.bind(toggleMark, Subscript),
571
+ description: phrases.ref("toggle_sub"),
572
+ group: KeyBinding.Group.Inline
523
573
  });
524
574
  subscript.button = Menu.Button.toggleMark({
525
575
  mark: Subscript,
@@ -598,22 +648,6 @@ function imageTypeButtons(state, active) {
598
648
  }
599
649
  return [cr("span", { class: "wg-label" }, imagePhrases.get(state, "image_style"), ":"), cr("span", buttons)];
600
650
  }
601
- const setImageDialog = /*@__PURE__*/Transaction.Effect.define();
602
- const createImagePanel = wg => {
603
- let dom = buildImagePanel(wg), mustFocus = true;
604
- return {
605
- top: true,
606
- dom,
607
- connect() {
608
- if (mustFocus) {
609
- mustFocus = false;
610
- let target = dom.querySelector("input[name=src]");
611
- if (target)
612
- target.focus();
613
- }
614
- }
615
- };
616
- };
617
651
  function startUpload(wg, file, set) {
618
652
  let imageFile = file.files?.[0], handler = wg.state.facet(imageUploader)[0];
619
653
  if (!imageFile || !handler)
@@ -635,9 +669,8 @@ function startUpload(wg, file, set) {
635
669
  Dialog.show(wg, { label: imagePhrases.get(wg.state, "upload_failed") + ": " + err });
636
670
  });
637
671
  }
638
- function buildImagePanel(wg) {
639
- let { state } = wg;
640
- let sel = (state.field(imageDialog) || state.selection).resolve(state.doc);
672
+ function buildImageDialog(wg, close) {
673
+ let { state } = wg, { sel } = state;
641
674
  let active = activeImage(sel);
642
675
  let size = !wg.state.schema.has(ImageSize) ? null :
643
676
  [cr("label", { for: "wg-img-size" }, imagePhrases.get(state, "width"), ":"),
@@ -650,90 +683,78 @@ function buildImagePanel(wg) {
650
683
  file = cr("input", { type: "file", id: "wg-img-file", name: "file", "aria-label": imagePhrases.get(state, "upload_image"),
651
684
  onchange: (e) => startUpload(wg, e.target, url => src.value = url) });
652
685
  }
653
- let form = cr("form", { class: "wg-img-form", onkeydown }, cr("div", { class: "wg-dialog-title" }, imagePhrases.get(state, active ? "update_image" : "insert_image")), cr("label", { for: "wg-img-src" }, imagePhrases.get(state, "image_source"), ":"), cr("span", { class: "wg-img-src-line" }, src, file), cr("label", { for: "wg-img-alt" }, imagePhrases.get(state, "alt_text"), ":"), cr("input", { type: "text", id: "wg-img-alt", name: "alt",
686
+ return cr("form", { class: "wg-img-form", onkeydown }, cr("h3", { class: "wg-dialog-title" }, imagePhrases.get(state, active ? "update_image" : "insert_image")), cr("label", { for: "wg-img-src" }, imagePhrases.get(state, "image_source"), ":"), cr("span", { class: "wg-img-src-line" }, src, file), cr("label", { for: "wg-img-alt" }, imagePhrases.get(state, "alt_text"), ":"), cr("input", { type: "text", id: "wg-img-alt", name: "alt",
654
687
  value: active && active.mark(ImageAlt) || "",
655
688
  placeholder: imagePhrases.get(state, "describe_image") }), imageTypeButtons(state, active), size, cr("div", { class: "wg-img-buttons" }, cr("button", { type: "submit", class: "wg-dialog-button" }, imagePhrases.get(state, active ? "update" : "insert")), " ", cr("button", { type: "button", class: "wg-dialog-button", onclick: close }, imagePhrases.get(state, "cancel"))));
656
- function onsubmit(e) {
657
- e.preventDefault();
658
- let { state } = wg, sel = (state.field(imageDialog) || state.selection).resolve(state.doc);
659
- let data = new FormData(form);
660
- let src = data.get("src");
661
- if (!src)
662
- return;
663
- let type = data.get("type") ?? (state.schema.has(Image) ? "inline" : "start");
664
- let cap = !!data.get("caption") || !state.schema.has(Figure);
665
- let marks = [];
666
- if (type == "center" || type == "end")
667
- marks = Alignment.of(type).addToSet(marks);
668
- if (data.get("alt"))
669
- marks = ImageAlt.of(data.get("alt")).addToSet(marks);
670
- if (data.get("size"))
671
- marks = ImageSize.of(Number(data.get("size"))).addToSet(marks);
672
- let tag = type == "inline" ? Image.of(src, marks) : cap ? CaptionedFigure.of(src, marks) : Figure.of(src, marks);
673
- let change;
674
- if (sel.from.parent.node.type == CaptionedFigure && sel.to.parent.start == sel.from.parent.start) {
675
- let from = sel.from.parent.before;
676
- if (tag instanceof Plot.Tag)
677
- change = { from, to: from + 1, insert: [tag] };
678
- else
679
- change = { from, to: sel.from.parent.after, insert: [tag], fit: true };
680
- }
681
- else {
682
- change = { from: sel.from.pos, to: sel.to.pos, insert: [tag instanceof Plot.Tag ? tag.create() : tag], fit: true };
683
- }
684
- wg.focus();
685
- let changes = ChangeSet.create(state.doc, change), pos = changes.findInserted(t => t == tag) ?? change.from;
686
- wg.dispatch({
687
- changes: change,
688
- effects: setImageDialog.of(false),
689
- userEvent: "insert.image",
690
- selection: tag instanceof Plot.Tag ? { anchor: pos + 1 } : GardSelection.node(pos, tag)
691
- });
692
- }
693
- function close() {
694
- wg.focus();
695
- wg.dispatch({ effects: setImageDialog.of(false) });
689
+ }
690
+ function finishInsertImage(wg, form) {
691
+ if (!form)
692
+ return;
693
+ let { state } = wg, { sel } = state;
694
+ let data = new FormData(form);
695
+ let src = data.get("src");
696
+ if (!src)
697
+ return;
698
+ let type = data.get("type") ?? (state.schema.has(Image) ? "inline" : "start");
699
+ let cap = !!data.get("caption") || !state.schema.has(Figure);
700
+ let marks = [];
701
+ if (type == "center" || type == "end")
702
+ marks = Alignment.of(type).addToSet(marks);
703
+ if (data.get("alt"))
704
+ marks = ImageAlt.of(data.get("alt")).addToSet(marks);
705
+ if (data.get("size"))
706
+ marks = ImageSize.of(Number(data.get("size"))).addToSet(marks);
707
+ let tag = type == "inline" ? Image.of(src, marks) : cap ? CaptionedFigure.of(src, marks) : Figure.of(src, marks);
708
+ let change;
709
+ if (sel.from.parent.node.type == CaptionedFigure && sel.to.parent.start == sel.from.parent.start) {
710
+ let from = sel.from.parent.before;
711
+ if (tag instanceof Plot.Tag)
712
+ change = { from, to: from + 1, insert: [tag] };
713
+ else
714
+ change = { from, to: sel.from.parent.after, insert: [tag], fit: true };
696
715
  }
697
- function onkeydown(e) {
698
- if (e.key == "Escape") {
699
- e.preventDefault();
700
- close();
701
- }
716
+ else {
717
+ change = { from: sel.from.pos, to: sel.to.pos, insert: [tag instanceof Plot.Tag ? tag.create() : tag], fit: true };
702
718
  }
703
- return cr("wg-dialog", { class: "wg-img-dialog", onsubmit }, form);
719
+ let changes = ChangeSet.create(state.doc, change), pos = changes.findInserted(t => t == tag) ?? change.from;
720
+ wg.dispatch({
721
+ changes: change,
722
+ userEvent: "insert.image",
723
+ selection: tag instanceof Plot.Tag ? { anchor: pos + 1 } : GardSelection.node(pos, tag)
724
+ });
704
725
  }
705
726
  const insertImage = wg => {
706
- let val = wg.state.field(imageDialog, false);
707
- if (val) {
708
- wg.dispatch({ effects: setImageDialog.of(false) });
727
+ let open = Dialog.get(wg, insertImage);
728
+ if (open) {
729
+ open.close();
709
730
  }
710
731
  else {
711
- let effects = [setImageDialog.of(true)];
712
- if (val === undefined)
713
- effects.push(GardState.appendConfig.of(imageDialog));
714
- wg.dispatch({ effects });
732
+ Dialog.show(wg, {
733
+ key: insertImage,
734
+ content: buildImageDialog,
735
+ closedBy: tr => !!tr.selection,
736
+ focus: "input[name=src]",
737
+ class: "wg-img-dialog",
738
+ tooltip: { pos: wg.state.selection.from },
739
+ positioningHint: true
740
+ }).result.then(form => finishInsertImage(wg, form));
715
741
  }
716
742
  return true;
717
743
  };
718
744
  const imageDialogTheme = /*@__PURE__*/Wordgard.styles({
719
- ".wg-img-dialog": {
720
- borderBottom: "1px solid var(--wg-border-color)"
721
- },
745
+ ".wg-img-dialog": {},
722
746
  ".wg-img-form": {
723
- padding: "5px 3px",
724
747
  display: "grid",
725
748
  gap: "8px",
726
749
  alignItems: "center",
727
750
  gridTemplateColumns: "max-content auto",
728
751
  "& label, & .wg-label": {
729
- textAlign: "right"
752
+ textAlign: "end"
730
753
  }
731
754
  },
732
- ".wg-dialog-title": {
755
+ ".wg-img-form .wg-dialog-title": {
733
756
  gridColumn: "span 2",
734
- fontSize: "90%",
735
- fontWeight: "bold",
736
- textAlign: "center"
757
+ margin: "0"
737
758
  },
738
759
  ".wg-img-buttons": {
739
760
  gridColumn: "2"
@@ -773,23 +794,11 @@ const imageDialogTheme = /*@__PURE__*/Wordgard.styles({
773
794
  fontSize: "80%"
774
795
  }
775
796
  });
776
- const imageDialog = /*@__PURE__*/GardState.Field.define({
777
- create: () => null,
778
- update(value, tr) {
779
- for (let e of tr.effects)
780
- if (e.is(setImageDialog))
781
- return e.value ? tr.state.selection : null;
782
- return value && value.map(tr.changes, tr.state);
783
- },
784
- provide: f => [
785
- GardState.prec.lowest(Panel.show.from(f, val => val && createImagePanel)),
786
- imageDialogTheme
787
- ]
788
- });
789
797
 
790
798
  function baseSupport() {
791
- return [GardState.schemaElement.of(ImageAlt), image.button, imageDialog, image.keyBinding, image.dropHandler];
799
+ return [GardState.schemaElement.of(ImageAlt), image.button, imageDialogTheme, image.keyBinding, image.dropHandler];
792
800
  }
801
+ const ImageGroup = /*@__PURE__*/(() => KeyBinding.Group.define({ description: imagePhrases.ref("group_image"), rank: 90 }))();
793
802
  function image() {
794
803
  return [GardState.schemaElement.of(Image), baseSupport()];
795
804
  }
@@ -910,8 +919,18 @@ const resizeHandlers = /*@__PURE__*/(() => [
910
919
  return false;
911
920
  };
912
921
  imageResizing.keyBindings = [
913
- KeyBinding.of({ key: "Ctrl-Alt-l", mac: "Ctrl-Cmd-l", run: imageResizing.resizeCommand(1.1, true) }),
914
- KeyBinding.of({ key: "Ctrl-Alt-k", mac: "Ctrl-Cmd-k", run: imageResizing.resizeCommand(0.9091, true) }),
922
+ KeyBinding.of({
923
+ key: "Ctrl-Alt-l", mac: "Ctrl-Cmd-l",
924
+ run: imageResizing.resizeCommand(1.1, true),
925
+ description: imagePhrases.ref("resize_up"),
926
+ group: ImageGroup
927
+ }),
928
+ KeyBinding.of({
929
+ key: "Ctrl-Alt-k", mac: "Ctrl-Cmd-k",
930
+ run: imageResizing.resizeCommand(0.9091, true),
931
+ description: imagePhrases.ref("resize_down"),
932
+ group: ImageGroup
933
+ }),
915
934
  ];
916
935
  imageResizing.dragHandle = [
917
936
  GardState.prec.high(resizeHandlers),
@@ -921,7 +940,12 @@ const resizeHandlers = /*@__PURE__*/(() => [
921
940
  ];
922
941
  ;return imageResizing})(imageResizing);
923
942
  ;image = /*@__PURE__*/(function (image) {
924
- image.keyBinding = KeyBinding.of({ key: "Ctrl-Alt-i", mac: "Ctrl-Cmd-i", run: insertImage });
943
+ image.keyBinding = KeyBinding.of({
944
+ key: "Ctrl-Alt-i", mac: "Ctrl-Cmd-i",
945
+ run: insertImage,
946
+ description: imagePhrases.ref("insert_image"),
947
+ group: ImageGroup
948
+ });
925
949
  image.button = Menu.Button.define({
926
950
  run: insertImage,
927
951
  active: state => !!activeImage(state.sel),
@@ -1247,11 +1271,9 @@ const backgroundPicker = /*@__PURE__*/Menu.CustomControl.define({
1247
1271
  function toggleLink(wg) {
1248
1272
  if (wg.state.readOnly)
1249
1273
  return false;
1250
- let open = Dialog.get(wg, "wg-link-dialog");
1274
+ let open = Dialog.get(wg, toggleLink);
1251
1275
  if (open) {
1252
- if (open.dom.contains(wg.contentDOM.ownerDocument.activeElement))
1253
- wg.focus();
1254
- Dialog.close(wg, "wg-link-dialog");
1276
+ open.close();
1255
1277
  return true;
1256
1278
  }
1257
1279
  let { selection, doc } = wg.state;
@@ -1269,11 +1291,14 @@ function toggleLink(wg) {
1269
1291
  }
1270
1292
  else {
1271
1293
  Dialog.show(wg, {
1294
+ key: toggleLink,
1272
1295
  label: phrases.get(wg.state, "link_target"),
1273
1296
  input: { type: "text", name: "url" },
1274
1297
  submitLabel: phrases.get(wg.state, "create_link"),
1275
1298
  class: "wg-link-dialog",
1276
- focus: true
1299
+ focus: true,
1300
+ closedBy: tr => !!tr.selection,
1301
+ tooltip: { pos: wg.state.selection.from }
1277
1302
  }).result.then(form => {
1278
1303
  wg.focus();
1279
1304
  let url = form && form.elements.namedItem("url")?.value;
@@ -1347,6 +1372,8 @@ function link() {
1347
1372
  link_1.keyBinding = KeyBinding.of({
1348
1373
  key: "Mod-k",
1349
1374
  run: toggleLink,
1375
+ description: phrases.ref("create_link"),
1376
+ group: KeyBinding.Group.Inline
1350
1377
  });
1351
1378
  link_1.button = Menu.Button.define({
1352
1379
  run: toggleLink,
@@ -1386,7 +1413,7 @@ function link() {
1386
1413
  linkTooltipTheme
1387
1414
  ];
1388
1415
  link_1.pasteOver = Wordgard.pasteHandler.of((wg, event) => {
1389
- let { selection } = wg.state, data = event.clipboardData;
1416
+ let { selection } = wg.state, data = event.dataTransfer;
1390
1417
  if (!data || selection.empty)
1391
1418
  return false;
1392
1419
  let text = data.getData("text/plain") || data.getData("Text") || data.getData("text/uri-list");
@@ -1429,4 +1456,4 @@ function fullSchema() {
1429
1456
  ];
1430
1457
  }
1431
1458
 
1432
- export { ColorPicker, alignment, backgroundColor, basicMarks, basicSchema, blockDoc, blockquote, bulletList, code, codeBlock, color, direction, emphasis, figure, fullSchema, heading, horizontalRule, image, imageResizing, inlineDoc, inlineMarks, inlineSchema, lineBreak, link, orderedList, paragraph, strikethrough, strong, subscript, superscript, underline };
1459
+ export { ColorPicker, alignment, backgroundColor, basicMarks, basicSchema, blockDoc, blockquote, bulletList, code, codeBlock, codeBlockLanguage, color, direction, emphasis, figure, fullSchema, heading, horizontalRule, image, imageResizing, inlineDoc, inlineMarks, inlineSchema, lineBreak, link, orderedList, paragraph, strikethrough, strong, subscript, superscript, underline };
package/dist/set.d.ts CHANGED
@@ -195,9 +195,10 @@ declare class PointSet<T extends PointSet.Value> implements Set<T> {
195
195
  /**
196
196
  Get the value at the given position, if any. If there's multiple
197
197
  values at that position, the one with the lowest side is
198
- returned.
198
+ returned. If a predicate is given, only points that satisfy it
199
+ are returned.
199
200
  */
200
- at(pos: number): T | undefined;
201
+ at(pos: number, pred?: (value: T) => boolean): T | undefined;
201
202
  /**
202
203
  Adjust the points for a set of document changes. Returns a new
203
204
  set with the adjusted points. May delete points when the content
package/dist/set.js CHANGED
@@ -99,6 +99,7 @@ class HeapCursor {
99
99
  heapSink(this.heap, this.heap.length - 1, this.cmp);
100
100
  }
101
101
  }
102
+ this.fill();
102
103
  }
103
104
  next() {
104
105
  if (this.heap.length) {
@@ -555,15 +556,16 @@ class PointSet {
555
556
  cursors.push(set.cursor(from, side));
556
557
  return cursors.length == 0 ? PointSet.empty.cursor() : cursors.length == 1 ? cursors[0] : new HeapCursor(cmpCursor, cursors);
557
558
  }
558
- at(pos) {
559
+ at(pos, pred) {
559
560
  for (let chunk of this.chunks) {
560
- if (chunk.end > pos)
561
- break;
562
561
  if (chunk.start > pos)
562
+ break;
563
+ if (chunk.end < pos)
563
564
  continue;
564
- let index = findAbove(chunk.pos, 0, pos - 1);
565
- if (index < chunk.pos.length && chunk.pos[index] == pos)
566
- return chunk.value[index];
565
+ for (let index = findAbove(chunk.pos, 0, pos - chunk.start - 1); index < chunk.pos.length && chunk.pos[index] + chunk.start == pos; index++) {
566
+ if (!pred || pred(chunk.value[index]))
567
+ return chunk.value[index];
568
+ }
567
569
  }
568
570
  return undefined;
569
571
  }