Files
outline/shared/editor/nodes/CheckboxItem.ts
T
dependabot[bot] fc01deeefd chore(deps-dev): bump oxlint-tsgolint from 0.14.2 to 0.22.1 (#12320)
* chore(deps-dev): bump oxlint-tsgolint from 0.14.2 to 0.22.1

Bumps [oxlint-tsgolint](https://github.com/oxc-project/tsgolint) from 0.14.2 to 0.22.1.
- [Release notes](https://github.com/oxc-project/tsgolint/releases)
- [Commits](https://github.com/oxc-project/tsgolint/compare/v0.14.2...v0.22.1)

---
updated-dependencies:
- dependency-name: oxlint-tsgolint
  dependency-version: 0.22.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore: Switch tsconfig to bundler resolution for tsgolint 0.22.1

oxlint-tsgolint 0.22.1 removed support for moduleResolution=node10
(the alias for "node"). Switch to "bundler" with resolvePackageJsonExports
disabled so packages whose exports field omits a types condition still
resolve. Update markdown-it type imports to sub-paths since the package's
.d.mts entry only re-exports a subset of named types.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: Resolve type-aware lint errors caught by tsgolint 0.22.1

oxlint-tsgolint 0.22.1 catches several await-thenable, no-floating-promises,
and no-meaningless-void-operator cases the prior 0.14.2 missed:

- Drop redundant inner `await` from Promise.all([await x, await y]) call sites
  so the array entries are real Promises rather than already-resolved values.
- Replace Promise.all wrappers around synchronous presenters (presentEvent,
  presentTemplate, presentPublicTeam) with plain map / direct calls.
- Wrap non-promise branches of ternaries inside Promise.all with
  Promise.resolve so the array remains thenable across both arms.
- Add `void` to the unawaited provider.connect() in the auth-failed retry
  chain, and remove `void` from the disconnect() call which returns void.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 07:59:13 -04:00

141 lines
3.5 KiB
TypeScript

import type Token from "markdown-it/lib/token.mjs";
import type {
NodeSpec,
Node as ProsemirrorNode,
NodeType,
} from "prosemirror-model";
import {
splitListItem,
sinkListItem,
liftListItem,
} from "prosemirror-schema-list";
import { v4 as uuidv4 } from "uuid";
import { toggleCheckboxItems } from "../commands/toggleCheckboxItems";
import type { MarkdownSerializerState } from "../lib/markdown/serializer";
import checkboxRule from "../rules/checkboxes";
import Node from "./Node";
export default class CheckboxItem extends Node {
get name() {
return "checkbox_item";
}
get schema(): NodeSpec {
return {
attrs: {
checked: {
default: false,
},
},
content: "block+",
defining: true,
draggable: true,
parseDOM: [
{
tag: `li[data-type="${this.name}"]`,
getAttrs: (dom: HTMLLIElement) => ({
checked: dom.className.includes("checked"),
}),
},
],
toDOM: (node) => {
const id = `checkbox-${uuidv4()}`;
const checked = node.attrs.checked.toString();
let input;
if (typeof document !== "undefined") {
input = document.createElement("span");
input.tabIndex = -1;
input.className = "checkbox";
input.setAttribute("aria-checked", checked);
input.setAttribute("aria-labelledby", id);
input.setAttribute("role", "checkbox");
input.addEventListener("click", this.handleClick);
}
return [
"li",
{
"data-type": this.name,
class: node.attrs.checked ? "checked" : undefined,
},
[
"span",
{
contentEditable: "false",
},
...(input
? [input]
: [["span", { class: "checkbox", "aria-checked": checked }]]),
],
["div", { id }, 0],
];
},
};
}
get rulePlugins() {
return [checkboxRule];
}
handleClick = (event: Event) => {
if (!(event.target instanceof HTMLSpanElement)) {
return;
}
const { view } = this.editor;
const { tr } = view.state;
const { top, left } = event.target.getBoundingClientRect();
const result = view.posAtCoords({ top, left });
if (result) {
const transaction = tr.setNodeMarkup(result.inside, undefined, {
checked: event.target.getAttribute("aria-checked") !== "true",
});
view.dispatch(transaction);
}
};
commands({ type }: { type: NodeType }) {
return {
indentCheckboxList: () => sinkListItem(type),
outdentCheckboxList: () => liftListItem(type),
};
}
keys({ type }: { type: NodeType }) {
return {
Enter: splitListItem(type, {
checked: false,
}),
Tab: sinkListItem(type),
"Mod-Enter": toggleCheckboxItems(type),
"Shift-Tab": liftListItem(type),
"Mod-]": sinkListItem(type),
"Mod-[": liftListItem(type),
};
}
toMarkdown(state: MarkdownSerializerState, node: ProsemirrorNode) {
state.out += node.attrs.checked ? "[x] " : "[ ] ";
if (state.inTable) {
node.forEach((block, _, i) => {
if (i > 0) {
state.out += " ";
}
state.renderInline(block);
});
return;
}
state.renderContent(node);
}
parseMarkdown() {
return {
block: "checkbox_item",
getAttrs: (tok: Token) => ({
checked: tok.attrGet("checked") ? true : undefined,
}),
};
}
}