@limetech/lime-elements 37.16.0 → 37.17.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.
@@ -3,6 +3,7 @@ import { EditorState } from 'prosemirror-state';
3
3
  import { EditorView } from 'prosemirror-view';
4
4
  import { Schema, DOMParser } from 'prosemirror-model';
5
5
  import { schema } from 'prosemirror-schema-basic';
6
+ import { addListNodes } from 'prosemirror-schema-list';
6
7
  import { exampleSetup } from 'prosemirror-example-setup';
7
8
  /**
8
9
  * This editor offers a rich text editing experience with markdown support,
@@ -27,7 +28,7 @@ export class TextEditor {
27
28
  }
28
29
  componentDidLoad() {
29
30
  const mySchema = new Schema({
30
- nodes: schema.spec.nodes,
31
+ nodes: addListNodes(schema.spec.nodes, 'paragraph block*', 'block'),
31
32
  marks: schema.spec.marks,
32
33
  });
33
34
  this.view = new EditorView(this.host.shadowRoot.querySelector('#editor'), {
@@ -1 +1 @@
1
- {"version":3,"file":"text-editor.js","sourceRoot":"","sources":["../../../src/components/text-editor/text-editor.tsx"],"names":[],"mappings":"AAAA,OAAO,EACH,SAAS,EACT,OAAO,EACP,KAAK,EAEL,KAAK,EACL,CAAC,GACJ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD;;;;;;;;;;;;GAYG;AAMH,MAAM,OAAO,UAAU;;;;EAaZ,iBAAiB,KAAI,CAAC;EAEtB,MAAM;IACT,OAAO,WAAK,EAAE,EAAC,QAAQ,GAAG,CAAC;EAC/B,CAAC;EAEM,gBAAgB;IACnB,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC;MACxB,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK;MACxB,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK;KAC3B,CAAC,CAAC;IAEH,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CACtB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,EAC7C;MACI,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC;QACtB,GAAG,EAAE,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,KAAK,CACrC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAChD;QACD,OAAO,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;OAC9C,CAAC;MACF,mBAAmB,EAAE,CAAC,WAAW,EAAE,EAAE;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACpD,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAEhC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;MACxD,CAAC;KACJ,CACJ,CAAC;EACN,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CACJ","sourcesContent":["import {\n Component,\n Element,\n Event,\n EventEmitter,\n State,\n h,\n} from '@stencil/core';\nimport { EditorState } from 'prosemirror-state';\nimport { EditorView } from 'prosemirror-view';\nimport { Schema, DOMParser } from 'prosemirror-model';\nimport { schema } from 'prosemirror-schema-basic';\nimport { exampleSetup } from 'prosemirror-example-setup';\n\n/**\n * This editor offers a rich text editing experience with markdown support,\n * in the sense that you can easily type markdown syntax and see the rendered\n * result as rich text in real-time. For instance, you can type `# Hello, world!`\n * and see it directly turning to a heading 1 (an `<h1>` HTML element).\n *\n * Naturally, you can use standard keyboard hotkeys such as <kbd>Ctrl</kbd> + <kbd>B</kbd>\n * to toggle bold text, <kbd>Ctrl</kbd> + <kbd>I</kbd> to toggle italic text, and so on.\n *\n * @exampleComponent limel-example-text-editor-basic\n * @beta\n * @private\n */\n@Component({\n tag: 'limel-text-editor',\n shadow: true,\n styleUrl: 'text-editor.scss',\n})\nexport class TextEditor {\n @Element()\n private host: HTMLLimelTextEditorElement;\n\n @State()\n private view: EditorView;\n\n /**\n * Dispatched when a change is made to the editor\n */\n @Event()\n private change: EventEmitter<{ html: string }>;\n\n public componentWillLoad() {}\n\n public render() {\n return <div id=\"editor\" />;\n }\n\n public componentDidLoad() {\n const mySchema = new Schema({\n nodes: schema.spec.nodes,\n marks: schema.spec.marks,\n });\n\n this.view = new EditorView(\n this.host.shadowRoot.querySelector('#editor'),\n {\n state: EditorState.create({\n doc: DOMParser.fromSchema(mySchema).parse(\n this.host.shadowRoot.querySelector('#editor'),\n ),\n plugins: exampleSetup({ schema: mySchema }),\n }),\n dispatchTransaction: (transaction) => {\n const newState = this.view.state.apply(transaction);\n this.view.updateState(newState);\n\n this.change.emit({ html: this.view.dom.innerHTML });\n },\n },\n );\n }\n}\n"]}
1
+ {"version":3,"file":"text-editor.js","sourceRoot":"","sources":["../../../src/components/text-editor/text-editor.tsx"],"names":[],"mappings":"AAAA,OAAO,EACH,SAAS,EACT,OAAO,EACP,KAAK,EAEL,KAAK,EACL,CAAC,GACJ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD;;;;;;;;;;;;GAYG;AAMH,MAAM,OAAO,UAAU;;;;EAaZ,iBAAiB,KAAI,CAAC;EAEtB,MAAM;IACT,OAAO,WAAK,EAAE,EAAC,QAAQ,GAAG,CAAC;EAC/B,CAAC;EAEM,gBAAgB;IACnB,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC;MACxB,KAAK,EAAE,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,kBAAkB,EAAE,OAAO,CAAC;MACnE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK;KAC3B,CAAC,CAAC;IAEH,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CACtB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,EAC7C;MACI,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC;QACtB,GAAG,EAAE,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,KAAK,CACrC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAChD;QACD,OAAO,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;OAC9C,CAAC;MACF,mBAAmB,EAAE,CAAC,WAAW,EAAE,EAAE;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACpD,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAEhC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;MACxD,CAAC;KACJ,CACJ,CAAC;EACN,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CACJ","sourcesContent":["import {\n Component,\n Element,\n Event,\n EventEmitter,\n State,\n h,\n} from '@stencil/core';\nimport { EditorState } from 'prosemirror-state';\nimport { EditorView } from 'prosemirror-view';\nimport { Schema, DOMParser } from 'prosemirror-model';\nimport { schema } from 'prosemirror-schema-basic';\nimport { addListNodes } from 'prosemirror-schema-list';\nimport { exampleSetup } from 'prosemirror-example-setup';\n\n/**\n * This editor offers a rich text editing experience with markdown support,\n * in the sense that you can easily type markdown syntax and see the rendered\n * result as rich text in real-time. For instance, you can type `# Hello, world!`\n * and see it directly turning to a heading 1 (an `<h1>` HTML element).\n *\n * Naturally, you can use standard keyboard hotkeys such as <kbd>Ctrl</kbd> + <kbd>B</kbd>\n * to toggle bold text, <kbd>Ctrl</kbd> + <kbd>I</kbd> to toggle italic text, and so on.\n *\n * @exampleComponent limel-example-text-editor-basic\n * @beta\n * @private\n */\n@Component({\n tag: 'limel-text-editor',\n shadow: true,\n styleUrl: 'text-editor.scss',\n})\nexport class TextEditor {\n @Element()\n private host: HTMLLimelTextEditorElement;\n\n @State()\n private view: EditorView;\n\n /**\n * Dispatched when a change is made to the editor\n */\n @Event()\n private change: EventEmitter<{ html: string }>;\n\n public componentWillLoad() {}\n\n public render() {\n return <div id=\"editor\" />;\n }\n\n public componentDidLoad() {\n const mySchema = new Schema({\n nodes: addListNodes(schema.spec.nodes, 'paragraph block*', 'block'),\n marks: schema.spec.marks,\n });\n\n this.view = new EditorView(\n this.host.shadowRoot.querySelector('#editor'),\n {\n state: EditorState.create({\n doc: DOMParser.fromSchema(mySchema).parse(\n this.host.shadowRoot.querySelector('#editor'),\n ),\n plugins: exampleSetup({ schema: mySchema }),\n }),\n dispatchTransaction: (transaction) => {\n const newState = this.view.state.apply(transaction);\n this.view.updateState(newState);\n\n this.change.emit({ html: this.view.dom.innerHTML });\n },\n },\n );\n }\n}\n"]}
@@ -12402,6 +12402,259 @@ To reuse elements from this schema, extend or read from its
12402
12402
  */
