editor types, checkbox fix, baseurl fix

This commit is contained in:
tonyrewin 2022-10-23 13:48:03 +03:00
parent 70535f2366
commit 7d338149f0
11 changed files with 43 additions and 30 deletions

View File

@ -1,5 +1,5 @@
import { schema as markdownSchema } from 'prosemirror-markdown' import { schema as markdownSchema } from 'prosemirror-markdown'
import { Schema } from 'prosemirror-model' import { NodeSpec, Schema } from 'prosemirror-model'
import { baseKeymap } from 'prosemirror-commands' import { baseKeymap } from 'prosemirror-commands'
import { sinkListItem, liftListItem } from 'prosemirror-schema-list' import { sinkListItem, liftListItem } from 'prosemirror-schema-list'
import { history } from 'prosemirror-history' import { history } from 'prosemirror-history'
@ -7,6 +7,7 @@ import { dropCursor } from 'prosemirror-dropcursor'
import { buildKeymap } from 'prosemirror-example-setup' import { buildKeymap } from 'prosemirror-example-setup'
import { keymap } from 'prosemirror-keymap' import { keymap } from 'prosemirror-keymap'
import type { ProseMirrorExtension } from '../helpers' import type { ProseMirrorExtension } from '../helpers'
import type OrderedMap from 'orderedmap'
const plainSchema = new Schema({ const plainSchema = new Schema({
nodes: { nodes: {
@ -29,7 +30,7 @@ const blockquoteSchema = {
content: 'block+', content: 'block+',
group: 'block', group: 'block',
toDOM: () => ['div', ['blockquote', 0]] toDOM: () => ['div', ['blockquote', 0]]
} } as NodeSpec
export default (plain = false): ProseMirrorExtension => ({ export default (plain = false): ProseMirrorExtension => ({
schema: () => schema: () =>
@ -39,7 +40,7 @@ export default (plain = false): ProseMirrorExtension => ({
marks: plainSchema.spec.marks marks: plainSchema.spec.marks
} }
: { : {
nodes: (markdownSchema.spec.nodes as any).update('blockquote', blockquoteSchema), nodes: (markdownSchema.spec.nodes as OrderedMap<NodeSpec>).update('blockquote', blockquoteSchema),
marks: markdownSchema.spec.marks marks: markdownSchema.spec.marks
}, },
plugins: (prev, schema) => [ plugins: (prev, schema) => [

View File

@ -2,7 +2,7 @@ import { Plugin, Transaction } from 'prosemirror-state'
import { Fragment, Node, Schema, Slice } from 'prosemirror-model' import { Fragment, Node, Schema, Slice } from 'prosemirror-model'
import type { ProseMirrorExtension } from '../helpers' import type { ProseMirrorExtension } from '../helpers'
import { createMarkdownParser } from '../../markdown' import { createMarkdownParser } from '../../markdown'
import { openPrompt } from './prompt' // import { openPrompt } from './prompt'
const URL_REGEX = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:\d+)?(\/|\/([\w!#%&+./:=?@-]))?/g const URL_REGEX = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:\d+)?(\/|\/([\w!#%&+./:=?@-]))?/g
@ -11,7 +11,7 @@ const transform = (schema: Schema, fragment: Fragment) => {
fragment.forEach((child: Node) => { fragment.forEach((child: Node) => {
if (child.isText) { if (child.isText) {
let pos = 0 let pos = 0
let match: any let match: RegExpExecArray
while ((match = URL_REGEX.exec(child.text)) !== null) { while ((match = URL_REGEX.exec(child.text)) !== null) {
const start = match.index const start = match.index

View File

@ -1,7 +1,7 @@
const prefix = 'ProseMirror-prompt' const prefix = 'ProseMirror-prompt'
// eslint-disable-next-line sonarjs/cognitive-complexity // eslint-disable-next-line sonarjs/cognitive-complexity
export function openPrompt(options: any) { export function openPrompt(options) {
const wrapper = document.body.appendChild(document.createElement('div')) const wrapper = document.body.appendChild(document.createElement('div'))
wrapper.className = prefix wrapper.className = prefix
@ -14,7 +14,7 @@ export function openPrompt(options: any) {
if (wrapper.parentNode) wrapper.remove() if (wrapper.parentNode) wrapper.remove()
} }
const domFields: Node[] = [] const domFields: HTMLElement[] = []
options.fields.forEach((name) => { options.fields.forEach((name) => {
domFields.push(options.fields[name].render()) domFields.push(options.fields[name].render())
}) })
@ -33,7 +33,7 @@ export function openPrompt(options: any) {
if (options.title) { if (options.title) {
form.appendChild(document.createElement('h5')).textContent = options.title form.appendChild(document.createElement('h5')).textContent = options.title
} }
domFields.forEach((field: Node) => { domFields.forEach((field: HTMLElement) => {
form.appendChild(document.createElement('div')).appendChild(field) form.appendChild(document.createElement('div')).appendChild(field)
}) })
const buttons = form.appendChild(document.createElement('div')) const buttons = form.appendChild(document.createElement('div'))
@ -77,7 +77,7 @@ export function openPrompt(options: any) {
if (input) input.focus() if (input) input.focus()
} }
function getValues(fields: any, domFields: any) { function getValues(fields: any, domFields: HTMLElement[]) {
const result = Object.create(null) const result = Object.create(null)
let i = 0 let i = 0
fields.forEarch((name) => { fields.forEarch((name) => {

View File

@ -1,7 +1,8 @@
import { inputRules } from 'prosemirror-inputrules' import { inputRules } from 'prosemirror-inputrules'
import type { MarkType } from 'prosemirror-model' import type { MarkSpec, MarkType } from 'prosemirror-model'
import { markInputRule } from './mark-input-rule' import { markInputRule } from './mark-input-rule'
import type { ProseMirrorExtension } from '../helpers' import type { ProseMirrorExtension } from '../helpers'
import type OrderedMap from 'orderedmap'
const strikethroughRule = (nodeType: MarkType) => markInputRule(/~{2}(.+)~{2}$/, nodeType) const strikethroughRule = (nodeType: MarkType) => markInputRule(/~{2}(.+)~{2}$/, nodeType)
@ -10,12 +11,12 @@ const strikethroughSchema = {
parseDOM: [{ tag: 'del' }], parseDOM: [{ tag: 'del' }],
toDOM: () => ['del'] toDOM: () => ['del']
} }
} } as MarkSpec
export default (): ProseMirrorExtension => ({ export default (): ProseMirrorExtension => ({
schema: (prev) => ({ schema: (prev) => ({
...prev, ...prev,
marks: (prev.marks as any).append(strikethroughSchema) marks: (prev.marks as OrderedMap<MarkSpec>).append(strikethroughSchema)
}), }),
plugins: (prev, schema) => [ plugins: (prev, schema) => [
...prev, ...prev,

View File

@ -1,8 +1,9 @@
import { EditorState, Selection } from 'prosemirror-state' import { EditorState, Selection } from 'prosemirror-state'
import type { Node, Schema, ResolvedPos } from 'prosemirror-model' import type { Node, Schema, ResolvedPos, NodeSpec } from 'prosemirror-model'
import { InputRule, inputRules } from 'prosemirror-inputrules' import { InputRule, inputRules } from 'prosemirror-inputrules'
import { keymap } from 'prosemirror-keymap' import { keymap } from 'prosemirror-keymap'
import type { ProseMirrorExtension } from '../helpers' import type { ProseMirrorExtension } from '../helpers'
import type OrderedMap from 'orderedmap'
export const tableInputRule = (schema: Schema) => export const tableInputRule = (schema: Schema) =>
new InputRule( new InputRule(
@ -95,7 +96,7 @@ const tableSchema = {
], ],
toDOM: (node: Node) => ['th', node.attrs, 0] toDOM: (node: Node) => ['th', node.attrs, 0]
} }
} } as NodeSpec
const findParentPos = ($pos: ResolvedPos, fn: (n: Node) => boolean) => { const findParentPos = ($pos: ResolvedPos, fn: (n: Node) => boolean) => {
for (let d = $pos.depth; d > 0; d--) { for (let d = $pos.depth; d > 0; d--) {
@ -174,7 +175,7 @@ const getTextSize = (n: Node) => {
export default (): ProseMirrorExtension => ({ export default (): ProseMirrorExtension => ({
schema: (prev) => ({ schema: (prev) => ({
...prev, ...prev,
nodes: (prev.nodes as any).append(tableSchema) nodes: (prev.nodes as OrderedMap<NodeSpec>).append(tableSchema)
}), }),
// eslint-disable-next-line sonarjs/cognitive-complexity // eslint-disable-next-line sonarjs/cognitive-complexity
plugins: (prev, schema) => [ plugins: (prev, schema) => [

View File

@ -1,9 +1,10 @@
import { DOMOutputSpec, DOMSerializer, Node as ProsemirrorNode, NodeType, Schema } from 'prosemirror-model' import { DOMOutputSpec, DOMSerializer, Node as ProsemirrorNode, NodeSpec, NodeType, Schema } from 'prosemirror-model'
import type { EditorView } from 'prosemirror-view' import type { EditorView } from 'prosemirror-view'
import { wrappingInputRule , inputRules } from 'prosemirror-inputrules' import { wrappingInputRule , inputRules } from 'prosemirror-inputrules'
import { splitListItem } from 'prosemirror-schema-list' import { splitListItem } from 'prosemirror-schema-list'
import { keymap } from 'prosemirror-keymap' import { keymap } from 'prosemirror-keymap'
import type { NodeViewFn, ProseMirrorExtension } from '../helpers' import type { NodeViewFn, ProseMirrorExtension } from '../helpers'
import type OrderedMap from 'orderedmap'
const todoListRule = (nodeType: NodeType) => const todoListRule = (nodeType: NodeType) =>
wrappingInputRule(new RegExp('^\\[( |x)]\\s$'), nodeType, (match) => ({ wrappingInputRule(new RegExp('^\\[( |x)]\\s$'), nodeType, (match) => ({
@ -44,7 +45,7 @@ const todoListSchema = {
['div', 0] ['div', 0]
] ]
} }
} } as NodeSpec
class TodoItemView { class TodoItemView {
contentDOM: Node contentDOM: Node
@ -78,7 +79,7 @@ const todoListKeymap = (schema: Schema) => ({
export default (): ProseMirrorExtension => ({ export default (): ProseMirrorExtension => ({
schema: (prev) => ({ schema: (prev) => ({
...prev, ...prev,
nodes: (prev.nodes as any).append(todoListSchema) nodes: (prev.nodes as OrderedMap<NodeSpec>).append(todoListSchema)
}), }),
plugins: (prev, schema) => [ plugins: (prev, schema) => [
keymap(todoListKeymap(schema)), keymap(todoListKeymap(schema)),

View File

@ -17,9 +17,9 @@ export type NodeViewFn = (
decorations: Decoration[] decorations: Decoration[]
) => NodeView ) => NodeView
export const isInitialized = (state: any) => state !== undefined && state instanceof EditorState export const isInitialized = (state) => state !== undefined && state instanceof EditorState
export const isEmpty = (state: any) => export const isEmpty = (state) =>
!isInitialized(state) || !isInitialized(state) ||
(state.doc.childCount === 1 && (state.doc.childCount === 1 &&
!state.doc.firstChild.type.spec.code && !state.doc.firstChild.type.spec.code &&

View File

@ -6,7 +6,7 @@ import { selectAll, deleteSelection } from 'prosemirror-commands'
import { undo as yUndo, redo as yRedo } from 'y-prosemirror' import { undo as yUndo, redo as yRedo } from 'y-prosemirror'
import debounce from 'lodash/debounce' import debounce from 'lodash/debounce'
import { createSchema, createExtensions, createEmptyText } from '../prosemirror/setup' import { createSchema, createExtensions, createEmptyText } from '../prosemirror/setup'
import { State, Draft, Config, ServiceError, newState, ExtensionsProps } from './context' import { State, Draft, Config, ServiceError, newState, ExtensionsProps, EditorActions } from './context'
import { mod } from '../env' import { mod } from '../env'
import { serialize, createMarkdownParser } from '../markdown' import { serialize, createMarkdownParser } from '../markdown'
import db from '../db' import db from '../db'
@ -16,11 +16,12 @@ const isText = (x) => x && x.doc && x.selection
const isState = (x) => typeof x.lastModified !== 'string' && Array.isArray(x.drafts || []) const isState = (x) => typeof x.lastModified !== 'string' && Array.isArray(x.drafts || [])
const isDraft = (x): boolean => x && (x.text || x.path) const isDraft = (x): boolean => x && (x.text || x.path)
export const createCtrl = (initial: State): [Store<State>, any] => {
export const createCtrl = (initial: State): [Store<State>, EditorActions] => {
const [store, setState] = createStore(initial) const [store, setState] = createStore(initial)
const onUndo = () => { const onUndo = () => {
if (!isInitialized(store.text)) return if (!isInitialized(store.text)) return false
const text = store.text as EditorState const text = store.text as EditorState
if (store.collab?.started) { if (store.collab?.started) {
yUndo(text) yUndo(text)
@ -53,12 +54,14 @@ export const createCtrl = (initial: State): [Store<State>, any] => {
return true return true
} }
const toggleMarkdown = () => { const toggleMarkdown = () => {
const state = unwrap(store) const state = unwrap(store)
const editorState = store.text as EditorState const editorState = store.text as EditorState
const markdown = !state.markdown const markdown = !state.markdown
const selection = { type: 'text', anchor: 1, head: 1 } const selection = { type: 'text', anchor: 1, head: 1 }
let doc: any let doc
if (markdown) { if (markdown) {
const lines = serialize(editorState).split('\n') const lines = serialize(editorState).split('\n')
@ -178,7 +181,7 @@ export const createCtrl = (initial: State): [Store<State>, any] => {
const room = window.location.pathname?.slice(1).trim() const room = window.location.pathname?.slice(1).trim()
const args = { room: room ?? undefined } const args = { room: room ?? undefined }
const data = await db.get('state') const data = await db.get('state')
let parsed: any let parsed: State
if (data !== undefined) { if (data !== undefined) {
try { try {
parsed = JSON.parse(data) parsed = JSON.parse(data)

View File

@ -89,6 +89,11 @@ export interface Draft {
extensions?: ProseMirrorExtension[] extensions?: ProseMirrorExtension[]
} }
export interface EditorActions {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key:string]: any
}
export class ServiceError extends Error { export class ServiceError extends Error {
public errorObject: ErrorObject public errorObject: ErrorObject
constructor(id: string, props: unknown) { constructor(id: string, props: unknown) {
@ -97,7 +102,7 @@ export class ServiceError extends Error {
} }
} }
export const StateContext = createContext<[Store<State>, any]>([undefined, undefined]) export const StateContext = createContext<[Store<State>, EditorActions]>([undefined, undefined])
export const useState = () => useContext(StateContext) export const useState = () => useContext(StateContext)

View File

@ -308,7 +308,7 @@ input[type='checkbox'] {
position: relative; position: relative;
&::before { &::before {
background: url('/icons/checkbox.svg') no-repeat; // background: url('/icons/checkbox.svg') no-repeat;
content: ''; content: '';
height: 2rem; height: 2rem;
left: 0; left: 0;
@ -320,7 +320,8 @@ input[type='checkbox'] {
&:checked + label { &:checked + label {
&::before { &::before {
background-image: url('/icons/checkbox-checked.svg'); // background-image: url('/icons/checkbox-checked.svg');
position: relative;
} }
} }
} }

View File

@ -1,4 +1,4 @@
export const isDev = import.meta.env.MODE === 'development' export const isDev = import.meta.env.MODE === 'development'
// export const apiBaseUrl = 'https://newapi.discours.io' export const apiBaseUrl = 'https://newapi.discours.io'
export const apiBaseUrl = 'http://localhost:8080' // export const apiBaseUrl = 'http://localhost:8000'