@limetech/lime-elements 39.44.6 → 39.45.0

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.
Files changed (25) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/limel-markdown.cjs.entry.js +1 -1
  3. package/dist/cjs/limel-prosemirror-adapter.cjs.entry.js +778 -395
  4. package/dist/cjs/{markdown-parser-ChnRAxpZ.js → markdown-parser-YH5HSSgF.js} +36 -56
  5. package/dist/collection/components/text-editor/prosemirror-adapter/editor-config.js +12 -1
  6. package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-command-utils/active-state-utils.js +36 -0
  7. package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-command-utils/list-utils.js +270 -0
  8. package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-command-utils/node-utils.js +15 -0
  9. package/dist/collection/components/text-editor/prosemirror-adapter/menu/menu-commands.js +81 -69
  10. package/dist/collection/components/text-editor/prosemirror-adapter/plugins/list-key-handler.js +44 -0
  11. package/dist/collection/components/text-editor/prosemirror-adapter/prosemirror-adapter.js +4 -3
  12. package/dist/esm/limel-markdown.entry.js +1 -1
  13. package/dist/esm/limel-prosemirror-adapter.entry.js +779 -396
  14. package/dist/esm/{markdown-parser-BSQKleVw.js → markdown-parser-DrxxGLF5.js} +36 -56
  15. package/dist/lime-elements/lime-elements.esm.js +1 -1
  16. package/dist/lime-elements/p-1f29f482.entry.js +1 -0
  17. package/dist/lime-elements/{p-3ea159fd.entry.js → p-38393fb4.entry.js} +1 -1
  18. package/dist/lime-elements/{p-B0qhUema.js → p-C9xHOCE_.js} +2 -2
  19. package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-command-utils/active-state-utils.d.ts +6 -0
  20. package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-command-utils/list-utils.d.ts +68 -0
  21. package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-command-utils/node-utils.d.ts +10 -0
  22. package/dist/types/components/text-editor/prosemirror-adapter/menu/menu-commands.d.ts +10 -0
  23. package/dist/types/components/text-editor/prosemirror-adapter/plugins/list-key-handler.d.ts +14 -0
  24. package/package.json +2 -2
  25. package/dist/lime-elements/p-845cfda7.entry.js +0 -1
@@ -1,47 +1,10 @@
1
1
  import { toggleMark, setBlockType, wrapIn, lift } from "prosemirror-commands";
2
- import { findWrapping, liftTarget } from "prosemirror-transform";
3
- import { TextSelection } from "prosemirror-state";
2
+ import { wrapInList, liftListItem } from "prosemirror-schema-list";
3
+ import { AllSelection, EditorState, TextSelection, } from "prosemirror-state";
4
4
  import { EditorMenuTypes, LevelMapping } from "./types";
5
5
  import { getLinkAttributes } from "../plugins/link/utils";
