New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@bangle.dev/core

Package Overview
Dependencies
Maintainers
1
Versions
143
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bangle.dev/core - npm Package Compare versions

Comparing version 0.3.0 to 0.3.1

533

components/__tests__/todo-item.test.js

@@ -11,2 +11,3 @@ /**

} from '../../test-helpers/index';
import { smartNodesBetween } from '../bullet-list';
import { listItem } from '../index';

@@ -198,4 +199,3 @@

// TODO make it more intuitive
it('when calling toggleTodo on bulletList it converts to paragraph', async () => {
it('nested todo list to plain li', async () => {
const { editorView } = await testEditor(

@@ -223,15 +223,2 @@ <doc>

<para>first</para>
</li>
</ul>
<para>[]second</para>
</doc>,
);
});
it.skip('Toggles nested ordered list to todo item', async () => {
const { editorView } = await testEditor(
<doc>
<ul>
<li todoChecked={false}>
<para>first</para>
<ul>

@@ -246,22 +233,449 @@ <li>

);
});
});
sendKeyToPm(editorView, 'Ctrl-Shift-7');
test.each([
[
'plain list',
<doc>
<ul>
<li>
<para>[] first</para>
</li>
</ul>
</doc>,
<doc>
<ul>
<li todoChecked={false}>
<para>[] first</para>
</li>
</ul>
</doc>,
],
expect(editorView.state.doc).toEqualDocument(
<doc>
<ul>
<li todoChecked={false}>
<para>first</para>
<ul>
<li todoChecked={false}>
<para>[]second</para>
</li>
</ul>
</li>
</ul>
</doc>,
);
});
[
'plain todo list ',
<doc>
<ul>
<li todoChecked={false}>
<para>[] first</para>
</li>
</ul>
</doc>,
<doc>
<para>[] first</para>
</doc>,
],
[
'plain nested list',
<doc>
<ul>
<li todoChecked={false}>
<para>first</para>
<ul>
<li>
<para>[]second</para>
</li>
</ul>
</li>
</ul>
</doc>,
<doc>
<ul>
<li todoChecked={false}>
<para>first</para>
<ul>
<li todoChecked={false}>
<para>[]second</para>
</li>
</ul>
</li>
</ul>
</doc>,
],
[
'plain nested list 2',
<doc>
<ul>
<li todoChecked={false}>
<para>first</para>
<ul>
<li>
<para>mango</para>
</li>
<li>
<para>[]second</para>
</li>
</ul>
</li>
</ul>
</doc>,
<doc>
<ul>
<li todoChecked={false}>
<para>first</para>
<ul>
<li todoChecked={false}>
<para>mango</para>
</li>
<li todoChecked={false}>
<para>[]second</para>
</li>
</ul>
</li>
</ul>
</doc>,
],
[
'Single todo item with many vanilla lists',
<doc>
<ul>
<li>
<para>first</para>
<ul>
<li todoChecked={true}>
<para>alpha</para>
</li>
<li>
<para>[]mango</para>
</li>
<li>
<para>charlie</para>
</li>
<li>
<para>tango</para>
</li>
</ul>
</li>
</ul>
</doc>,
<doc>
<ul>
<li>
<para>first</para>
<ul>
<li todoChecked={true}>
<para>[]alpha</para>
</li>
<li todoChecked={false}>
<para>mango</para>
</li>
<li todoChecked={false}>
<para>charlie</para>
</li>
<li todoChecked={false}>
<para>tango</para>
</li>
</ul>
</li>
</ul>
</doc>,
],
[
'toggling parent doesnt affect children',
<doc>
<ul>
<li>
<para>first[]</para>
<ul>
<li>
<para>alpha</para>
</li>
<li>
<para>mango</para>
</li>
</ul>
</li>
<li>
<para>distant</para>
</li>
</ul>
</doc>,
<doc>
<ul>
<li todoChecked={false}>
<para>first[]</para>
<ul>
<li>
<para>alpha</para>
</li>
<li>
<para>mango</para>
</li>
</ul>
</li>
<li todoChecked={false}>
<para>distant</para>
</li>
</ul>
</doc>,
],
[
'todo item',
<doc>
<ul>
<li todoChecked={false}>
<para>[]first</para>
<ul>
<li todoChecked={false}>
<para>alpha</para>
</li>
<li todoChecked={false}>
<para>mango</para>
</li>
</ul>
</li>
<li todoChecked={false}>
<para>distant</para>
</li>
</ul>
</doc>,
<doc>
<para>first[]</para>
<ul>
<li todoChecked={false}>
<para>alpha</para>
<ul>
<li todoChecked={false}>
<para>mango</para>
</li>
</ul>
</li>
<li todoChecked={false}>
<para>distant</para>
</li>
</ul>
</doc>,
],
[
'nested todo item',
<doc>
<ul>
<li todoChecked={false}>
<para>first</para>
<ul>
<li todoChecked={false}>
<para>[]alpha</para>
</li>
<li todoChecked={false}>
<para>mango</para>
</li>
</ul>
</li>
<li todoChecked={false}>
<para>distant</para>
</li>
</ul>
</doc>,
<doc>
<ul>
<li todoChecked={false}>
<para>first</para>
</li>
</ul>
<para>alpha[]</para>
<ul>
<li todoChecked={false}>
<para>mango</para>
</li>
<li todoChecked={false}>
<para>distant</para>
</li>
</ul>
</doc>,
],
[
'toggling nested list with selection inside the nested lists',
<doc>
<ul>
<li>
<para>first</para>
<ul>
<li>
<para>[alpha</para>
</li>
<li>
<para>mang]o</para>
</li>
</ul>
</li>
<li>
<para>distant</para>
</li>
</ul>
</doc>,
<doc>
<ul>
<li>
<para>first</para>
<ul>
<li todoChecked={false}>
<para>alpha</para>
</li>
<li todoChecked={false}>
<para>mango</para>
</li>
</ul>
</li>
<li>
<para>distant</para>
</li>
</ul>
</doc>,
],
// TODO this is not intuitive
[
'toggling nested list with selection spanning parent and child lists',
<doc>
<ul>
<li>
<para>f[irst</para>
<ul>
<li>
<para>alpha</para>
</li>
<li>
<para>mang]o</para>
</li>
</ul>
</li>
<li>
<para>distant</para>
</li>
</ul>
</doc>,
<doc>
<ul>
<li todoChecked={false}>
<para>first</para>
<ul>
<li todoChecked={false}>
<para>alpha</para>
</li>
<li todoChecked={false}>
<para>mango</para>
</li>
</ul>
</li>
{/** the item below should have had todoChecked */}
<li>
<para>distant</para>
</li>
</ul>
</doc>,
],
])('toggleTodoList: Case %# %s', async (name, input, expected) => {
const { editorView } = await testEditor(input);
sendKeyToPm(editorView, 'Ctrl-Shift-7');
expect(editorView.state.doc).toEqualDocument(expected);
});
test.each([
[
'todo list',
<doc>
<ul>
<li todoChecked={false}>
<para>[] first</para>
</li>
</ul>
</doc>,
<doc>
<ul>
<li>
<para>[] first</para>
</li>
</ul>
</doc>,
],
[
'plain nested list',
<doc>
<ul>
<li todoChecked={false}>
<para>first</para>
<ul>
<li>
<para>[]second</para>
</li>
</ul>
</li>
</ul>
</doc>,
<doc>
<ul>
<li todoChecked={false}>
<para>first</para>
</li>
</ul>
<para>[]second</para>
</doc>,
],
[
"toggling parent doesn't affect children",
<doc>
<ul>
<li todoChecked={false}>
<para>firs[]t</para>
<ul>
<li todoChecked={false}>
<para>alpha</para>
</li>
<li todoChecked={false}>
<para>mango</para>
</li>
</ul>
</li>
<li todoChecked={false}>
<para>distant</para>
</li>
</ul>
</doc>,
<doc>
<ul>
<li>
<para>first[]</para>
<ul>
<li todoChecked={false}>
<para>alpha</para>
</li>
<li todoChecked={false}>
<para>mango</para>
</li>
</ul>
</li>
<li>
<para>distant</para>
</li>
</ul>
</doc>,
],
])('toggleBulletList: Case %# %s', async (name, input, expected) => {
const { editorView } = await testEditor(input);
sendKeyToPm(editorView, 'Ctrl-Shift-8');
expect(editorView.state.doc).toEqualDocument(expected);
});
describe('Pressing Backspace', () => {

@@ -1204,1 +1618,58 @@ it('Backspacing works', async () => {

});
describe('smartNodesBetween', () => {
test('works', async () => {
const { view } = await testEditor(
<doc>
<ul>
<li>
<para>firs[]t</para>
<ul>
<li>
<para>alpha</para>
</li>
</ul>
</li>
<li>
<para>distant</para>
</li>
</ul>
</doc>,
);
const state = view.state;
const nodes = [];
smartNodesBetween(
state.selection.$from,
state.selection.$to,
state.doc,
(node, pos) => {
if (
['listItem', 'bulletList', 'orderedItem'].includes(node.type.name)
) {
nodes.push([node.type.name, node.textContent, pos]);
}
},
);
expect(nodes).toMatchInlineSnapshot(`
Array [
Array [
"listItem",
"firstalpha",
1,
],
Array [
"bulletList",
"alpha",
9,
],
Array [
"listItem",
"distant",
21,
],
]
`);
});
});

231

components/bullet-list.js
import { keymap } from 'prosemirror-keymap';
import { wrappingInputRule } from 'prosemirror-inputrules';
import { parentHasDirectParentOfType } from '../core-commands';
import { toggleList } from './list-item/commands';
import { chainCommands } from 'prosemirror-commands';
import { filter } from '../utils/index';

@@ -56,3 +57,3 @@ export const spec = specFactory;

keymap({
[keybindings.toggle]: toggleList(type, schema.nodes.listItem),
[keybindings.toggle]: toggleBulletList(),
[keybindings.toggleTodo]: toggleTodoList(),

@@ -70,92 +71,99 @@ }),

export function toggleBulletList() {
return (state, dispatch, view) => {
return toggleList(
state.schema.nodes.bulletList,
state.schema.nodes.listItem,
)(state, dispatch, view);
};
}
const handleTodos = filter(
[isSelectionParentBulletList, (state) => todoCount(state).todos !== 0],
(state, dispatch) => {
const { selection } = state;
let tr = state.tr;
smartNodesBetween(selection.$from, selection.$to, tr.doc, (node, pos) => {
if (
node.type.name === 'listItem' &&
typeof node.attrs.todoChecked === 'boolean'
) {
tr = tr.setNodeMarkup(
pos,
undefined,
Object.assign({}, node.attrs, { todoChecked: null }),
);
}
});
// TODO: implemeted two different ways to toggle
// todos, none of them convert bulletList -> todoList directly
export function toggleTodoList2() {
return (state, dispatch, view) => {
const result = toggleList(
state.schema.nodes.bulletList,
state.schema.nodes.listItem,
true,
)(state, dispatch, view);
return result;
};
}
if (dispatch) {
dispatch(tr);
}
export function toggleTodoList() {
return (state, dispatch, view) => {
const result = toggleBulletList()(state, dispatch, view);
return true;
},
);
if (!result) {
return false;
}
const handleBulletLists = (state, dispatch, view) =>
toggleList(state.schema.nodes.bulletList, state.schema.nodes.listItem)(
state,
dispatch,
view,
);
state = view.state;
const { selection } = state;
return chainCommands(handleTodos, handleBulletLists);
}
const fromNode = selection.$from.node(-2);
const endNode = selection.$to.node(-2);
const isSelectionParentBulletList = (state) => {
const { selection } = state;
const fromNode = selection.$from.node(-2);
const endNode = selection.$to.node(-2);
// make sure the current selection is now bulletList
if (
!fromNode ||
fromNode.type.name !== state.schema.nodes.bulletList.name ||
!endNode ||
endNode.type.name !== state.schema.nodes.bulletList.name
) {
// returning true as toggling was still successful
return true;
}
return (
fromNode &&
fromNode.type === state.schema.nodes.bulletList &&
endNode &&
endNode.type === state.schema.nodes.bulletList
);
};
// at this point we have bulletList and we want to set every direct child
// to todoChecked
export function toggleTodoList() {
// The job of the command below is to see if the selection
// has some todo list-items, if yes, convert all list-items
// to todo.
const handleTodos = filter(
[
isSelectionParentBulletList,
(state) => {
const { todos, lists } = todoCount(state);
// If all the list items are todo or none of them are todo
// return false so we can run the vanilla toggleList
return todos !== lists;
},
],
(state, dispatch) => {
let { tr, selection } = state;
// NOTE: On start end depths start point to the start of listItems and end points to end of listItems
// in the current selections parent bulletList.
// example: even though selection is between A & B,
// the start and end will be * and ~.
// <ul>
// *<li>[A</li>
// <li><B]></li>
// <li><C></li>~
// </ul>
const start = selection.$from.start(-2);
const end = selection.$to.end(-2);
smartNodesBetween(
selection.$from,
selection.$to,
state.tr.doc,
(node, pos) => {
if (node.type.name === 'listItem' && node.attrs.todoChecked == null) {
tr = tr.setNodeMarkup(
pos,
undefined,
Object.assign({}, node.attrs, { todoChecked: false }),
);
}
},
);
const parent = selection.$from.node(-2);
let tr = state.tr;
tr.doc.nodesBetween(start, end, (node, pos) => {
// since we only need to iterate through
// the direct children of bulletList
if (parent === node) {
return true;
if (dispatch) {
dispatch(tr);
}
if (node.type.name === 'listItem') {
if (node.attrs.todoChecked == null) {
tr = tr.setNodeMarkup(
pos,
undefined,
Object.assign({}, node.attrs, { todoChecked: false }),
);
}
}
// don't dig deeper for any other node
return false;
});
return true;
},
);
if (dispatch) {
dispatch(tr);
}
const fallback = (state, dispatch, view) =>
toggleList(
state.schema.nodes.bulletList,
state.schema.nodes.listItem,
true,
)(state, dispatch, view);
return true;
};
return chainCommands(handleTodos, fallback);
}

@@ -184,1 +192,66 @@

}
/**
* given a bullet/ordered list it will call callback for each node
* which
* - strictly lies inside the range provided
* - nodes that are sibblings of the top level nodes
* which lie in the range.
*
* Example
* <ul>
* <li>[A
* <list-A's kids/>
* </li>
* <li><B]></li>
* <li><C></li>
* <li>D <list-D's kids </li>
* </ul>
*
* In the above the callback will be called for everyone
* A, list-A's kids, B, C, D _but_ not list-D's kids.
*/
export function smartNodesBetween($from, $to, doc, callback) {
const start = $from.start(-2);
const end = $to.end(-2);
const depth = Math.min(doc.resolve(start).depth, doc.resolve(end).depth);
doc.nodesBetween(start, end, (node, pos) => {
if (pos >= start) {
callback(node, pos);
}
// prevent return false for nodes higher in depth
// as we want to recurse in their kids.
if (doc.resolve(pos).depth <= depth) {
return;
}
// do not dig deeper into children of nodes outside of selection
if (pos < $from.pos) {
return false;
}
if (pos > $to.pos) {
return false;
}
});
}
function todoCount(state) {
let lists = 0;
let todos = 0;
const { selection } = state;
smartNodesBetween(selection.$from, selection.$to, state.doc, (node, pos) => {
if (node.type.name === 'listItem') {
lists++;
if (typeof node.attrs.todoChecked === 'boolean') {
todos++;
}
}
});
return {
lists: lists,
todos: todos,
};
}

@@ -170,4 +170,4 @@ import { liftTarget, ReplaceAroundStep } from 'prosemirror-transform';

* @param {Object} itemType 'listItem'
* @param {boolean} todo if toggling into a bulletList switch on todoChecked attr for
* each listItem.
* @param {boolean} todo if true and the final result of toggle is a bulletList
* set `todoChecked` attr for each listItem.
*/

@@ -174,0 +174,0 @@ export function toggleList(listType, itemType, todo) {

{
"name": "@bangle.dev/core",
"version": "0.3.0",
"version": "0.3.1",
"homepage": "https://bangle.dev",

@@ -5,0 +5,0 @@ "authors": [

@@ -348,3 +348,3 @@ import { DOMSerializer } from 'prosemirror-model';

export function fNot(func) {
export function complement(func) {
return (...args) => !func(...args);

@@ -351,0 +351,0 @@ }

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc