@humandialog/forms.svelte 1.2.7 → 1.3.2

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.
@@ -35,6 +35,12 @@ function update(...args) {
35
35
  else
36
36
  isExpandable = false;
37
37
  }
38
+ export function activateMainOperation() {
39
+ const mainOperationButton = document.getElementById("__hd_fab_mainOperation");
40
+ if (!mainOperationButton)
41
+ return;
42
+ mainOperationButton.click();
43
+ }
38
44
  function on_click(e, operation) {
39
45
  if (!operation)
40
46
  return;
@@ -90,7 +96,8 @@ function getSelectionPos() {
90
96
  {#if operations && operations.length > 0}
91
97
  {@const topPosition = 350}
92
98
  {@const verticalPosition = mainOperation.aboveKeyboard ? `bottom: ${topPosition}px` : "bottom: 10px"}
93
- <button class="text-white bg-blue-700 hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300
99
+ <button id="__hd_fab_mainOperation"
100
+ class="text-white bg-blue-700 hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300
94
101
  font-medium rounded-full text-sm text-center shadow-md
95
102
  w-[55px] h-[55px]
96
103
  fixed m-0 absolute bottom-0 right-[0px]
@@ -1,6 +1,8 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
2
  declare const __propDef: {
3
- props: Record<string, never>;
3
+ props: {
4
+ activateMainOperation?: (() => void) | undefined;
5
+ };
4
6
  events: {
5
7
  [evt: string]: CustomEvent<any>;
6
8
  };
@@ -10,5 +12,6 @@ export type FabProps = typeof __propDef.props;
10
12
  export type FabEvents = typeof __propDef.events;
11
13
  export type FabSlots = typeof __propDef.slots;
12
14
  export default class Fab extends SvelteComponentTyped<FabProps, FabEvents, FabSlots> {
15
+ get activateMainOperation(): () => void;
13
16
  }
14
17
  export {};
@@ -1,7 +1,7 @@
1
1
  <script>import { afterUpdate, tick } from "svelte";
2
2
  import Icon from "./icon.svelte";
3
3
  import { contextItemsStore } from "../stores";
4
- import { isDeviceSmallerThan } from "../utils";
4
+ import { isDeviceSmallerThan, isOnScreenKeyboardVisible } from "../utils";
5
5
  import { hideWholeContextMenu } from "./menu";
6
6
  export let widthPx = 400;
7
7
  export let menu_items_id_prefix = "__hd_svelte_menuitem_";
@@ -24,16 +24,8 @@ afterUpdate(() => {
24
24
  return;
25
25
  const m = 15;
26
26
  let container_rect = new DOMRect(m, 0, window.innerWidth - 2 * m, window.innerHeight);
27
- if (isDeviceSmallerThan("sm")) {
28
- const sel = window.getSelection();
29
- console.log("sel", sel);
30
- if (sel && sel.rangeCount > 0 && sel.focusNode && sel.focusNode.nodeType == sel.focusNode.TEXT_NODE) {
31
- const el = sel.focusNode.parentElement;
32
- if (el && (el.isContentEditable || el.contentEditable == "true" || el.tagName == "INPUT")) {
33
- console.log("keyboard visible, move menu 300px up", el);
34
- container_rect.height -= 300;
35
- }
36
- }
27
+ if (isOnScreenKeyboardVisible()) {
28
+ container_rect.height -= 300;
37
29
  }
38
30
  let xShifted = false;
39
31
  if (rect.right > container_rect.right) {
@@ -1,4 +1,4 @@
1
- <script>import { onMount, onDestroy, getContext, afterUpdate } from "svelte";
1
+ <script>import { onMount, onDestroy, getContext, afterUpdate, tick } from "svelte";
2
2
  import { reef, session } from "@humandialog/auth.svelte";
3
3
  import { Editor } from "@tiptap/core";
4
4
  import StarterKit from "@tiptap/starter-kit";
@@ -10,18 +10,35 @@ import Blockquote from "@tiptap/extension-blockquote";
10
10
  import HardBreak from "@tiptap/extension-hard-break";
11
11
  import HorizontalRule from "@tiptap/extension-horizontal-rule";
12
12
  import Image from "@tiptap/extension-image";
13
+ import Link from "@tiptap/extension-link";
13
14
  import Bold from "@tiptap/extension-bold";
14
15
  import Code from "@tiptap/extension-code";
15
16
  import Italic from "@tiptap/extension-italic";
16
17
  import Strike from "@tiptap/extension-strike";
18
+ import Underline from "@tiptap/extension-underline";
17
19
  import Dropcursor from "@tiptap/extension-dropcursor";
18
20
  import Gapcursor from "@tiptap/extension-gapcursor";
19
21
  import History from "@tiptap/extension-history";
20
22
  import { data_tick_store, contextItemsStore, contextTypesStore, onErrorShowAlert } from "../../stores.js";
21
23
  import { informModification, pushChanges } from "../../updates.js";
22
- import { isDeviceSmallerThan, parseWidthDirective } from "../../utils.js";
24
+ import { isDeviceSmallerThan, parseWidthDirective, refreshToolbarOperations, UI } from "../../utils.js";
23
25
  import Palette from "./internal/palette.svelte";
24
- import { FaFont, FaRemoveFormat, FaCode, FaComment, FaQuoteRight, FaExclamationTriangle, FaInfo, FaImage } from "svelte-icons/fa";
26
+ import {
27
+ FaFont,
28
+ FaRemoveFormat,
29
+ FaCode,
30
+ FaComment,
31
+ FaQuoteRight,
32
+ FaExclamationTriangle,
33
+ FaInfo,
34
+ FaImage,
35
+ FaBold,
36
+ FaItalic,
37
+ FaUnderline,
38
+ FaStrikethrough,
39
+ FaArrowLeft,
40
+ FaGripLines
41
+ } from "svelte-icons/fa";
25
42
  import IcH1 from "./internal/h1.icon.svelte";
26
43
  import IcH2 from "./internal/h2.icon.svelte";
27
44
  import IcH3 from "./internal/h3.icon.svelte";
@@ -46,14 +63,34 @@ export function run(onStop = void 0) {
46
63
  onFinishEditing = onStop;
47
64
  editor.commands.focus();
48
65
  }
66
+ let suggestionRange = void 0;
49
67
  export function getFormattingOperations(withCaptions = false) {
50
68
  let result = [];
69
+ if (isDeviceSmallerThan("sm")) {
70
+ result = [
71
+ {
72
+ caption: "Back to edit",
73
+ icon: FaArrowLeft,
74
+ action: (fi) => {
75
+ editor?.commands.focus();
76
+ }
77
+ },
78
+ {
79
+ separator: true
80
+ }
81
+ ];
82
+ }
51
83
  commands.forEach((c2) => {
52
- result.push({
53
- caption: withCaptions ? c2.caption : "",
54
- icon: c2.icon,
55
- action: c2.on_choice
56
- });
84
+ if (c2.separator) {
85
+ result.push({ separator: true });
86
+ } else {
87
+ result.push({
88
+ caption: withCaptions ? c2.caption : "",
89
+ icon: c2.icon,
90
+ action: (f) => c2.on_choice(suggestionRange),
91
+ activeFunc: c2.is_active
92
+ });
93
+ }
57
94
  });
58
95
  return result;
59
96
  }
@@ -71,6 +108,7 @@ else
71
108
  dark:bg-stone-700 dark:border-stone-600
72
109
  px-2.5`;
73
110
  let last_tick = -1;
111
+ let lockNextBlurCallbacks = 0;
74
112
  $:
75
113
  updateAfterUIChanges($data_tick_store);
76
114
  function updateAfterUIChanges(...args) {
@@ -133,10 +171,17 @@ const suggestion = {
133
171
  if (!props.clientRect) {
134
172
  return;
135
173
  }
136
- const cursorRect = props.clientRect();
137
- show_command_palette(cursorRect);
138
- palette.set_current_editor_range(props.range);
139
- palette.filter("");
174
+ if (isDeviceSmallerThan("sm")) {
175
+ lockNextBlurCallbacks++;
176
+ suggestionRange = props.range;
177
+ editor.commands.blur();
178
+ setTimeout(() => UI.fab?.activateMainOperation(), 100);
179
+ } else {
180
+ const cursorRect = props.clientRect();
181
+ show_command_palette(cursorRect);
182
+ palette.set_current_editor_range(props.range);
183
+ palette.filter("");
184
+ }
140
185
  },
141
186
  onUpdate(props) {
142
187
  if (is_command_palette_visible) {
@@ -319,69 +364,6 @@ const QuoteBlock = Paragraph.extend({
319
364
  };
320
365
  }
321
366
  });
322
- function prepareFullImagePath(url) {
323
- if (!url.startsWith("/json/")) {
324
- const apiVer = $session.configuration.api_version ?? "anyv";
325
- if (url.startsWith("/"))
326
- url = `/json/${apiVer}${url}`;
327
- else
328
- url = `/json/${apiVer}/${url}`;
329
- }
330
- let fullPath = "";
331
- let absolute_pattern = /^https?:\/\//i;
332
- if (!absolute_pattern.test(url)) {
333
- fullPath = $session.apiAddress;
334
- if (fullPath.endsWith("/")) {
335
- if (url.startsWith("/"))
336
- fullPath = fullPath + url.substr(1);
337
- else
338
- fullPath = fullPath + url;
339
- } else {
340
- if (url.startsWith("/"))
341
- fullPath = fullPath + url;
342
- else
343
- fullPath = fullPath + "/" + url;
344
- }
345
- } else
346
- fullPath = url;
347
- if ($session.tenants.length > 0) {
348
- const currentGroupInfo = $session.tenants.find((t) => t.id == $session.tid);
349
- if (currentGroupInfo && currentGroupInfo.headers && currentGroupInfo.headers.length > 0) {
350
- const paramsNo = currentGroupInfo.headers.length;
351
- for (let i = 0; i < paramsNo; i++) {
352
- const param = currentGroupInfo.headers[i];
353
- if (i == 0) {
354
- if (fullPath.includes("?")) {
355
- fullPath += "&";
356
- } else {
357
- fullPath += "?";
358
- }
359
- } else
360
- fullPath += "&";
361
- fullPath += param.key.toLowerCase();
362
- fullPath += "=" + param.value;
363
- }
364
- }
365
- } else {
366
- const user = $session.localDevCurrentUser;
367
- if (user) {
368
- if (fullPath.includes("?")) {
369
- fullPath += "&";
370
- } else {
371
- fullPath += "?";
372
- }
373
- if (user.uid > 0)
374
- fullPath += "x-reef-user-id=" + user.uid;
375
- else
376
- fullPath += "x-reef-as-user=" + user.username;
377
- if (user.role)
378
- fullPath += "&x-reef-access-role=" + user.role;
379
- if (user.groupId)
380
- fullPath += "&x-reef-group-id=" + user.groupId;
381
- }
382
- }
383
- return fullPath;
384
- }
385
367
  let downloadedImages = [];
386
368
  const CrossImage = Image.extend({
387
369
  addAttributes() {
@@ -478,6 +460,8 @@ onMount(() => {
478
460
  Code,
479
461
  Italic,
480
462
  Strike,
463
+ Underline,
464
+ Link,
481
465
  Dropcursor,
482
466
  Gapcursor,
483
467
  History,
@@ -491,15 +475,20 @@ onMount(() => {
491
475
  hasChangedValue = true;
492
476
  changedValue = editor2.getHTML();
493
477
  handleImagesChanges(transaction);
478
+ refreshToolbarOperations();
494
479
  },
495
480
  onFocus({ editor: editor2, event }) {
496
481
  if (onFocusCb)
497
482
  onFocusCb();
498
483
  },
499
484
  onBlur({ editor: editor2, event }) {
500
- on_blur();
501
- if (onBlurCb)
502
- onBlurCb();
485
+ if (lockNextBlurCallbacks > 0) {
486
+ lockNextBlurCallbacks--;
487
+ } else {
488
+ on_blur();
489
+ if (onBlurCb)
490
+ onBlurCb();
491
+ }
503
492
  },
504
493
  onContentError({ editor: editor2, error, disableCollaboration }) {
505
494
  console.log("editor content error:", error);
@@ -639,61 +628,101 @@ function handleImagesChanges(transaction) {
639
628
  deletedImageSrcs.forEach((src) => onRemoveImage(src));
640
629
  }
641
630
  let commands = [
631
+ { caption: "Bold", description: "Marks text as bolded", tags: "strong", icon: FaBold, on_choice: makeBold, is_active: () => editor?.isActive("bold") },
632
+ { caption: "Italic", description: "Marks text as italic", tags: "strong", icon: FaItalic, on_choice: makeItalic, is_active: () => editor?.isActive("italic") },
633
+ { caption: "Underlie", description: "Marks text as underlined", icon: FaUnderline, on_choice: makeUnderline, is_active: () => editor?.isActive("underline") },
634
+ { caption: "Strikethrough", description: "Marks text as strikethrough", icon: FaStrikethrough, on_choice: makeStrikethrough, is_active: () => editor?.isActive("strike") },
635
+ { caption: "Styles", separator: true },
642
636
  { caption: "Normal", description: "This is normal text style", tags: "text", icon: FaRemoveFormat, on_choice: (range) => {
643
637
  if (range)
644
638
  editor.chain().focus().deleteRange(range).setParagraph().run();
645
639
  else
646
640
  editor.commands.setParagraph();
647
- } },
641
+ }, is_active: () => editor?.isActive("paragraph") },
648
642
  { caption: "Heading 1", description: "Description heading", tags: "h1", icon: IcH1, on_choice: (range) => {
649
643
  if (range)
650
644
  editor.chain().focus().deleteRange(range).setHeading({ level: 1 }).run();
651
645
  else
652
646
  editor.commands.setHeading({ level: 1 });
653
- } },
654
- { caption: "Heading 2", description: "Description heading", tags: "h2", icon: IcH2, on_choice: (range) => {
647
+ }, is_active: () => editor?.isActive("heading", { level: 1 }) },
648
+ { caption: "Heading 2", description: "Secondary heading", tags: "h2", icon: IcH2, on_choice: (range) => {
655
649
  if (range)
656
650
  editor.chain().focus().deleteRange(range).setHeading({ level: 2 }).run();
657
651
  else
658
652
  editor.commands.setHeading({ level: 2 });
659
- } },
653
+ }, is_active: () => editor?.isActive("heading", { level: 2 }) },
660
654
  { caption: "Code", description: "Source code monospace text", icon: FaCode, on_choice: (range) => {
661
655
  if (range)
662
656
  editor.chain().focus().deleteRange(range).setAsCode().run();
663
657
  else
664
658
  editor.commands.setAsCode();
665
- } },
659
+ }, is_active: () => editor?.isActive("CodeBlock") },
666
660
  { caption: "Comment", description: "With this you can comment the above paragraph", icon: FaComment, on_choice: (range) => {
667
661
  if (range)
668
662
  editor.chain().focus().deleteRange(range).setAsComment().run();
669
663
  else
670
664
  editor.commands.setAsComment();
671
- } },
665
+ }, is_active: () => editor?.isActive("CommentBlock") },
672
666
  { caption: "Quote", description: "To quote someone", icon: FaQuoteRight, on_choice: (range) => {
673
667
  if (range)
674
668
  editor.chain().focus().deleteRange(range).setAsQuote().run();
675
669
  else
676
670
  editor.commands.setAsQuote();
677
- } },
671
+ }, is_active: () => editor?.isActive("QuoteBlock") },
678
672
  { caption: "Warning", description: "An important warning to above paragraph", icon: FaExclamationTriangle, on_choice: (range) => {
679
673
  if (range)
680
674
  editor.chain().focus().deleteRange(range).setAsWarning().run();
681
675
  else
682
676
  editor.commands.setAsWarning();
683
- } },
677
+ }, is_active: () => editor?.isActive("WarningBlock") },
684
678
  { caption: "Info", description: "An important info about above paragraph", icon: FaInfo, on_choice: (range) => {
685
679
  if (range)
686
680
  editor.chain().focus().deleteRange(range).setAsInfo().run();
687
681
  else
688
682
  editor.commands.setAsInfo();
689
- } },
683
+ }, is_active: () => editor?.isActive("InfoBlock") },
684
+ { caption: "Other blocks", separator: true },
690
685
  { caption: "Image", description: "Add image to document", icon: FaImage, on_choice: (range) => {
691
686
  if (range)
692
687
  editor.chain().focus().deleteRange(range).run();
693
688
  if (onAddImage)
694
689
  onAddImage(onAddedImageReady);
690
+ } },
691
+ { caption: "Horizontal rule", description: "Add horizonal role", tags: "hr", icon: FaGripLines, on_choice: (range) => {
692
+ if (range)
693
+ editor.chain().focus().deleteRange(range).setHorizontalRule().run();
694
+ else
695
+ editor.commands.setHorizontalRule();
695
696
  } }
696
697
  ];
698
+ function makeBold(range) {
699
+ if (range) {
700
+ editor.chain().focus().deleteRange(range).toggleBold().run();
701
+ } else {
702
+ editor.chain().focus().toggleBold().run();
703
+ }
704
+ }
705
+ function makeItalic(range) {
706
+ if (range) {
707
+ editor.chain().focus().deleteRange(range).toggleItalic().run();
708
+ } else {
709
+ editor.chain().focus().toggleItalic().run();
710
+ }
711
+ }
712
+ function makeUnderline(range) {
713
+ if (range) {
714
+ editor.chain().focus().deleteRange(range).toggleUnderline().run();
715
+ } else {
716
+ editor.chain().focus().toggleUnderline().run();
717
+ }
718
+ }
719
+ function makeStrikethrough(range) {
720
+ if (range) {
721
+ editor.chain().focus().deleteRange(range).toggleStrike().run();
722
+ } else {
723
+ editor.chain().focus().toggleStrike().run();
724
+ }
725
+ }
697
726
  </script>
698
727
 
699
728
 
@@ -6,4 +6,6 @@ export declare class Document_command {
6
6
  icon: any;
7
7
  icon_size?: number;
8
8
  on_choice: any;
9
+ is_active: any;
10
+ separator?: boolean;
9
11
  }
@@ -6,4 +6,6 @@ export class Document_command {
6
6
  icon;
7
7
  icon_size = 6;
8
8
  on_choice;
9
+ is_active;
10
+ separator = false;
9
11
  }
@@ -4,18 +4,40 @@ export let id;
4
4
  export let cmd;
5
5
  export let width_px = 400;
6
6
  export let is_highlighted = false;
7
+ export let active = false;
7
8
  let icon_placeholder_size = cmd.description ? 12 : 6;
8
9
  let icon_size = cmd.icon_size ? cmd.icon_size : icon_placeholder_size - 6;
9
- let cl = $$props.class ? $$props.class : "";
10
+ let cl = $$props.class ?? "";
10
11
  $:
11
- active_class = is_highlighted ? "bg-stone-200 dark:bg-stone-700" : "";
12
+ active_class = calculateBackground(is_highlighted, active);
13
+ function calculateBackground(...args) {
14
+ if (is_highlighted) {
15
+ if (active)
16
+ return "bg-stone-400/40 dark:bg-stone-400/40";
17
+ else
18
+ return "bg-stone-400/30 dark:bg-stone-400/30";
19
+ } else {
20
+ if (active)
21
+ return "bg-stone-400/20 dark:bg-stone-400/20";
22
+ else
23
+ return "";
24
+ }
25
+ }
26
+ let element;
27
+ export function scrollToView() {
28
+ element?.scrollIntoView({
29
+ block: "nearest",
30
+ inline: "nearest"
31
+ });
32
+ }
12
33
  </script>
13
34
 
14
35
  <!-- svelte-ignore a11y-click-events-have-key-events -->
15
36
  <div id={id} class="font-medium m-0 p-0 text-sm w-full text-left flex flew-row cursor-context-menu {active_class} {cl}"
16
37
  on:click
17
38
  on:mousemove
18
- on:mousedown>
39
+ on:mousedown
40
+ bind:this={element}>
19
41
  <div class="flex items-center justify-center" style:width={`${icon_placeholder_size*0.25}rem`}>
20
42
  {#if cmd.icon}
21
43
  <Icon size={icon_size} component={cmd.icon}/>
@@ -7,6 +7,8 @@ declare const __propDef: {
7
7
  cmd: Document_command;
8
8
  width_px?: number | undefined;
9
9
  is_highlighted?: boolean | undefined;
10
+ active?: boolean | undefined;
11
+ scrollToView?: (() => void) | undefined;
10
12
  };
11
13
  events: {
12
14
  click: MouseEvent;
@@ -21,6 +23,7 @@ export type PaletteProps = typeof __propDef.props;
21
23
  export type PaletteEvents = typeof __propDef.events;
22
24
  export type PaletteSlots = typeof __propDef.slots;
23
25
  export default class Palette extends SvelteComponentTyped<PaletteProps, PaletteEvents, PaletteSlots> {
26
+ get scrollToView(): () => void;
24
27
  get id(): string;
25
28
  /**accessor*/
26
29
  set id(_: string);
@@ -33,5 +36,11 @@ export default class Palette extends SvelteComponentTyped<PaletteProps, PaletteE
33
36
  get is_highlighted(): boolean | undefined;
34
37
  /**accessor*/
35
38
  set is_highlighted(_: boolean | undefined);
39
+ get active(): boolean | undefined;
40
+ /**accessor*/
41
+ set active(_: boolean | undefined);
42
+ get undefined(): any;
43
+ /**accessor*/
44
+ set undefined(_: any);
36
45
  }
37
46
  export {};