typing-fixes
This commit is contained in:
parent
d0e98bb525
commit
ce9057d637
|
@ -89,6 +89,7 @@
|
|||
"markdown-it-mark": "^3.0.1",
|
||||
"markdown-it-replace-link": "^1.1.0",
|
||||
"nanostores": "^0.7.0",
|
||||
"orderedmap": "^2.1.0",
|
||||
"postcss": "^8.4.16",
|
||||
"postcss-modules": "^5.0.0",
|
||||
"prettier": "^2.7.1",
|
||||
|
|
3
src/assets/handle.svg
Normal file
3
src/assets/handle.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg viewBox="0 0 10 10" height="14" width="14">
|
||||
<path d="M3 2a1 1 0 110-2 1 1 0 010 2zm0 4a1 1 0 110-2 1 1 0 010 2zm0 4a1 1 0 110-2 1 1 0 010 2zm4-8a1 1 0 110-2 1 1 0 010 2zm0 4a1 1 0 110-2 1 1 0 010 2zm0 4a1 1 0 110-2 1 1 0 010 2z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 245 B |
|
@ -20,7 +20,8 @@ export default () => {
|
|||
}
|
||||
return (
|
||||
<ProseMirror
|
||||
class={'editor'}
|
||||
// eslint-disable-next-line solid/no-react-specific-props
|
||||
className="editor"
|
||||
style={style()}
|
||||
editorView={store.editorView as EditorView}
|
||||
text={store.text as ProseMirrorState}
|
||||
|
|
|
@ -11,7 +11,8 @@ export const Editor = () => {
|
|||
const onChange = (text: EditorState) => ctrl.setState({ text, lastModified: new Date() })
|
||||
return (
|
||||
<ProseMirror
|
||||
class="editor"
|
||||
// eslint-disable-next-line solid/no-react-specific-props
|
||||
className="editor"
|
||||
style={store.markdown && `white-space: pre-wrap;`}
|
||||
editorView={store.editorView}
|
||||
text={store.text}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { schema as markdownSchema } from 'prosemirror-markdown'
|
||||
import { Schema } from 'prosemirror-model'
|
||||
import type OrderedMap from 'orderedmap'
|
||||
import { NodeSpec, Schema } from 'prosemirror-model'
|
||||
import { baseKeymap } from 'prosemirror-commands'
|
||||
import { sinkListItem, liftListItem } from 'prosemirror-schema-list'
|
||||
import { history } from 'prosemirror-history'
|
||||
|
@ -39,7 +40,10 @@ export default (plain = false): ProseMirrorExtension => ({
|
|||
marks: plainSchema.spec.marks
|
||||
}
|
||||
: {
|
||||
nodes: (markdownSchema.spec.nodes as any).update('blockquote', blockquoteSchema),
|
||||
nodes: (markdownSchema.spec.nodes as OrderedMap<NodeSpec>).update(
|
||||
'blockquote',
|
||||
blockquoteSchema as unknown as NodeSpec
|
||||
),
|
||||
marks: markdownSchema.spec.marks
|
||||
},
|
||||
plugins: (prev, schema) => [
|
||||
|
|
|
@ -2,7 +2,13 @@ import { ySyncPlugin, yCursorPlugin, yUndoPlugin } from 'y-prosemirror'
|
|||
import type { YOptions } from '../../store'
|
||||
import type { ProseMirrorExtension } from '../helpers'
|
||||
|
||||
export const cursorBuilder = (user: any): HTMLElement => {
|
||||
export interface EditingProps {
|
||||
name: string
|
||||
foreground: string
|
||||
background: string
|
||||
}
|
||||
|
||||
export const cursorBuilder = (user: EditingProps): HTMLElement => {
|
||||
const cursor = document.createElement('span')
|
||||
cursor.classList.add('ProseMirror-yjs-cursor')
|
||||
cursor.setAttribute('style', `border-color: ${user.background}`)
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import { Plugin, NodeSelection } from 'prosemirror-state'
|
||||
import { DecorationSet, Decoration } from 'prosemirror-view'
|
||||
import type { ProseMirrorExtension } from '../helpers'
|
||||
|
||||
const handleIcon = `
|
||||
<svg viewBox="0 0 10 10" height="14" width="14">
|
||||
<path d="M3 2a1 1 0 110-2 1 1 0 010 2zm0 4a1 1 0 110-2 1 1 0 010 2zm0 4a1 1 0 110-2 1 1 0 010 2zm4-8a1 1 0 110-2 1 1 0 010 2zm0 4a1 1 0 110-2 1 1 0 010 2zm0 4a1 1 0 110-2 1 1 0 010 2z"/>
|
||||
</svg>`
|
||||
import handleIcon from '../../../../assets/handle.svg'
|
||||
|
||||
const createDragHandle = () => {
|
||||
const handle = document.createElement('span')
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { Plugin } from 'prosemirror-state'
|
||||
import type { Node, Schema } from 'prosemirror-model'
|
||||
import type { Node, NodeSpec, Schema } from 'prosemirror-model'
|
||||
import type { EditorView } from 'prosemirror-view'
|
||||
import type { ProseMirrorExtension } from '../helpers'
|
||||
import type { NodeViewFn, ProseMirrorExtension } from '../helpers'
|
||||
import type OrderedMap from 'orderedmap'
|
||||
|
||||
const REGEX = /^!\[([^[\]]*?)]\((.+?)\)\s+/
|
||||
const MAX_MATCH = 500
|
||||
|
@ -17,7 +18,7 @@ const isUrl = (str: string) => {
|
|||
|
||||
const isBlank = (text: string) => text === ' ' || text === '\u00A0'
|
||||
|
||||
const imageInput = (schema: Schema, path?: string) =>
|
||||
const imageInput = (schema: Schema, _path?: string) =>
|
||||
new Plugin({
|
||||
props: {
|
||||
handleTextInput(view, from, to, text) {
|
||||
|
@ -68,7 +69,7 @@ const imageSchema = {
|
|||
src: dom.getAttribute('src'),
|
||||
title: dom.getAttribute('title'),
|
||||
alt: dom.getAttribute('alt'),
|
||||
path: (dom as any).dataset.path
|
||||
path: (dom as NodeSpec).dataset.path
|
||||
})
|
||||
}
|
||||
],
|
||||
|
@ -101,12 +102,12 @@ class ImageView {
|
|||
contentDOM: Element
|
||||
container: HTMLElement
|
||||
handle: HTMLElement
|
||||
onResizeFn: any
|
||||
onResizeEndFn: any
|
||||
onResizeFn: (e: Event) => void
|
||||
onResizeEndFn: (e: Event) => void
|
||||
width: number
|
||||
updating: number
|
||||
|
||||
constructor(node: Node, view: EditorView, getPos: () => number, schema: Schema, path: string) {
|
||||
constructor(node: Node, view: EditorView, getPos: () => number, schema: Schema, _path: string) {
|
||||
this.node = node
|
||||
this.view = view
|
||||
this.getPos = getPos
|
||||
|
@ -161,12 +162,12 @@ class ImageView {
|
|||
export default (path?: string): ProseMirrorExtension => ({
|
||||
schema: (prev) => ({
|
||||
...prev,
|
||||
nodes: (prev.nodes as any).update('image', imageSchema)
|
||||
nodes: (prev.nodes as OrderedMap<NodeSpec>).update('image', imageSchema as unknown as NodeSpec)
|
||||
}),
|
||||
plugins: (prev, schema) => [...prev, imageInput(schema, path)],
|
||||
nodeViews: {
|
||||
image: (node, view, getPos) => {
|
||||
return new ImageView(node, view, getPos, view.state.schema, path)
|
||||
}
|
||||
} as any
|
||||
} as unknown as { [key: string]: NodeViewFn }
|
||||
})
|
||||
|
|
|
@ -31,7 +31,6 @@ const markdownLinks = (schema: Schema) =>
|
|||
if (action?.pos) {
|
||||
(state as any).pos = action.pos
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
},
|
||||
|
|
|
@ -16,48 +16,34 @@ import {
|
|||
import type { MenuItemSpec, MenuElement } from 'prosemirror-menu'
|
||||
|
||||
import { wrapInList } from 'prosemirror-schema-list'
|
||||
import { NodeSelection } from 'prosemirror-state'
|
||||
import { Command, EditorState, NodeSelection, Transaction } from 'prosemirror-state'
|
||||
|
||||
import { TextField, openPrompt } from './prompt'
|
||||
import type { ProseMirrorExtension } from '../helpers'
|
||||
import type { Schema } from 'prosemirror-model'
|
||||
import type { Attrs, MarkType, NodeType, Schema } from 'prosemirror-model'
|
||||
import type { EditorView } from 'prosemirror-view'
|
||||
|
||||
// Helpers to create specific types of items
|
||||
|
||||
function canInsert(state: { selection: { $from: any } }, nodeType: any) {
|
||||
function canInsert(state: EditorState, nodeType: NodeType) {
|
||||
const $from = state.selection.$from
|
||||
|
||||
for (let d = $from.depth; d >= 0; d--) {
|
||||
const index = $from.index(d)
|
||||
|
||||
if ($from.node(d).canReplaceWith(index, index, nodeType)) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
function insertImageItem(nodeType: { createAndFill: (arg0: any) => any }) {
|
||||
function insertImageItem(nodeType: NodeType) {
|
||||
return new MenuItem({
|
||||
icon: icons.image,
|
||||
label: 'image',
|
||||
enable(state: any) {
|
||||
enable(state) {
|
||||
return canInsert(state, nodeType)
|
||||
},
|
||||
run(
|
||||
state: {
|
||||
selection: { node?: any; from?: any; to?: any }
|
||||
doc: { textBetween: (arg0: any, arg1: any, arg2: string) => any }
|
||||
},
|
||||
_: any,
|
||||
view: {
|
||||
dispatch: (arg0: any) => void
|
||||
state: { tr: { replaceSelectionWith: (arg0: any) => any } }
|
||||
focus: () => void
|
||||
}
|
||||
) {
|
||||
const { from, to, node } = state.selection
|
||||
run(state: EditorState, _, view: EditorView) {
|
||||
const { from, to, node } = state.selection as NodeSelection
|
||||
let attrs = null
|
||||
|
||||
if (state.selection instanceof NodeSelection && node.type === nodeType) {
|
||||
attrs = node.attrs
|
||||
}
|
||||
|
@ -77,7 +63,7 @@ function insertImageItem(nodeType: { createAndFill: (arg0: any) => any }) {
|
|||
})
|
||||
},
|
||||
// eslint-disable-next-line no-shadow
|
||||
callback(attrs: any) {
|
||||
callback(attrs: Attrs) {
|
||||
view.dispatch(view.state.tr.replaceSelectionWith(nodeType.createAndFill(attrs)))
|
||||
view.focus()
|
||||
}
|
||||
|
@ -86,53 +72,31 @@ function insertImageItem(nodeType: { createAndFill: (arg0: any) => any }) {
|
|||
})
|
||||
}
|
||||
|
||||
function cmdItem(
|
||||
cmd: (arg0: any) => any,
|
||||
options: { [x: string]: any; active?: (state: any) => any; enable?: any; title?: any; select?: any }
|
||||
) {
|
||||
const passedOptions = {
|
||||
label: options.title,
|
||||
run: cmd
|
||||
} as { [key: string]: any }
|
||||
|
||||
function cmdItem(cmd: Command, options: MenuItemSpec) {
|
||||
const passedOptions = { label: options.title, run: cmd } as MenuItemSpec
|
||||
Object.keys(options).forEach((prop) => (passedOptions[prop] = options[prop]))
|
||||
|
||||
if ((!options.enable || options.enable === true) && !options.select) {
|
||||
passedOptions[options.enable ? 'enable' : 'select'] = (state: any) => cmd(state)
|
||||
}
|
||||
|
||||
// TODO: enable/disable items logix
|
||||
passedOptions.select = (state) => cmd(state)
|
||||
return new MenuItem(passedOptions as MenuItemSpec)
|
||||
}
|
||||
|
||||
function markActive(
|
||||
state: {
|
||||
selection: { from: any; $from: any; to: any; empty: any }
|
||||
storedMarks: any
|
||||
doc: { rangeHasMark: (arg0: any, arg1: any, arg2: any) => any }
|
||||
},
|
||||
type: { isInSet: (arg0: any) => any }
|
||||
) {
|
||||
function markActive(state: EditorState, type: MarkType) {
|
||||
const { from, $from, to, empty } = state.selection
|
||||
|
||||
if (empty) return type.isInSet(state.storedMarks || $from.marks())
|
||||
|
||||
return state.doc.rangeHasMark(from, to, type)
|
||||
}
|
||||
|
||||
function markItem(markType: any, options: { [x: string]: any; title?: string; icon?: any }) {
|
||||
function markItem(markType: MarkType, options: MenuItemSpec) {
|
||||
const passedOptions = {
|
||||
active(state: any) {
|
||||
active(state) {
|
||||
return markActive(state, markType)
|
||||
},
|
||||
enable: true
|
||||
} as { [key: string]: any }
|
||||
|
||||
}
|
||||
} as MenuItemSpec
|
||||
Object.keys(options).forEach((prop: string) => (passedOptions[prop] = options[prop]))
|
||||
|
||||
return cmdItem(toggleMark(markType), passedOptions)
|
||||
}
|
||||
|
||||
function linkItem(markType: any) {
|
||||
function linkItem(markType: MarkType) {
|
||||
return new MenuItem({
|
||||
title: 'Add or remove link',
|
||||
icon: {
|
||||
|
@ -140,19 +104,13 @@ function linkItem(markType: any) {
|
|||
height: 18,
|
||||
path: 'M3.27177 14.7277C2.06258 13.5186 2.06258 11.5527 3.27177 10.3435L6.10029 7.51502L4.75675 6.17148L1.92823 9C-0.0234511 10.9517 -0.0234511 14.1196 1.92823 16.0713C3.87991 18.023 7.04785 18.023 8.99952 16.0713L11.828 13.2428L10.4845 11.8992L7.65598 14.7277C6.44679 15.9369 4.48097 15.9369 3.27177 14.7277ZM6.87756 12.536L12.5346 6.87895L11.1203 5.46469L5.4633 11.1217L6.87756 12.536ZM6.17055 4.75768L8.99907 1.92916C10.9507 -0.0225206 14.1187 -0.0225201 16.0704 1.92916C18.022 3.88084 18.022 7.04878 16.0704 9.00046L13.2418 11.829L11.8983 10.4854L14.7268 7.65691C15.936 6.44772 15.936 4.4819 14.7268 3.27271C13.5176 2.06351 11.5518 2.06351 10.3426 3.2727L7.51409 6.10122L6.17055 4.75768Z'
|
||||
},
|
||||
active(state: any) {
|
||||
return markActive(state, markType)
|
||||
},
|
||||
enable(state: { selection: { empty: any } }) {
|
||||
return !state.selection.empty
|
||||
},
|
||||
run(state: any, dispatch: any, view: { state: any; dispatch: any; focus: () => void }) {
|
||||
active: (state) => Boolean(markActive(state, markType)),
|
||||
enable: (state: EditorState) => !state.selection.empty,
|
||||
run(state: EditorState, dispatch: (t: Transaction) => void, view: EditorView) {
|
||||
if (markActive(state, markType)) {
|
||||
toggleMark(markType)(state, dispatch)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
openPrompt({
|
||||
fields: {
|
||||
href: new TextField({
|
||||
|
@ -160,7 +118,7 @@ function linkItem(markType: any) {
|
|||
required: true
|
||||
})
|
||||
},
|
||||
callback(attrs: any) {
|
||||
callback(attrs: Attrs) {
|
||||
toggleMark(markType, attrs)(view.state, view.dispatch)
|
||||
view.focus()
|
||||
}
|
||||
|
@ -169,14 +127,8 @@ function linkItem(markType: any) {
|
|||
})
|
||||
}
|
||||
|
||||
function wrapListItem(
|
||||
nodeType: any,
|
||||
options: {
|
||||
title?: string
|
||||
icon?: { width: number; height: number; path: string } | { width: number; height: number; path: string }
|
||||
attrs?: any
|
||||
}
|
||||
) {
|
||||
function wrapListItem(nodeType: NodeType, options: MenuItemSpec & { attrs: Attrs }) {
|
||||
options.run = (_) => true
|
||||
return cmdItem(wrapInList(nodeType, options.attrs), options)
|
||||
}
|
||||
|
||||
|
@ -255,7 +207,7 @@ type BuildSchema = {
|
|||
*/
|
||||
export function buildMenuItems(schema: Schema) {
|
||||
const r: { [key: string]: MenuItem | MenuItem[] } = {}
|
||||
let type: any
|
||||
let type: NodeType | MarkType
|
||||
|
||||
if ((type = schema.marks.strong)) {
|
||||
r.toggleStrong = markItem(type, {
|
||||
|
@ -265,7 +217,7 @@ export function buildMenuItems(schema: Schema) {
|
|||
height: 16,
|
||||
path: 'M9.82857 7.76C10.9371 6.99429 11.7143 5.73714 11.7143 4.57143C11.7143 1.98857 9.71428 0 7.14286 0H0V16H8.04571C10.4343 16 12.2857 14.0571 12.2857 11.6686C12.2857 9.93143 11.3029 8.44571 9.82857 7.76ZM3.42799 2.85708H6.85656C7.80513 2.85708 8.57085 3.6228 8.57085 4.57137C8.57085 5.51994 7.80513 6.28565 6.85656 6.28565H3.42799V2.85708ZM3.42799 13.1429H7.42799C8.37656 13.1429 9.14228 12.3772 9.14228 11.4286C9.14228 10.4801 8.37656 9.71434 7.42799 9.71434H3.42799V13.1429Z'
|
||||
}
|
||||
})
|
||||
} as MenuItemSpec)
|
||||
}
|
||||
|
||||
if ((type = schema.marks.em)) {
|
||||
|
@ -276,14 +228,14 @@ export function buildMenuItems(schema: Schema) {
|
|||
height: 16,
|
||||
path: 'M4.39216 0V3.42857H6.81882L3.06353 12.5714H0V16H8.78431V12.5714H6.35765L10.1129 3.42857H13.1765V0H4.39216Z'
|
||||
}
|
||||
})
|
||||
} as MenuItemSpec)
|
||||
}
|
||||
|
||||
if ((type = schema.marks.code)) {
|
||||
r.toggleCode = markItem(type, {
|
||||
title: 'Toggle code font',
|
||||
icon: icons.code
|
||||
})
|
||||
} as MenuItemSpec)
|
||||
}
|
||||
|
||||
if ((type = schema.marks.link)) r.toggleLink = linkItem(type)
|
||||
|
@ -298,7 +250,7 @@ export function buildMenuItems(schema: Schema) {
|
|||
height: 16,
|
||||
path: 'M0.000114441 1.6C0.000114441 0.714665 0.71478 0 1.60011 0C2.48544 0 3.20011 0.714665 3.20011 1.6C3.20011 2.48533 2.48544 3.19999 1.60011 3.19999C0.71478 3.19999 0.000114441 2.48533 0.000114441 1.6ZM0 8.00013C0 7.1148 0.714665 6.40014 1.6 6.40014C2.48533 6.40014 3.19999 7.1148 3.19999 8.00013C3.19999 8.88547 2.48533 9.60013 1.6 9.60013C0.714665 9.60013 0 8.88547 0 8.00013ZM1.6 12.8C0.714665 12.8 0 13.5254 0 14.4C0 15.2747 0.725332 16 1.6 16C2.47466 16 3.19999 15.2747 3.19999 14.4C3.19999 13.5254 2.48533 12.8 1.6 12.8ZM19.7333 15.4662H4.79999V13.3329H19.7333V15.4662ZM4.79999 9.06677H19.7333V6.93344H4.79999V9.06677ZM4.79999 2.66664V0.533307H19.7333V2.66664H4.79999Z'
|
||||
}
|
||||
})
|
||||
} as MenuItemSpec & { attrs: Attrs })
|
||||
}
|
||||
|
||||
if ((type = schema.nodes.ordered_list)) {
|
||||
|
@ -309,7 +261,7 @@ export function buildMenuItems(schema: Schema) {
|
|||
height: 16,
|
||||
path: 'M2.00002 4.00003H1.00001V1.00001H0V0H2.00002V4.00003ZM2.00002 13.5V13H0V12H3.00003V16H0V15H2.00002V14.5H1.00001V13.5H2.00002ZM0 6.99998H1.80002L0 9.1V10H3.00003V9H1.20001L3.00003 6.89998V5.99998H0V6.99998ZM4.9987 2.99967V0.999648H18.9988V2.99967H4.9987ZM4.9987 15.0001H18.9988V13.0001H4.9987V15.0001ZM18.9988 8.99987H4.9987V6.99986H18.9988V8.99987Z'
|
||||
}
|
||||
})
|
||||
} as MenuItemSpec & { attrs: Attrs })
|
||||
}
|
||||
|
||||
if ((type = schema.nodes.blockquote)) {
|
||||
|
@ -360,10 +312,8 @@ export function buildMenuItems(schema: Schema) {
|
|||
r.insertHorizontalRule = new MenuItem({
|
||||
label: '---',
|
||||
icon: icons.horizontal_rule,
|
||||
enable(state: any) {
|
||||
return canInsert(state, hr)
|
||||
},
|
||||
run(state: { tr: { replaceSelectionWith: (arg0: any) => any } }, dispatch: (arg0: any) => void) {
|
||||
enable: (state) => canInsert(state, hr),
|
||||
run(state: EditorState, dispatch: (tr: Transaction) => void) {
|
||||
dispatch(state.tr.replaceSelectionWith(hr.create()))
|
||||
}
|
||||
})
|
||||
|
@ -404,7 +354,7 @@ export default (): ProseMirrorExtension => ({
|
|||
...prev,
|
||||
menuBar({
|
||||
floating: true,
|
||||
content: buildMenuItems(schema).fullMenu as any[]
|
||||
content: buildMenuItems(schema).fullMenu as MenuItem | MenuItem[]
|
||||
})
|
||||
]
|
||||
})
|
||||
|
|
|
@ -64,7 +64,7 @@ const pasteMarkdown = (schema: Schema) => {
|
|||
event.preventDefault()
|
||||
|
||||
const paste = parser.parse(text)
|
||||
const slice = paste as any
|
||||
const slice = paste as Node & { openStart: number; openEnd: number }
|
||||
const fragment = shiftKey ? slice.content : transform(schema, slice.content)
|
||||
const tr = view.state.tr.replaceSelection(new Slice(fragment, slice.openStart, slice.openEnd))
|
||||
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
const prefix = 'ProseMirror-prompt'
|
||||
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
export function openPrompt(options: any) {
|
||||
export function openPrompt(options) {
|
||||
const wrapper = document.body.appendChild(document.createElement('div'))
|
||||
wrapper.className = prefix
|
||||
|
||||
const mouseOutside = (e: any) => {
|
||||
if (!wrapper.contains(e.target)) close()
|
||||
const mouseOutside = (e: MouseEvent) => {
|
||||
if (!wrapper.contains(e.target as Node)) close()
|
||||
}
|
||||
setTimeout(() => window.addEventListener('mousedown', mouseOutside), 50)
|
||||
const close = () => {
|
||||
|
@ -14,7 +13,7 @@ export function openPrompt(options: any) {
|
|||
if (wrapper.parentNode) wrapper.remove()
|
||||
}
|
||||
|
||||
const domFields: any = []
|
||||
const domFields = []
|
||||
options.fields.forEach((name) => {
|
||||
domFields.push(options.fields[name].render())
|
||||
})
|
||||
|
@ -33,7 +32,7 @@ export function openPrompt(options: any) {
|
|||
if (options.title) {
|
||||
form.appendChild(document.createElement('h5')).textContent = options.title
|
||||
}
|
||||
domFields.forEach((field: any) => {
|
||||
domFields.forEach((field) => {
|
||||
form.appendChild(document.createElement('div')).appendChild(field)
|
||||
})
|
||||
const buttons = form.appendChild(document.createElement('div'))
|
||||
|
@ -74,11 +73,11 @@ export function openPrompt(options: any) {
|
|||
}
|
||||
})
|
||||
|
||||
const input: any = form.elements[0]
|
||||
if (input) input.focus()
|
||||
const inpel = form.elements[0] as HTMLInputElement
|
||||
if (inpel) inpel.focus()
|
||||
}
|
||||
|
||||
function getValues(fields: any, domFields: any) {
|
||||
function getValues(fields, domFields) {
|
||||
const result = Object.create(null)
|
||||
let i = 0
|
||||
fields.forEarch((name) => {
|
||||
|
@ -95,7 +94,7 @@ function getValues(fields: any, domFields: any) {
|
|||
return result
|
||||
}
|
||||
|
||||
function reportInvalid(dom: any, message: any) {
|
||||
function reportInvalid(dom: HTMLElement, message: string) {
|
||||
const parent = dom.parentNode
|
||||
const msg = parent.appendChild(document.createElement('div'))
|
||||
msg.style.left = dom.offsetLeft + dom.offsetWidth + 2 + 'px'
|
||||
|
@ -106,13 +105,24 @@ function reportInvalid(dom: any, message: any) {
|
|||
setTimeout(() => parent.removeChild(msg), 1500)
|
||||
}
|
||||
|
||||
interface FieldOptions {
|
||||
options: { value: string; label: string }[]
|
||||
required: boolean
|
||||
label: string
|
||||
value: string
|
||||
validateType: (v) => boolean
|
||||
validate: (v) => boolean
|
||||
read: (v) => string
|
||||
clean: (v) => boolean
|
||||
}
|
||||
|
||||
export class Field {
|
||||
options: any
|
||||
constructor(options: any) {
|
||||
options: FieldOptions
|
||||
constructor(options) {
|
||||
this.options = options
|
||||
}
|
||||
|
||||
read(dom: any) {
|
||||
read(dom) {
|
||||
return dom.value
|
||||
}
|
||||
// :: (any) → ?string
|
||||
|
@ -121,13 +131,12 @@ export class Field {
|
|||
return typeof _value === typeof ''
|
||||
}
|
||||
|
||||
validate(value: any) {
|
||||
validate(value) {
|
||||
if (!value && this.options.required) return 'Required field'
|
||||
|
||||
return this.validateType(value) || (this.options.validate && this.options.validate(value))
|
||||
}
|
||||
|
||||
clean(value: any) {
|
||||
clean(value) {
|
||||
return this.options.clean ? this.options.clean(value) : value
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +156,7 @@ export class TextField extends Field {
|
|||
export class SelectField extends Field {
|
||||
render() {
|
||||
const select = document.createElement('select')
|
||||
this.options.options.forEach((o: { value: string; label: string }) => {
|
||||
this.options.options.forEach((o) => {
|
||||
const opt = select.appendChild(document.createElement('option'))
|
||||
opt.value = o.value
|
||||
opt.selected = o.value === this.options.value
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
import { renderGrouped } from 'prosemirror-menu'
|
||||
import { Plugin } from 'prosemirror-state'
|
||||
import { EditorState, Plugin } from 'prosemirror-state'
|
||||
import type { EditorView } from 'prosemirror-view'
|
||||
import type { ProseMirrorExtension } from '../helpers'
|
||||
import { buildMenuItems } from './menu'
|
||||
|
||||
export class SelectionTooltip {
|
||||
tooltip: any
|
||||
tooltip: HTMLElement
|
||||
|
||||
constructor(view: any, schema: any) {
|
||||
constructor(view: EditorView, schema) {
|
||||
this.tooltip = document.createElement('div')
|
||||
this.tooltip.className = 'tooltip'
|
||||
view.dom.parentNode.appendChild(this.tooltip)
|
||||
const { dom } = renderGrouped(view, (buildMenuItems(schema) as any).fullMenu)
|
||||
const { dom } = renderGrouped(view, buildMenuItems(schema).fullMenu as any)
|
||||
this.tooltip.appendChild(dom)
|
||||
this.update(view, null)
|
||||
}
|
||||
|
||||
update(view: any, lastState: any) {
|
||||
update(view: EditorView, lastState: EditorState) {
|
||||
const state = view.state
|
||||
if (lastState && lastState.doc.eq(state.doc) && lastState.selection.eq(state.selection)) {
|
||||
return
|
||||
|
@ -41,9 +42,9 @@ export class SelectionTooltip {
|
|||
}
|
||||
}
|
||||
|
||||
export function toolTip(schema: any) {
|
||||
export function toolTip(schema) {
|
||||
return new Plugin({
|
||||
view(editorView: any) {
|
||||
view(editorView: EditorView) {
|
||||
return new SelectionTooltip(editorView, schema)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
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 { keymap } from 'prosemirror-keymap'
|
||||
import type { ProseMirrorExtension } from '../helpers'
|
||||
import type OrderedMap from 'orderedmap'
|
||||
|
||||
export const tableInputRule = (schema: Schema) =>
|
||||
new InputRule(
|
||||
|
@ -174,7 +175,7 @@ const getTextSize = (n: Node) => {
|
|||
export default (): ProseMirrorExtension => ({
|
||||
schema: (prev) => ({
|
||||
...prev,
|
||||
nodes: (prev.nodes as any).append(tableSchema)
|
||||
nodes: (prev.nodes as OrderedMap<NodeSpec>).append(tableSchema as NodeSpec)
|
||||
}),
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
plugins: (prev, schema) => [
|
||||
|
|
|
@ -1,80 +1,73 @@
|
|||
import { keymap } from 'prosemirror-keymap'
|
||||
import type { ProseMirrorExtension } from './helpers'
|
||||
import { Schema } from 'prosemirror-model'
|
||||
import base from './extension/base'
|
||||
import markdown from './extension/markdown'
|
||||
import link from './extension/link'
|
||||
// import scroll from './prosemirror/extension/scroll'
|
||||
import todoList from './extension/todo-list'
|
||||
import code from './extension/code'
|
||||
import strikethrough from './extension/strikethrough'
|
||||
import placeholder from './extension/placeholder'
|
||||
// import menu from './extension/menu'
|
||||
import image from './extension/image'
|
||||
import dragHandle from './extension/drag-handle'
|
||||
import pasteMarkdown from './extension/paste-markdown'
|
||||
import table from './extension/table'
|
||||
// import scroll from './prosemirror/extension/scroll'
|
||||
import { keymap } from 'prosemirror-keymap'
|
||||
import { Schema } from 'prosemirror-model'
|
||||
import type { Command } from 'prosemirror-state'
|
||||
import { t } from '../../../utils/intl'
|
||||
import base from './extension/base'
|
||||
import code from './extension/code'
|
||||
import collab from './extension/collab'
|
||||
import type { Config, YOptions } from '../store'
|
||||
import dragHandle from './extension/drag-handle'
|
||||
import image from './extension/image'
|
||||
import link from './extension/link'
|
||||
import markdown from './extension/markdown'
|
||||
import pasteMarkdown from './extension/paste-markdown'
|
||||
import placeholder from './extension/placeholder'
|
||||
import selectionMenu from './extension/selection'
|
||||
import strikethrough from './extension/strikethrough'
|
||||
import table from './extension/table'
|
||||
import todoList from './extension/todo-list'
|
||||
import type { Config, YOptions } from '../store'
|
||||
import type { ProseMirrorExtension } from './helpers'
|
||||
|
||||
interface Props {
|
||||
interface ExtensionsProps {
|
||||
data?: unknown
|
||||
keymap?: any
|
||||
keymap?: { [key: string]: Command }
|
||||
config: Config
|
||||
markdown: boolean
|
||||
path?: string
|
||||
y?: YOptions
|
||||
schema?: Schema
|
||||
collab?: boolean
|
||||
}
|
||||
|
||||
const customKeymap = (props: Props): ProseMirrorExtension => ({
|
||||
const customKeymap = (props: ExtensionsProps): ProseMirrorExtension => ({
|
||||
plugins: (prev) => (props.keymap ? [...prev, keymap(props.keymap)] : prev)
|
||||
})
|
||||
/*
|
||||
const codeMirrorKeymap = (props: Props) => {
|
||||
const keys = []
|
||||
for (const key in props.keymap) {
|
||||
keys.push({key: key, run: props.keymap[key]})
|
||||
}
|
||||
|
||||
return cmKeymap.of(keys)
|
||||
export const createExtensions = (props: ExtensionsProps): ProseMirrorExtension[] => {
|
||||
const eee = [
|
||||
// scroll(props.config.typewriterMode),
|
||||
placeholder(t('Just start typing...')),
|
||||
customKeymap(props),
|
||||
base(props.markdown),
|
||||
selectionMenu()
|
||||
]
|
||||
if (props.markdown) {
|
||||
eee.push(
|
||||
markdown(),
|
||||
todoList(),
|
||||
dragHandle(),
|
||||
code(),
|
||||
strikethrough(),
|
||||
link(),
|
||||
table(),
|
||||
image(props.path),
|
||||
pasteMarkdown()
|
||||
/*
|
||||
codeBlock({
|
||||
theme: codeTheme(props.config),
|
||||
typewriterMode: props.config.typewriterMode,
|
||||
fontSize: props.config.fontSize,
|
||||
prettier: props.config.prettier,
|
||||
extensions: () => [codeMirrorKeymap(props)],
|
||||
}),
|
||||
*/
|
||||
)
|
||||
}
|
||||
if (props.collab) eee.push(collab(props.y))
|
||||
return eee
|
||||
}
|
||||
*/
|
||||
export const createExtensions = (props: Props): ProseMirrorExtension[] =>
|
||||
props.markdown
|
||||
? [
|
||||
placeholder('Просто начните...'),
|
||||
customKeymap(props),
|
||||
base(props.markdown),
|
||||
collab(props.y),
|
||||
selectionMenu()
|
||||
]
|
||||
: [
|
||||
selectionMenu(),
|
||||
customKeymap(props),
|
||||
base(props.markdown),
|
||||
markdown(),
|
||||
todoList(),
|
||||
dragHandle(),
|
||||
code(),
|
||||
strikethrough(),
|
||||
link(),
|
||||
table(),
|
||||
image(props.path),
|
||||
pasteMarkdown(),
|
||||
collab(props.y)
|
||||
// scroll(props.config.typewriterMode),
|
||||
/*
|
||||
codeBlock({
|
||||
theme: codeTheme(props.config),
|
||||
typewriterMode: props.config.typewriterMode,
|
||||
fontSize: props.config.fontSize,
|
||||
prettier: props.config.prettier,
|
||||
extensions: () => [codeMirrorKeymap(props)],
|
||||
}),
|
||||
*/
|
||||
]
|
||||
|
||||
export const createEmptyText = () => ({
|
||||
doc: {
|
||||
|
@ -88,7 +81,7 @@ export const createEmptyText = () => ({
|
|||
}
|
||||
})
|
||||
|
||||
export const createSchema = (props: Props) => {
|
||||
export const createSchema = (props: ExtensionsProps) => {
|
||||
const extensions = createExtensions({
|
||||
config: props.config,
|
||||
markdown: props.markdown,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Store, createStore, unwrap } from 'solid-js/store'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import type { EditorState } from 'prosemirror-state'
|
||||
import type { Command, EditorState } from 'prosemirror-state'
|
||||
import { undo, redo } from 'prosemirror-history'
|
||||
import { selectAll, deleteSelection } from 'prosemirror-commands'
|
||||
import * as Y from 'yjs'
|
||||
|
@ -23,7 +23,7 @@ const isState = (x) => typeof x.lastModified !== 'string' && Array.isArray(x.dra
|
|||
const isDraft = (x): boolean => x && (x.text || x.path)
|
||||
const mod = 'Ctrl'
|
||||
|
||||
export const createCtrl = (initial): [Store<State>, any] => {
|
||||
export const createCtrl = (initial): [Store<State>, { [key: string]: any }] => {
|
||||
const [store, setState] = createStore(initial)
|
||||
|
||||
const onNew = () => {
|
||||
|
@ -64,7 +64,7 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
[`Shift-${mod}-z`]: onRedo,
|
||||
[`${mod}-y`]: onRedo,
|
||||
[`${mod}-m`]: onToggleMarkdown
|
||||
}
|
||||
} as { [key: string]: Command }
|
||||
|
||||
const createTextFromDraft = async (d: Draft): Promise<Draft> => {
|
||||
let draft = d
|
||||
|
@ -83,7 +83,7 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
return {
|
||||
text: draft.text,
|
||||
extensions,
|
||||
updatedAt: draft.updatedAt ? new Date(draft.updatedAt) : undefined,
|
||||
lastModified: draft.lastModified ? new Date(draft.lastModified) : undefined,
|
||||
path: draft.path,
|
||||
markdown: draft.markdown
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
...drafts,
|
||||
{
|
||||
body: text,
|
||||
updatedAt: prev.updatedAt as Date,
|
||||
lastModified: prev.lastModified as Date,
|
||||
path: prev.path,
|
||||
markdown: prev.markdown
|
||||
} as Draft
|
||||
|
@ -121,7 +121,7 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
next = {
|
||||
text: createEmptyText(),
|
||||
extensions,
|
||||
updatedAt: new Date(),
|
||||
lastModified: new Date(),
|
||||
path: undefined,
|
||||
markdown: state.markdown
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
} else if (data.args.text) {
|
||||
data = await doOpenDraft(data, {
|
||||
text: { ...JSON.parse(data.args.text) },
|
||||
updatedAt: new Date()
|
||||
lastModified: new Date()
|
||||
})
|
||||
} else if (data.args.draft) {
|
||||
const draft = await loadDraft(data.config, data.args.draft)
|
||||
|
@ -258,7 +258,7 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
const loadDraft = async (config: Config, path: string): Promise<Draft> => {
|
||||
const draftstore = useStore(draftsatom)
|
||||
const draft = createMemo(() => draftstore()[path])
|
||||
const lastModified = draft().updatedAt
|
||||
const lastModified = draft().lastModified
|
||||
const draftContent = draft().body
|
||||
const schema = createSchema({
|
||||
config,
|
||||
|
@ -280,7 +280,7 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
...draft(),
|
||||
body: doc,
|
||||
text,
|
||||
updatedAt: lastModified.toISOString(),
|
||||
lastModified: lastModified.toISOString(),
|
||||
path
|
||||
}
|
||||
}
|
||||
|
@ -327,9 +327,9 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
const item = index === -1 ? draft : state.drafts[index]
|
||||
let drafts = state.drafts.filter((f) => f !== item)
|
||||
if (!isEmpty(state.text as EditorState) && state.lastModified) {
|
||||
drafts = addToDrafts(drafts, { updatedAt: new Date(), text: state.text } as Draft)
|
||||
drafts = addToDrafts(drafts, { lastModified: new Date(), text: state.text } as Draft)
|
||||
}
|
||||
draft.updatedAt = item.updatedAt
|
||||
draft.lastModified = item.lastModified
|
||||
const next = await createTextFromDraft(draft)
|
||||
|
||||
return {
|
||||
|
@ -343,7 +343,8 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
|
||||
const saveState = () =>
|
||||
debounce(async (state: State) => {
|
||||
const data: any = {
|
||||
const data: State = {
|
||||
loading: 'initialized',
|
||||
lastModified: state.lastModified,
|
||||
drafts: state.drafts,
|
||||
config: state.config,
|
||||
|
@ -357,7 +358,8 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
if (isInitialized(state.text as EditorState)) {
|
||||
if (state.path) {
|
||||
const text = serialize(store.editorView.state)
|
||||
// TODO: await remote.writeDraft(state.path, text)
|
||||
// await remote.writeDraft(state.path, text)
|
||||
draftsatom.setKey(state.path, text)
|
||||
} else {
|
||||
data.text = store.editorView.state.toJSON()
|
||||
}
|
||||
|
@ -418,7 +420,7 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
if ((backup && !isEmpty(state.text as EditorState)) || state.path) {
|
||||
let drafts = state.drafts
|
||||
if (!state.error) {
|
||||
drafts = addToDrafts(drafts, { updatedAt: new Date(), text: state.text } as Draft)
|
||||
drafts = addToDrafts(drafts, { lastModified: new Date(), text: state.text } as Draft)
|
||||
}
|
||||
|
||||
newst = {
|
||||
|
@ -455,7 +457,7 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
const editorState = store.text as EditorState
|
||||
const markdown = !state.markdown
|
||||
const selection = { type: 'text', anchor: 1, head: 1 }
|
||||
let doc: any
|
||||
let doc
|
||||
|
||||
if (markdown) {
|
||||
const lines = serialize(editorState).split('\n')
|
||||
|
@ -495,6 +497,7 @@ export const createCtrl = (initial): [Store<State>, any] => {
|
|||
extensions,
|
||||
markdown
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
const updateConfig = (config: Partial<Config>) => {
|
||||
|
|
|
@ -5,7 +5,6 @@ import type { WebrtcProvider } from 'y-webrtc'
|
|||
import type { ProseMirrorExtension, ProseMirrorState } from '../prosemirror/helpers'
|
||||
import type { EditorView } from 'prosemirror-view'
|
||||
import { createEmptyText } from '../prosemirror/setup'
|
||||
import type { Shout } from '../../../graphql/types.gen'
|
||||
|
||||
export interface Args {
|
||||
draft: string // path to draft
|
||||
|
@ -70,7 +69,7 @@ export interface State {
|
|||
|
||||
export interface Draft {
|
||||
extensions?: ProseMirrorExtension[]
|
||||
updatedAt: Date
|
||||
lastModified: Date
|
||||
body?: string
|
||||
text?: { doc: any; selection: { type: string; anchor: number; head: number } }
|
||||
path?: string
|
||||
|
|
|
@ -2,48 +2,64 @@
|
|||
@import './Sidebar';
|
||||
|
||||
.editor {
|
||||
flex: 1;
|
||||
padding-top: 1em;
|
||||
margin: 0.5em;
|
||||
padding: 1em;
|
||||
min-width: 50%;
|
||||
min-height: fit-content;
|
||||
display: inline-block;
|
||||
border: 1px dotted rgb(0 0 0 / 80%);
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
a {
|
||||
color: rgb(0 100 200);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
-webkit-padding: 0.4em 0;
|
||||
padding: 0.4em;
|
||||
margin: 0 0 0.5em;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 2px;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
input:disabled {
|
||||
color: #ccc;
|
||||
}
|
||||
a:visited {
|
||||
color: rgb(0 100 200 / 70%);
|
||||
}
|
||||
|
||||
button {
|
||||
color: #333;
|
||||
background-color: #f4f4f4;
|
||||
outline: none;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
color: #999;
|
||||
}
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
textarea {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
padding: 0.4em;
|
||||
margin: 0 0 0.5em;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
button:not(:disabled):active {
|
||||
background-color: #ddd;
|
||||
}
|
||||
input:disabled {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
border-color: #666;
|
||||
}
|
||||
button {
|
||||
color: #333;
|
||||
background-color: #f4f4f4;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
button:not(:disabled):active {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
border-color: #666;
|
||||
}
|
||||
|
||||
.ProseMirror {
|
||||
|
@ -104,17 +120,17 @@
|
|||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 2px solid;
|
||||
@include font-size(1.6rem);
|
||||
|
||||
margin: 1.5em 0;
|
||||
border-left: 2px solid;
|
||||
padding-left: 1.6em;
|
||||
}
|
||||
}
|
||||
|
||||
.ProseMirror-menuitem {
|
||||
display: flex;
|
||||
font-size: small;
|
||||
display: flex;
|
||||
|
||||
&:hover {
|
||||
> * {
|
||||
|
@ -175,7 +191,7 @@
|
|||
content: '';
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
border-top: 4px solid currentcolor;
|
||||
border-top: 4px solid draftcurrentcolor;
|
||||
opacity: 0.6;
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
|
@ -215,7 +231,7 @@
|
|||
content: '';
|
||||
border-top: 4px solid transparent;
|
||||
border-bottom: 4px solid transparent;
|
||||
border-left: 4px solid currentcolor;
|
||||
border-left: 4px solid draftcurrentcolor;
|
||||
opacity: 0.6;
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
|
@ -270,7 +286,7 @@
|
|||
}
|
||||
|
||||
.ProseMirror-icon svg {
|
||||
fill: currentcolor;
|
||||
fill: draftcurrentcolor;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
|
@ -333,7 +349,7 @@ li.ProseMirror-selectednode::after {
|
|||
|
||||
.ProseMirror-prompt {
|
||||
background: #fff;
|
||||
box-shadow: 0 4px 10px rgb(0 0 0 / 25%);
|
||||
box-shadow: 0 4px 10px rgba(0 0 0 / 25%);
|
||||
font-size: 0.7em;
|
||||
position: absolute;
|
||||
}
|
||||
|
@ -378,7 +394,7 @@ li.ProseMirror-selectednode::after {
|
|||
|
||||
.tooltip {
|
||||
background: var(--background);
|
||||
box-shadow: 0 4px 10px rgb(0 0 0 / 25%);
|
||||
box-shadow: 0 4px 10px rgba(0 0 0 / 25%);
|
||||
color: #000;
|
||||
display: flex;
|
||||
position: absolute;
|
||||
|
|
|
@ -92,10 +92,11 @@
|
|||
}
|
||||
|
||||
.sidebar-container {
|
||||
color: rgb(255 255 255 / 50%);
|
||||
font-family: Muller;
|
||||
@include font-size(1.6rem);
|
||||
|
||||
color: rgb(255 255 255 / 50%);
|
||||
font-family: Muller;
|
||||
display: inline-flex;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
top: 0;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { persistentAtom } from '@nanostores/persistent'
|
||||
import { persistentAtom, persistentMap } from '@nanostores/persistent'
|
||||
import type { Reaction } from '../graphql/types.gen'
|
||||
import { atom } from 'nanostores'
|
||||
import { createSignal } from 'solid-js'
|
||||
|
@ -18,7 +18,7 @@ interface Collab {
|
|||
title?: string
|
||||
}
|
||||
|
||||
export const drafts = persistentAtom<{ [key: string]: Draft }>(
|
||||
export const drafts = persistentMap<{ [key: string]: Draft }>(
|
||||
'drafts',
|
||||
{},
|
||||
{
|
||||
|
|
|
@ -8553,7 +8553,7 @@ ora@^6.1.0:
|
|||
strip-ansi "^7.0.1"
|
||||
wcwidth "^1.0.1"
|
||||
|
||||
orderedmap@^2.0.0:
|
||||
orderedmap@^2.0.0, orderedmap@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/orderedmap/-/orderedmap-2.1.0.tgz#819457082fa3a06abd316d83a281a1ca467437cd"
|
||||
integrity sha512-/pIFexOm6S70EPdznemIz3BQZoJ4VTFrhqzu0ACBqBgeLsLxq8e6Jim63ImIfwW/zAD1AlXpRMlOv3aghmo4dA==
|
||||
|
|
Loading…
Reference in New Issue
Block a user