svedit 0.6.0 → 0.6.1

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.
@@ -16,8 +16,18 @@
16
16
  );
17
17
  });
18
18
 
19
+ let plain_text = $derived(svedit.session.get(path).text);
20
+ let is_empty = $derived(
21
+ get_char_length(plain_text) === 0 && !(svedit.is_composing && is_focused)
22
+ );
23
+
24
+ let is_collapsed = $derived(
25
+ is_focused && svedit.session.selection?.anchor_offset == svedit.session.selection?.focus_offset
26
+ );
27
+
19
28
  // Get selection highlight range if not inside an annotation
20
29
  let selection_highlight_range = $derived.by(() => {
30
+ if (is_collapsed) return null;
21
31
  if (!is_focused) return null;
22
32
  if (svedit.session.active_annotation()) return null;
23
33
  const sel = svedit.session.selection;
@@ -25,6 +35,14 @@
25
35
  return get_selection_range(sel);
26
36
  });
27
37
 
38
+ let fragments = $derived(
39
+ get_fragments(
40
+ svedit.session.get(path).text,
41
+ svedit.session.get(path).annotations,
42
+ selection_highlight_range
43
+ )
44
+ );
45
+
28
46
  /**
29
47
  * Converts text with annotations into renderable fragments for display.
30
48
  * @param {string} text - The plain text content
@@ -78,18 +96,6 @@
78
96
 
79
97
  return fragments;
80
98
  }
81
-
82
- let fragments = $derived(
83
- get_fragments(
84
- svedit.session.get(path).text,
85
- svedit.session.get(path).annotations,
86
- selection_highlight_range
87
- )
88
- );
89
- let plain_text = $derived(svedit.session.get(path).text);
90
- let is_empty = $derived(
91
- get_char_length(plain_text) === 0 && !(svedit.is_composing && is_focused)
92
- );
93
99
  </script>
94
100
 
95
101
  <!-- ATTENTION: The comments are needed to prevent unwanted text nodes with whitespace. -->
@@ -1 +1 @@
1
- {"version":3,"file":"AnnotatedTextProperty.svelte.d.ts","sourceRoot":"","sources":["../src/lib/AnnotatedTextProperty.svelte.js"],"names":[],"mappings":";;;;;AAuHA,2HAAoE"}
1
+ {"version":3,"file":"AnnotatedTextProperty.svelte.d.ts","sourceRoot":"","sources":["../src/lib/AnnotatedTextProperty.svelte.js"],"names":[],"mappings":";;;;;AA6HA,2HAAoE"}
@@ -68,7 +68,9 @@
68
68
  const key_mapper = getContext('key_mapper');
69
69
 
70
70
  // Initialize commands and keymap on the session
71
- session.initialize_commands(context);
71
+ $effect(() => {
72
+ session.initialize_commands(context);
73
+ });
72
74
 
73
75
  // Handle focus - push session's keymap onto stack
74
76
  function handle_canvas_focus() {
@@ -977,8 +979,8 @@ ${fallback_html}`;
977
979
  }
978
980
  }
979
981
 
980
- let anchor_offset = 0;
981
- let focus_offset = 0;
982
+ let start_offset = 0;
983
+ let end_offset = 0;
982
984
  let current_offset = 0;
983
985
 
984
986
  function processNode(node) {
@@ -988,12 +990,12 @@ ${fallback_html}`;
988
990
  if (node === range.startContainer) {
989
991
  // Convert UTF-16 offset to character offset
990
992
  const char_start_offset = utf16_to_char_offset(nodeText, range.startOffset);
991
- anchor_offset = current_offset + char_start_offset;
993
+ start_offset = current_offset + char_start_offset;
992
994
  }
993
995
  if (node === range.endContainer) {
994
996
  // Convert UTF-16 offset to character offset
995
997
  const char_end_offset = utf16_to_char_offset(nodeText, range.endOffset);
996
- focus_offset = current_offset + char_end_offset;
998
+ end_offset = current_offset + char_end_offset;
997
999
  }
998
1000
  current_offset += nodeCharLength;
999
1001
  } else if (node.nodeType === Node.ELEMENT_NODE) {
@@ -1001,7 +1003,7 @@ ${fallback_html}`;
1001
1003
  processNode(childNode);
1002
1004
  }
1003
1005
  }
1004
- return focus_offset !== 0;
1006
+ return end_offset !== 0;
1005
1007
  }
1006
1008
 
1007
1009
  // Process nodes to find offsets
@@ -1012,21 +1014,17 @@ ${fallback_html}`;
1012
1014
  // Check if it's a backward selection
1013
1015
  // When range is provided, we can't detect backward selection from the range alone
1014
1016
  // since ranges are always normalized (start before end)
1015
- const is_backward = dom_selection
1016
- ? dom_selection.anchorNode === range.endContainer &&
1017
- dom_selection.anchorOffset === range.endOffset
1018
- : false;
1019
-
1020
- // Swap offsets if it's a backward selection
1021
- if (is_backward) {
1022
- [anchor_offset, focus_offset] = [focus_offset, anchor_offset];
1023
- }
1017
+ const is_backward = dom_selection ? __is_dom_selection_backwards() : false;
1018
+
1019
+ // Assign to anchor/focus based on direction
1020
+ const anchor_offset = is_backward ? end_offset : start_offset;
1021
+ const focus_offset = is_backward ? start_offset : end_offset;
1024
1022
 
1025
1023
  return {
1026
1024
  type: 'text',
1027
1025
  path,
1028
- anchor_offset: anchor_offset,
1029
- focus_offset: focus_offset
1026
+ anchor_offset,
1027
+ focus_offset
1030
1028
  };
1031
1029
  }
1032
1030
 
@@ -1163,8 +1161,6 @@ ${fallback_html}`;
1163
1161
  `[data-path="${selection.path.join('.')}"][data-type="text"]`
1164
1162
  );
1165
1163
  const empty_text = session.get(selection.path).text.length === 0;
1166
-
1167
- const range = window.document.createRange();
1168
1164
  const dom_selection = window.getSelection();
1169
1165
  let current_offset = 0;
1170
1166
  /** @type {HTMLElement | Text} */