12403
12403
  const schema = new Schema({ nodes, marks });
12404
12404
 
12405
+ const olDOM = ["ol", 0], ulDOM = ["ul", 0], liDOM = ["li", 0];
12406
+ /**
12407
+ An ordered list [node spec](https://prosemirror.net/docs/ref/#model.NodeSpec). Has a single
12408
+ attribute, `order`, which determines the number at which the list
12409
+ starts counting, and defaults to 1. Represented as an `<ol>`
12410
+ element.
12411
+ */
12412
+ const orderedList = {
12413
+ attrs: { order: { default: 1 } },
12414
+ parseDOM: [{ tag: "ol", getAttrs(dom) {
12415
+ return { order: dom.hasAttribute("start") ? +dom.getAttribute("start") : 1 };
12416
+ } }],
12417
+ toDOM(node) {
12418
+ return node.attrs.order == 1 ? olDOM : ["ol", { start: node.attrs.order }, 0];
12419
+ }
12420
+ };
12421
+ /**
12422
+ A bullet list node spec, represented in the DOM as `<ul>`.
12423
+ */
12424
+ const bulletList = {
12425
+ parseDOM: [{ tag: "ul" }],
12426
+ toDOM() { return ulDOM; }
12427
+ };
12428
+ /**
12429
+ A list item (`<li>`) spec.
12430
+ */
12431
+ const listItem = {
12432
+ parseDOM: [{ tag: "li" }],
12433
+ toDOM() { return liDOM; },
12434
+ defining: true
12435
+ };
12436
+ function add$1(obj, props) {
12437
+ let copy = {};
12438
+ for (let prop in obj)
12439
+ copy[prop] = obj[prop];
12440
+ for (let prop in props)
12441
+ copy[prop] = props[prop];
12442
+ return copy;
12443
+ }
12444
+ /**
12445
+ Convenience function for adding list-related node types to a map
12446
+ specifying the nodes for a schema. Adds
12447
+ [`orderedList`](https://prosemirror.net/docs/ref/#schema-list.orderedList) as `"ordered_list"`,
12448
+ [`bulletList`](https://prosemirror.net/docs/ref/#schema-list.bulletList) as `"bullet_list"`, and
12449
+ [`listItem`](https://prosemirror.net/docs/ref/#schema-list.listItem) as `"list_item"`.
12450
+
12451
+ `itemContent` determines the content expression for the list items.
12452
+ If you want the commands defined in this module to apply to your
12453
+ list structure, it should have a shape like `"paragraph block*"` or
12454
+ `"paragraph (ordered_list | bullet_list)*"`. `listGroup` can be
12455
+ given to assign a group name to the list node types, for example
12456
+ `"block"`.
12457
+ */
12458
+ function addListNodes(nodes, itemContent, listGroup) {
12459
+ return nodes.append({
12460
+ ordered_list: add$1(orderedList, { content: "list_item+", group: listGroup }),
12461
+ bullet_list: add$1(bulletList, { content: "list_item+", group: listGroup }),
12462
+ list_item: add$1(listItem, { content: itemContent })
12463
+ });
12464
+ }
12465
+ /**
12466
+ Returns a command function that wraps the selection in a list with
12467
+ the given type an attributes. If `dispatch` is null, only return a
12468
+ value to indicate whether this is possible, but don't actually
12469
+ perform the change.
12470
+ */
12471
+ function wrapInList(listType, attrs = null) {
12472
+ return function (state, dispatch) {
12473
+ let { $from, $to } = state.selection;
12474
+ let range = $from.blockRange($to), doJoin = false, outerRange = range;
12475
+ if (!range)
12476
+ return false;
12477
+ // This is at the top of an existing list item
12478
+ if (range.depth >= 2 && $from.node(range.depth - 1).type.compatibleContent(listType) && range.startIndex == 0) {
12479
+ // Don't do anything if this is the top of the list
12480
+ if ($from.index(range.depth - 1) == 0)
12481
+ return false;
12482
+ let $insert = state.doc.resolve(range.start - 2);
12483
+ outerRange = new NodeRange($insert, $insert, range.depth);
12484
+ if (range.endIndex < range.parent.childCount)
12485
+ range = new NodeRange($from, state.doc.resolve($to.end(range.depth)), range.depth);
12486
+ doJoin = true;
12487
+ }
12488
+ let wrap = findWrapping(outerRange, listType, attrs, range);
12489
+ if (!wrap)
12490
+ return false;
12491
+ if (dispatch)
12492
+ dispatch(doWrapInList(state.tr, range, wrap, doJoin, listType).scrollIntoView());
12493
+ return true;
12494
+ };
12495
+ }
12496
+ function doWrapInList(tr, range, wrappers, joinBefore, listType) {
12497
+ let content = Fragment.empty;
12498
+ for (let i = wrappers.length - 1; i >= 0; i--)
12499
+ content = Fragment.from(wrappers[i].type.create(wrappers[i].attrs, content));
12500
+ tr.step(new ReplaceAroundStep(range.start - (joinBefore ? 2 : 0), range.end, range.start, range.end, new Slice(content, 0, 0), wrappers.length, true));
12501
+ let found = 0;
12502
+ for (let i = 0; i < wrappers.length; i++)
12503
+ if (wrappers[i].type == listType)
12504
+ found = i + 1;
12505
+ let splitDepth = wrappers.length - found;
12506
+ let splitPos = range.start + wrappers.length - (joinBefore ? 2 : 0), parent = range.parent;
12507
+ for (let i = range.startIndex, e = range.endIndex, first = true; i < e; i++, first = false) {
12508
+ if (!first && canSplit(tr.doc, splitPos, splitDepth)) {
12509
+ tr.split(splitPos, splitDepth);
12510
+ splitPos += 2 * splitDepth;
12511
+ }
12512
+ splitPos += parent.child(i).nodeSize;
12513
+ }
12514
+ return tr;
12515
+ }
12516
+ /**
12517
+ Build a command that splits a non-empty textblock at the top level
12518
+ of a list item by also splitting that list item.
12519
+ */
12520
+ function splitListItem(itemType, itemAttrs) {
12521
+ return function (state, dispatch) {
12522
+ let { $from, $to, node } = state.selection;
12523
+ if ((node && node.isBlock) || $from.depth < 2 || !$from.sameParent($to))
12524
+ return false;
12525
+ let grandParent = $from.node(-1);
12526
+ if (grandParent.type != itemType)
12527
+ return false;
12528
+ if ($from.parent.content.size == 0 && $from.node(-1).childCount == $from.indexAfter(-1)) {
12529
+ // In an empty block. If this is a nested list, the wrapping
12530
+ // list item should be split. Otherwise, bail out and let next
12531
+ // command handle lifting.
12532
+ if ($from.depth == 3 || $from.node(-3).type != itemType ||
12533
+ $from.index(-2) != $from.node(-2).childCount - 1)
12534
+ return false;
12535
+ if (dispatch) {
12536
+ let wrap = Fragment.empty;
12537
+ let depthBefore = $from.index(-1) ? 1 : $from.index(-2) ? 2 : 3;
12538
+ // Build a fragment containing empty versions of the structure
12539
+ // from the outer list item to the parent node of the cursor
12540
+ for (let d = $from.depth - depthBefore; d >= $from.depth - 3; d--)
12541
+ wrap = Fragment.from($from.node(d).copy(wrap));
12542
+ let depthAfter = $from.indexAfter(-1) < $from.node(-2).childCount ? 1
12543
+ : $from.indexAfter(-2) < $from.node(-3).childCount ? 2 : 3;
12544
+ // Add a second list item with an empty default start node
12545
+ wrap = wrap.append(Fragment.from(itemType.createAndFill()));
12546
+ let start = $from.before($from.depth - (depthBefore - 1));
12547
+ let tr = state.tr.replace(start, $from.after(-depthAfter), new Slice(wrap, 4 - depthBefore, 0));
12548
+ let sel = -1;
12549
+ tr.doc.nodesBetween(start, tr.doc.content.size, (node, pos) => {
12550
+ if (sel > -1)
12551
+ return false;
12552
+ if (node.isTextblock && node.content.size == 0)
12553
+ sel = pos + 1;
12554
+ });
12555
+ if (sel > -1)
12556
+ tr.setSelection(Selection.near(tr.doc.resolve(sel)));
12557
+ dispatch(tr.scrollIntoView());
12558
+ }
12559
+ return true;
12560
+ }
12561
+ let nextType = $to.pos == $from.end() ? grandParent.contentMatchAt(0).defaultType : null;
12562
+ let tr = state.tr.delete($from.pos, $to.pos);
12563
+ let types = nextType ? [itemAttrs ? { type: itemType, attrs: itemAttrs } : null, { type: nextType }] : undefined;
12564
+ if (!canSplit(tr.doc, $from.pos, 2, types))
12565
+ return false;
12566
+ if (dispatch)
12567
+ dispatch(tr.split($from.pos, 2, types).scrollIntoView());
12568
+ return true;
12569
+ };
12570
+ }
12571
+ /**
12572
+ Create a command to lift the list item around the selection up into
12573
+ a wrapping list.
12574
+ */
12575
+ function liftListItem(itemType) {
12576
+ return function (state, dispatch) {
12577
+ let { $from, $to } = state.selection;
12578
+ let range = $from.blockRange($to, node => node.childCount > 0 && node.firstChild.type == itemType);
12579
+ if (!range)
12580
+ return false;
12581
+ if (!dispatch)
12582
+ return true;
12583
+ if ($from.node(range.depth - 1).type == itemType) // Inside a parent list
12584
+ return liftToOuterList(state, dispatch, itemType, range);
12585
+ else // Outer list node
12586
+ return liftOutOfList(state, dispatch, range);
12587
+ };
12588
+ }
12589
+ function liftToOuterList(state, dispatch, itemType, range) {
12590
+ let tr = state.tr, end = range.end, endOfList = range.$to.end(range.depth);
12591
+ if (end < endOfList) {
12592
+ // There are siblings after the lifted items, which must become
12593
+ // children of the last item
12594
+ tr.step(new ReplaceAroundStep(end - 1, endOfList, end, endOfList, new Slice(Fragment.from(itemType.create(null, range.parent.copy())), 1, 0), 1, true));
12595
+ range = new NodeRange(tr.doc.resolve(range.$from.pos), tr.doc.resolve(endOfList), range.depth);
12596
+ }
12597
+ const target = liftTarget(range);
12598
+ if (target == null)
12599
+ return false;
12600
+ tr.lift(range, target);
12601
+ let after = tr.mapping.map(end, -1) - 1;
12602
+ if (canJoin(tr.doc, after))
12603
+ tr.join(after);
12604
+ dispatch(tr.scrollIntoView());
12605
+ return true;
12606
+ }
12607
+ function liftOutOfList(state, dispatch, range) {
12608
+ let tr = state.tr, list = range.parent;
12609
+ // Merge the list items into a single big item
12610
+ for (let pos = range.end, i = range.endIndex - 1, e = range.startIndex; i > e; i--) {
12611
+ pos -= list.child(i).nodeSize;
12612
+ tr.delete(pos - 1, pos + 1);
12613
+ }
12614
+ let $start = tr.doc.resolve(range.start), item = $start.nodeAfter;
12615
+ if (tr.mapping.map(range.end) != range.start + $start.nodeAfter.nodeSize)
12616
+ return false;
12617
+ let atStart = range.startIndex == 0, atEnd = range.endIndex == list.childCount;
12618
+ let parent = $start.node(-1), indexBefore = $start.index(-1);
12619
+ if (!parent.canReplace(indexBefore + (atStart ? 0 : 1), indexBefore + 1, item.content.append(atEnd ? Fragment.empty : Fragment.from(list))))
12620
+ return false;
12621
+ let start = $start.pos, end = start + item.nodeSize;
12622
+ // Strip off the surrounding list. At the sides where we're not at
12623
+ // the end of the list, the existing list is closed. At sides where
12624
+ // this is the end, it is overwritten to its end.
12625
+ tr.step(new ReplaceAroundStep(start - (atStart ? 1 : 0), end + (atEnd ? 1 : 0), start + 1, end - 1, new Slice((atStart ? Fragment.empty : Fragment.from(list.copy(Fragment.empty)))
12626
+ .append(atEnd ? Fragment.empty : Fragment.from(list.copy(Fragment.empty))), atStart ? 0 : 1, atEnd ? 0 : 1), atStart ? 0 : 1));
12627
+ dispatch(tr.scrollIntoView());
12628
+ return true;
12629
+ }
12630
+ /**
12631
+ Create a command to sink the list item around the selection down
12632
+ into an inner list.
12633
+ */
12634
+ function sinkListItem(itemType) {
12635
+ return function (state, dispatch) {
12636
+ let { $from, $to } = state.selection;
12637
+ let range = $from.blockRange($to, node => node.childCount > 0 && node.firstChild.type == itemType);
12638
+ if (!range)
12639
+ return false;
12640
+ let startIndex = range.startIndex;
12641
+ if (startIndex == 0)
12642
+ return false;
12643
+ let parent = range.parent, nodeBefore = parent.child(startIndex - 1);
12644
+ if (nodeBefore.type != itemType)
12645
+ return false;
12646
+ if (dispatch) {
12647
+ let nestedBefore = nodeBefore.lastChild && nodeBefore.lastChild.type == parent.type;
12648
+ let inner = Fragment.from(nestedBefore ? itemType.create() : null);
12649
+ let slice = new Slice(Fragment.from(itemType.create(null, Fragment.from(parent.type.create(null, inner)))), nestedBefore ? 3 : 1, 0);
12650
+ let before = range.start, after = range.end;
12651
+ dispatch(state.tr.step(new ReplaceAroundStep(before - (nestedBefore ? 3 : 1), after, before, after, slice, 1, true))
12652
+ .scrollIntoView());
12653
+ }
12654
+ return true;
12655
+ };
12656
+ }
12657
+
12405
12658
  var base = {
12406
12659
  8: "Backspace",
12407
12660
  9: "Tab",
@@ -14921,199 +15174,6 @@ function getAllWrapping(node) {
14921
15174
  return res;
14922
15175
  }
14923
15176
 
14924
- /**
14925
- Returns a command function that wraps the selection in a list with
14926
- the given type an attributes. If `dispatch` is null, only return a
14927
- value to indicate whether this is possible, but don't actually
14928
- perform the change.
14929
- */
14930
- function wrapInList(listType, attrs = null) {
14931
- return function (state, dispatch) {
14932
- let { $from, $to } = state.selection;
14933
- let range = $from.blockRange($to), doJoin = false, outerRange = range;
14934
- if (!range)
14935
- return false;
14936
- // This is at the top of an existing list item
14937
- if (range.depth >= 2 && $from.node(range.depth - 1).type.compatibleContent(listType) && range.startIndex == 0) {
14938
- // Don't do anything if this is the top of the list
14939
- if ($from.index(range.depth - 1) == 0)
14940
- return false;
14941
- let $insert = state.doc.resolve(range.start - 2);
14942
- outerRange = new NodeRange($insert, $insert, range.depth);
14943
- if (range.endIndex < range.parent.childCount)
14944
- range = new NodeRange($from, state.doc.resolve($to.end(range.depth)), range.depth);
14945
- doJoin = true;
14946
- }
14947
- let wrap = findWrapping(outerRange, listType, attrs, range);
14948
- if (!wrap)
14949
- return false;
14950
- if (dispatch)
14951
- dispatch(doWrapInList(state.tr, range, wrap, doJoin, listType).scrollIntoView());
14952
- return true;
14953
- };
14954
- }
14955
- function doWrapInList(tr, range, wrappers, joinBefore, listType) {
14956
- let content = Fragment.empty;
14957
- for (let i = wrappers.length - 1; i >= 0; i--)
14958
- content = Fragment.from(wrappers[i].type.create(wrappers[i].attrs, content));
14959
- tr.step(new ReplaceAroundStep(range.start - (joinBefore ? 2 : 0), range.end, range.start, range.end, new Slice(content, 0, 0), wrappers.length, true));
14960
- let found = 0;
14961
- for (let i = 0; i < wrappers.length; i++)
14962
- if (wrappers[i].type == listType)
14963
- found = i + 1;
14964
- let splitDepth = wrappers.length - found;
14965
- let splitPos = range.start + wrappers.length - (joinBefore ? 2 : 0), parent = range.parent;
14966
- for (let i = range.startIndex, e = range.endIndex, first = true; i < e; i++, first = false) {
14967
- if (!first && canSplit(tr.doc, splitPos, splitDepth)) {
14968
- tr.split(splitPos, splitDepth);
14969
- splitPos += 2 * splitDepth;
14970
- }
14971
- splitPos += parent.child(i).nodeSize;
14972
- }
14973
- return tr;
14974
- }
14975
- /**
14976
- Build a command that splits a non-empty textblock at the top level
14977
- of a list item by also splitting that list item.
14978
- */
14979
- function splitListItem(itemType, itemAttrs) {
14980
- return function (state, dispatch) {
14981
- let { $from, $to, node } = state.selection;
14982
- if ((node && node.isBlock) || $from.depth < 2 || !$from.sameParent($to))
14983
- return false;
14984
- let grandParent = $from.node(-1);
14985
- if (grandParent.type != itemType)
14986
- return false;
14987
- if ($from.parent.content.size == 0 && $from.node(-1).childCount == $from.indexAfter(-1)) {
14988
- // In an empty block. If this is a nested list, the wrapping
14989
- // list item should be split. Otherwise, bail out and let next
14990
- // command handle lifting.
14991
- if ($from.depth == 3 || $from.node(-3).type != itemType ||
14992
- $from.index(-2) != $from.node(-2).childCount - 1)
14993
- return false;
14994
- if (dispatch) {
14995
- let wrap = Fragment.empty;
14996
- let depthBefore = $from.index(-1) ? 1 : $from.index(-2) ? 2 : 3;
14997
- // Build a fragment containing empty versions of the structure
14998
- // from the outer list item to the parent node of the cursor
14999
- for (let d = $from.depth - depthBefore; d >= $from.depth - 3; d--)
15000
- wrap = Fragment.from($from.node(d).copy(wrap));
15001
- let depthAfter = $from.indexAfter(-1) < $from.node(-2).childCount ? 1
15002
- : $from.indexAfter(-2) < $from.node(-3).childCount ? 2 : 3;
15003
- // Add a second list item with an empty default start node
15004
- wrap = wrap.append(Fragment.from(itemType.createAndFill()));
15005
- let start = $from.before($from.depth - (depthBefore - 1));
15006
- let tr = state.tr.replace(start, $from.after(-depthAfter), new Slice(wrap, 4 - depthBefore, 0));
15007
- let sel = -1;
15008
- tr.doc.nodesBetween(start, tr.doc.content.size, (node, pos) => {
15009
- if (sel > -1)
15010
- return false;
15011
- if (node.isTextblock && node.content.size == 0)
15012
- sel = pos + 1;
15013
- });
15014
- if (sel > -1)
15015
- tr.setSelection(Selection.near(tr.doc.resolve(sel)));
15016
- dispatch(tr.scrollIntoView());
15017
- }
15018
- return true;
15019
- }
15020
- let nextType = $to.pos == $from.end() ? grandParent.contentMatchAt(0).defaultType : null;
15021
- let tr = state.tr.delete($from.pos, $to.pos);
15022
- let types = nextType ? [itemAttrs ? { type: itemType, attrs: itemAttrs } : null, { type: nextType }] : undefined;
15023
- if (!canSplit(tr.doc, $from.pos, 2, types))
15024
- return false;
15025
- if (dispatch)
15026
- dispatch(tr.split($from.pos, 2, types).scrollIntoView());
15027
- return true;
15028
- };
15029
- }
15030
- /**
15031
- Create a command to lift the list item around the selection up into
15032
- a wrapping list.
15033
- */
15034
- function liftListItem(itemType) {
15035
- return function (state, dispatch) {
15036
- let { $from, $to } = state.selection;
15037
- let range = $from.blockRange($to, node => node.childCount > 0 && node.firstChild.type == itemType);
15038
- if (!range)
15039
- return false;
15040
- if (!dispatch)
15041
- return true;
15042
- if ($from.node(range.depth - 1).type == itemType) // Inside a parent list
15043
- return liftToOuterList(state, dispatch, itemType, range);
15044
- else // Outer list node
15045
- return liftOutOfList(state, dispatch, range);
15046
- };
15047
- }
15048
- function liftToOuterList(state, dispatch, itemType, range) {
15049
- let tr = state.tr, end = range.end, endOfList = range.$to.end(range.depth);
15050
- if (end < endOfList) {
15051
- // There are siblings after the lifted items, which must become
15052
- // children of the last item
15053
- tr.step(new ReplaceAroundStep(end - 1, endOfList, end, endOfList, new Slice(Fragment.from(itemType.create(null, range.parent.copy())), 1, 0), 1, true));
15054
- range = new NodeRange(tr.doc.resolve(range.$from.pos), tr.doc.resolve(endOfList), range.depth);
15055
- }
15056
- const target = liftTarget(range);
15057
- if (target == null)
15058
- return false;
15059
- tr.lift(range, target);
15060
- let after = tr.mapping.map(end, -1) - 1;
15061
- if (canJoin(tr.doc, after))
15062
- tr.join(after);
15063
- dispatch(tr.scrollIntoView());
15064
- return true;
15065
- }
15066
- function liftOutOfList(state, dispatch, range) {
15067
- let tr = state.tr, list = range.parent;
15068
- // Merge the list items into a single big item
15069
- for (let pos = range.end, i = range.endIndex - 1, e = range.startIndex; i > e; i--) {
15070
- pos -= list.child(i).nodeSize;
15071
- tr.delete(pos - 1, pos + 1);
15072
- }
15073
- let $start = tr.doc.resolve(range.start), item = $start.nodeAfter;
15074
- if (tr.mapping.map(range.end) != range.start + $start.nodeAfter.nodeSize)
15075
- return false;
15076
- let atStart = range.startIndex == 0, atEnd = range.endIndex == list.childCount;
15077
- let parent = $start.node(-1), indexBefore = $start.index(-1);
15078
- if (!parent.canReplace(indexBefore + (atStart ? 0 : 1), indexBefore + 1, item.content.append(atEnd ? Fragment.empty : Fragment.from(list))))
15079
- return false;
15080
- let start = $start.pos, end = start + item.nodeSize;
15081
- // Strip off the surrounding list. At the sides where we're not at
15082
- // the end of the list, the existing list is closed. At sides where
15083
- // this is the end, it is overwritten to its end.
15084
- tr.step(new ReplaceAroundStep(start - (atStart ? 1 : 0), end + (atEnd ? 1 : 0), start + 1, end - 1, new Slice((atStart ? Fragment.empty : Fragment.from(list.copy(Fragment.empty)))
15085
- .append(atEnd ? Fragment.empty : Fragment.from(list.copy(Fragment.empty))), atStart ? 0 : 1, atEnd ? 0 : 1), atStart ? 0 : 1));
15086
- dispatch(tr.scrollIntoView());
15087
- return true;
15088
- }
15089
- /**
15090
- Create a command to sink the list item around the selection down
15091
- into an inner list.
15092
- */
15093
- function sinkListItem(itemType) {
15094
- return function (state, dispatch) {
15095
- let { $from, $to } = state.selection;
15096
- let range = $from.blockRange($to, node => node.childCount > 0 && node.firstChild.type == itemType);
15097
- if (!range)
15098
- return false;
15099
- let startIndex = range.startIndex;
15100
- if (startIndex == 0)
15101
- return false;
15102
- let parent = range.parent, nodeBefore = parent.child(startIndex - 1);
15103
- if (nodeBefore.type != itemType)
15104
- return false;
15105
- if (dispatch) {
15106
- let nestedBefore = nodeBefore.lastChild && nodeBefore.lastChild.type == parent.type;
15107
- let inner = Fragment.from(nestedBefore ? itemType.create() : null);
15108
- let slice = new Slice(Fragment.from(itemType.create(null, Fragment.from(parent.type.create(null, inner)))), nestedBefore ? 3 : 1, 0);
15109
- let before = range.start, after = range.end;
15110
- dispatch(state.tr.step(new ReplaceAroundStep(before - (nestedBefore ? 3 : 1), after, before, after, slice, 1, true))
15111
- .scrollIntoView());
15112
- }
15113
- return true;
15114
- };
15115
- }
15116
-
15117
15177
  /**
15118
15178
  Input rules are regular expressions describing a piece of text
15119
15179
  that, when typed, causes something to happen. This might be
@@ -15859,7 +15919,7 @@ const TextEditor = class {
15859
15919
  }
15860
15920
  componentDidLoad() {
15861
15921
  const mySchema = new Schema({
15862
- nodes: schema.spec.nodes,
15922
+ nodes: addListNodes(schema.spec.nodes, 'paragraph block*', 'block'),
15863
15923
  marks: schema.spec.marks,
15864
15924
  });
15865
15925
  this.view = new EditorView(this.host.shadowRoot.querySelector('#editor'), {