6
- const setActiveMethodForMark = (command, markType) => {
7
- command.active = (state) => {
8
- const { from, $from, to, empty } = state.selection;
9
- if (empty) {
10
- return !!markType.isInSet(state.storedMarks || $from.marks());
11
- }
12
- else {
13
- return state.doc.rangeHasMark(from, to, markType);
14
- }
15
- };
16
- };
17
- const setActiveMethodForNode = (command, nodeType, level) => {
18
- command.active = (state) => {
19
- const { $from } = state.selection;
20
- const node = $from.node($from.depth);
21
- if (node && node.type.name === nodeType.name) {
22
- if (nodeType.name === LevelMapping.Heading && level) {
23
- return node.attrs.level === level;
24
- }
25
- return true;
26
- }
27
- return false;
28
- };
29
- };
30
- const setActiveMethodForWrap = (command, nodeType) => {
31
- command.active = (state) => {
32
- const { from, to } = state.selection;
33
- for (let pos = from; pos <= to; pos++) {
34
- const resolvedPos = state.doc.resolve(pos);
35
- for (let i = resolvedPos.depth; i > 0; i--) {
36
- const node = resolvedPos.node(i);
37
- if (node && node.type.name === nodeType.name) {
38
- return true;
39
- }
40
- }
41
- }
42
- return false;
43
- };
44
- };
6
+ import { setActiveMethodForMark, setActiveMethodForNode, setActiveMethodForWrap, } from "./menu-command-utils/active-state-utils";
7
+ import { resolveListContext, convertInnermostList, joinAdjacentListsOnDispatch, selectionHasNonListableBlock, unifyToList, } from "./menu-command-utils/list-utils";
45
8
  const createInsertLinkCommand = (schema, _, link) => {
46
9
  const command = (state, dispatch) => {
47
10
  const { from, to } = state.selection;
@@ -101,11 +64,13 @@ const toggleNodeType = (schema, type, attrs = {}, shouldWrap = false) => {
101
64
  const paragraphType = schema.nodes.paragraph;
102
65
  return (state, dispatch) => {
103
66
  const { $from, $to } = state.selection;
104
- const hasActiveWrap = $from.node($from.depth - 1).type === nodeType;
105
67
  if (state.selection instanceof TextSelection &&
106
68
  // Ensure selection is within the same parent block
107
69
  // We don't want toggling block types across multiple blocks
108
70
  $from.sameParent($from.doc.resolve($to.pos))) {
71
+ // Resolved only under the TextSelection guard: an AllSelection
72
+ // resolves at depth 0, where there is no parent node to read.
73
+ const hasActiveWrap = $from.node($from.depth - 1).type === nodeType;
109
74
  if ($from.parent.type === nodeType) {
110
75
  if (dispatch) {
111
76
  dispatch(state.tr.setBlockType($from.pos, $to.pos, paragraphType));
@@ -162,40 +127,85 @@ const createWrapInCommand = (schema, nodeType) => {
162
127
  setActiveMethodForWrap(command, type);
163
128
  return command;
164
129
  };
165
- const toggleList = (listType) => {
166
- return (state, dispatch) => {
167
- const { $from, $to } = state.selection;
168
- const range = $from.blockRange($to);
169
- if (!range) {
130
+ // Select-all produces an AllSelection, whose endpoints resolve at the
131
+ // document level where list commands cannot operate. Re-anchoring it as
132
+ // a TextSelection over the same content lets the list ladder (and the
133
+ // delegated prosemirror-schema-list commands) treat select-all like any
134
+ // other full-content selection.
135
+ const withTextSelection = (state) => {
136
+ if (!(state.selection instanceof AllSelection)) {
137
+ return state;
138
+ }
139
+ const selection = TextSelection.between(state.doc.resolve(0), state.doc.resolve(state.doc.content.size));
140
+ // A plugin-free scratch state on the shared doc: only feed it
141
+ // commands driven by doc and selection.
142
+ return EditorState.create({
143
+ doc: state.doc,
144
+ selection: selection,
145
+ storedMarks: state.storedMarks,
146
+ });
147
+ };
148
+ /**
149
+ * Creates a command for toggling list types.
150
+ *
151
+ * @param schema - The ProseMirror schema.
152
+ * @param listTypeName - The name of the list type to toggle.
153
+ * @returns A command for toggling list types.
154
+ */
155
+ export const createListCommand = (schema, listTypeName) => {
156
+ const type = schema.nodes[listTypeName];
157
+ if (!type) {
158
+ throw new Error(`List type "${listTypeName}" not found in schema`);
159
+ }
160
+ const itemType = schema.nodes.list_item;
161
+ if (!itemType) {
162
+ throw new Error('Node type "list_item" not found in schema');
163
+ }
164
+ // The keymap invokes the command directly, so the command body applies
165
+ // the same applicability rules as `allowed` to keep keyboard and
166
+ // toolbar behavior identical.
167
+ const command = (state, dispatch) => {
168
+ state = withTextSelection(state);
169
+ if (!(state.selection instanceof TextSelection)) {
170
170
  return false;
171
171
  }
172
- const wrapping = range && findWrapping(range, listType);
173
- if (wrapping) {
174
- // Wrap the selection in a list
175
- if (dispatch) {
176
- dispatch(state.tr.wrap(range, wrapping).scrollIntoView());
177
- }
178
- return true;
172
+ const context = resolveListContext(state, type);
173
+ if (context.kind === 'same-type') {
174
+ return liftListItem(itemType)(state, dispatch);
179
175
  }
180
- else {
181
- // Check if we are in a list item and lift out of the list
182
- const liftRange = range && liftTarget(range);
183
- if (liftRange !== null) {
184
- if (dispatch) {
185
- dispatch(state.tr.lift(range, liftRange).scrollIntoView());
186
- }
187
- return true;
176
+ if (context.kind === 'other-type') {
177
+ return convertInnermostList(state, context.listDepth, type, dispatch);
178
+ }
179
+ if (context.kind === 'no-list') {
180
+ // For a single block the schema decides, through the wrap
181
+ // command itself; multi-block selections keep the stricter
182
+ // gate so unify cannot half-apply.
183
+ if (!context.singleBlock && selectionHasNonListableBlock(state)) {
184
+ return false;
188
185
  }
186
+ return wrapInList(type)(state, joinAdjacentListsOnDispatch(state, type, dispatch));
187
+ }
188
+ if (selectionHasNonListableBlock(state)) {
189
189
  return false;
190
190
  }
191
+ return unifyToList(state, type, dispatch);
192
+ };
193
+ command.allowed = (state) => {
194
+ state = withTextSelection(state);
195
+ if (!(state.selection instanceof TextSelection)) {
196
+ return false;
197
+ }
198
+ const context = resolveListContext(state, type);
199
+ // Inside a list, toggling or converting is always applicable, even
200
+ // when a non-listable ancestor wraps the list.
201
+ if (context.kind === 'same-type' || context.kind === 'other-type') {
202
+ return true;
203
+ }
204
+ if (context.kind === 'no-list' && context.singleBlock) {
205
+ return wrapInList(type)(state);
206
+ }
207
+ return !selectionHasNonListableBlock(state);
191
208
  };
192
- };
193
- const createListCommand = (schema, listType) => {
194
- const type = schema.nodes[listType];
195
- if (!type) {
196
- throw new Error(`List type "${listType}" not found in schema`);
197
- }
198
- const command = toggleList(type);
199
209
  setActiveMethodForWrap(command, type);
200
210
  return command;
201
211
  };
@@ -232,6 +242,8 @@ export class MenuCommandFactory {
232
242
  'Mod-Shift-1': this.getCommand(EditorMenuTypes.HeaderLevel1),
233
243
  'Mod-Shift-2': this.getCommand(EditorMenuTypes.HeaderLevel2),
234
244
  'Mod-Shift-3': this.getCommand(EditorMenuTypes.HeaderLevel3),
245
+ 'Mod-Shift-7': this.getCommand(EditorMenuTypes.OrderedList),
246
+ 'Mod-Shift-8': this.getCommand(EditorMenuTypes.BulletList),
235
247
  'Mod-Shift-X': this.getCommand(EditorMenuTypes.Strikethrough),
236
248
  'Mod-`': this.getCommand(EditorMenuTypes.Code),
237
249
  'Mod-Shift-C': this.getCommand(EditorMenuTypes.CodeBlock),
@@ -0,0 +1,44 @@
1
+ import { Plugin, PluginKey } from "prosemirror-state";
2
+ import { sinkListItem, liftListItem } from "prosemirror-schema-list";
3
+ import { findAncestorDepthOfType } from "../menu/menu-command-utils/node-utils";
4
+ export const listKeyHandlerPluginKey = new PluginKey('listKeyHandlerPlugin');
5
+ /**
6
+ * Creates a plugin for handling Tab and Shift+Tab inside list items:
7
+ * Tab indents the item and Shift+Tab outdents it. Enter and Backspace
8
+ * are handled by the base keymap (splitListItem and joinBackward), which
9
+ * runs before this plugin.
10
+ *
11
+ * @param schema - The document schema
12
+ * @returns A ProseMirror plugin for handling list-specific key events
13
+ */
14
+ export function createListKeyHandlerPlugin(schema) {
15
+ return new Plugin({
16
+ key: listKeyHandlerPluginKey,
17
+ props: {
18
+ handleKeyDown: (view, event) => {
19
+ if (event.key !== 'Tab') {
20
+ return false;
21
+ }
22
+ const { state } = view;
23
+ const { $from } = state.selection;
24
+ const inListItem = findAncestorDepthOfType($from, schema.nodes.list_item) !==
25
+ null;
26
+ if (!inListItem) {
27
+ return false;
28
+ }
29
+ // Inside a list item, Tab and Shift+Tab are always handled
30
+ // so focus never leaves the editor mid-list, even when the
31
+ // indent or outdent itself cannot apply.
32
+ event.preventDefault();
33
+ if (event.shiftKey) {
34
+ liftListItem(schema.nodes.list_item)(state, view.dispatch);
35
+ return true;
36
+ }
37
+ // Sinking fails on first items (no preceding sibling to
38
+ // become the parent); Tab is still swallowed.
39
+ sinkListItem(schema.nodes.list_item)(state, view.dispatch);
40
+ return true;
41
+ },
42
+ },
43
+ });
44
+ }
@@ -87,13 +87,14 @@ export class ProsemirrorAdapter {
87
87
  return newItem;
88
88
  };
89
89
  this.updateActiveActionBarItems = (activeTypes, allowedTypes) => {
90
- const newItems = getTextEditorMenuItems().map((item) => {
90
+ this.actionBarItems = getTextEditorMenuItems()
91
+ .map(this.getTranslatedItem)
92
+ .map((item) => {
91
93
  if (isItem(item)) {
92
- return Object.assign(Object.assign({}, item), { selected: activeTypes[item.value], allowed: allowedTypes[item.value] });
94
+ return Object.assign(Object.assign({}, item), { selected: activeTypes[item.value], disabled: !allowedTypes[item.value] });
93
95
  }
94
96
  return item;
95
97
  });
96
- this.actionBarItems = newItems.filter((item) => isItem(item) ? item.allowed : true);
97
98
  };
98
99
  this.handleTransaction = (transaction) => {
99
100
  this.transactionFired = true;
@@ -1,5 +1,5 @@
1
1
  import { r as registerInstance, h, H as Host } from './index-BGxJfR2f.js';
2
- import { m as markdownToHTML } from './markdown-parser-BSQKleVw.js';
2
+ import { m as markdownToHTML } from './markdown-parser-DrxxGLF5.js';
3
3
  import { g as globalConfig } from './config-Dnt5w_Bp.js';
4
4
  import { d as defaultSchema } from './index-CbciMfiU.js';
5
5
  import { a as adaptColorContrast } from './adapt-color-contrast-Dgcw_h7C.js';