@@ -1241,24 +1237,14 @@ ${fallback_html}`;
1241
1237
 
1242
1238
  // Set the range if both start and end were found
1243
1239
  if (anchor_node && focus_node) {
1244
- // Always set range in document order (start to end)
1245
- if (is_backward) {
1246
- range.setStart(focus_node, focus_node_offset);
1247
- range.setEnd(anchor_node, anchor_node_offset);
1248
- } else {
1249
- range.setStart(anchor_node, anchor_node_offset);
1250
- range.setEnd(focus_node, focus_node_offset);
1251
- }
1252
-
1253
1240
  dom_selection.removeAllRanges();
1254
- if (is_backward) {
1255
- // For backward selections, collapse to end and extend to start
1256
- range.collapse(false); // collapse to end
1257
- dom_selection.addRange(range);
1258
- dom_selection.extend(focus_node, focus_node_offset);
1259
- } else {
1260
- dom_selection.addRange(range);
1261
- }
1241
+ // NOTE: Only using setBaseAndExtent() will preserve selection direction
1242
+ dom_selection.setBaseAndExtent(
1243
+ anchor_node,
1244
+ anchor_node_offset,
1245
+ focus_node,
1246
+ focus_node_offset
1247
+ );
1262
1248
  el.focus(); // needed?
1263
1249
 
1264
1250
  // Scroll the selection into view
@@ -1 +1 @@
1
- {"version":3,"file":"Svedit.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Svedit.svelte.js"],"names":[],"mappings":";;;;;;;AAszCA;;eAAqD;iCA9xC1C,cAAc"}
1
+ {"version":3,"file":"Svedit.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Svedit.svelte.js"],"names":[],"mappings":";;;;;;;AAwyCA;;eAAqD;iCAhxC1C,cAAc"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svedit",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -16,8 +16,18 @@
16
16
  );
17
17
  });
18
18
 
19
+ let plain_text = $derived(svedit.session.get(path).text);
20
+ let is_empty = $derived(
21
+ get_char_length(plain_text) === 0 && !(svedit.is_composing && is_focused)
22
+ );
23
+
24
+ let is_collapsed = $derived(
25
+ is_focused && svedit.session.selection?.anchor_offset == svedit.session.selection?.focus_offset
26
+ );
27
+
19
28
  // Get selection highlight range if not inside an annotation
20
29
  let selection_highlight_range = $derived.by(() => {
30
+ if (is_collapsed) return null;
21
31
  if (!is_focused) return null;
22
32
  if (svedit.session.active_annotation()) return null;
23
33
  const sel = svedit.session.selection;
@@ -25,6 +35,14 @@
25
35
  return get_selection_range(sel);
26
36
  });
27
37
 
38
+ let fragments = $derived(
39
+ get_fragments(
40
+ svedit.session.get(path).text,
41
+ svedit.session.get(path).annotations,
42
+ selection_highlight_range
43
+ )
44
+ );
45
+
28
46
  /**
29
47
  * Converts text with annotations into renderable fragments for display.
30
48
  * @param {string} text - The plain text content
@@ -78,18 +96,6 @@
78
96
 
79
97
  return fragments;
80
98
  }
81
-
82
- let fragments = $derived(
83
- get_fragments(
84
- svedit.session.get(path).text,
85
- svedit.session.get(path).annotations,
86
- selection_highlight_range
87
- )
88
- );
89
- let plain_text = $derived(svedit.session.get(path).text);
90
- let is_empty = $derived(
91
- get_char_length(plain_text) === 0 && !(svedit.is_composing && is_focused)
92
- );
93
99
  </script>
94
100
 
95
101
  <!-- ATTENTION: The comments are needed to prevent unwanted text nodes with whitespace. -->
@@ -68,7 +68,9 @@
68
68
  const key_mapper = getContext('key_mapper');
69
69
 
70
70
  // Initialize commands and keymap on the session
71
- session.initialize_commands(context);
71
+ $effect(() => {
72
+ session.initialize_commands(context);
73
+ });
72
74
 
73
75
  // Handle focus - push session's keymap onto stack
74
76
  function handle_canvas_focus() {
@@ -977,8 +979,8 @@ ${fallback_html}`;
977
979
  }
978
980
  }
979
981
 
980
- let anchor_offset = 0;
981
- let focus_offset = 0;
982
+ let start_offset = 0;
983
+ let end_offset = 0;
982
984
  let current_offset = 0;
983
985
 
984
986
  function processNode(node) {
@@ -988,12 +990,12 @@ ${fallback_html}`;
988
990
  if (node === range.startContainer) {
989
991
  // Convert UTF-16 offset to character offset
990
992
  const char_start_offset = utf16_to_char_offset(nodeText, range.startOffset);
991
- anchor_offset = current_offset + char_start_offset;
993
+ start_offset = current_offset + char_start_offset;
992
994
  }
993
995
  if (node === range.endContainer) {
994
996
  // Convert UTF-16 offset to character offset
995
997
  const char_end_offset = utf16_to_char_offset(nodeText, range.endOffset);
996
- focus_offset = current_offset + char_end_offset;
998
+ end_offset = current_offset + char_end_offset;
997
999
  }
998
1000
  current_offset += nodeCharLength;
999
1001
  } else if (node.nodeType === Node.ELEMENT_NODE) {
@@ -1001,7 +1003,7 @@ ${fallback_html}`;
1001
1003
  processNode(childNode);
1002
1004
  }
1003
1005
  }
1004
- return focus_offset !== 0;
1006
+ return end_offset !== 0;
1005
1007
  }
1006
1008
 
1007
1009
  // Process nodes to find offsets
@@ -1012,21 +1014,17 @@ ${fallback_html}`;
1012
1014
  // Check if it's a backward selection
1013
1015
  // When range is provided, we can't detect backward selection from the range alone
1014
1016
  // since ranges are always normalized (start before end)
1015
- const is_backward = dom_selection
1016
- ? dom_selection.anchorNode === range.endContainer &&
1017
- dom_selection.anchorOffset === range.endOffset
1018
- : false;
1019
-
1020
- // Swap offsets if it's a backward selection
1021
- if (is_backward) {
1022
- [anchor_offset, focus_offset] = [focus_offset, anchor_offset];
1023
- }
1017
+ const is_backward = dom_selection ? __is_dom_selection_backwards() : false;
1018
+
1019
+ // Assign to anchor/focus based on direction
1020
+ const anchor_offset = is_backward ? end_offset : start_offset;
1021
+ const focus_offset = is_backward ? start_offset : end_offset;
1024
1022
 
1025
1023
  return {
1026
1024
  type: 'text',
1027
1025
  path,
1028
- anchor_offset: anchor_offset,
1029
- focus_offset: focus_offset
1026
+ anchor_offset,
1027
+ focus_offset
1030
1028
  };
1031
1029
  }
1032
1030
 
@@ -1163,8 +1161,6 @@ ${fallback_html}`;
1163
1161
  `[data-path="${selection.path.join('.')}"][data-type="text"]`
1164
1162
  );
1165
1163
  const empty_text = session.get(selection.path).text.length === 0;
1166
-
1167
- const range = window.document.createRange();
1168
1164
  const dom_selection = window.getSelection();
1169
1165
  let current_offset = 0;
1170
1166
  /** @type {HTMLElement | Text} */
@@ -1241,24 +1237,14 @@ ${fallback_html}`;
1241
1237
 
1242
1238
  // Set the range if both start and end were found
1243
1239
  if (anchor_node && focus_node) {
1244
- // Always set range in document order (start to end)
1245
- if (is_backward) {
1246
- range.setStart(focus_node, focus_node_offset);
1247
- range.setEnd(anchor_node, anchor_node_offset);
1248
- } else {
1249
- range.setStart(anchor_node, anchor_node_offset);
1250
- range.setEnd(focus_node, focus_node_offset);
1251
- }
1252
-
1253
1240
  dom_selection.removeAllRanges();
1254
- if (is_backward) {
1255
- // For backward selections, collapse to end and extend to start
1256
- range.collapse(false); // collapse to end
1257
- dom_selection.addRange(range);
1258
- dom_selection.extend(focus_node, focus_node_offset);
1259
- } else {
1260
- dom_selection.addRange(range);
1261
- }
1241
+ // NOTE: Only using setBaseAndExtent() will preserve selection direction
1242
+ dom_selection.setBaseAndExtent(
1243
+ anchor_node,
1244
+ anchor_node_offset,
1245
+ focus_node,
1246
+ focus_node_offset
1247
+ );
1262
1248
  el.focus(); // needed?
1263
1249
 
1264
1250
  // Scroll the selection into view