@k2b/ui 0.40.0 → 0.42.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.
- package/dist/base.css +22 -0
- package/dist/browser/actions/Dropdown.js +220 -110
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/index.js.map +1 -1
- package/dist/browser/actions/menu-search.js +166 -0
- package/dist/browser/actions/menu-search.js.map +1 -0
- package/dist/browser/actions/menu-sheet.js +107 -13
- package/dist/browser/actions/menu-sheet.js.map +1 -1
- package/dist/browser/chat/ChatComposer.js +759 -570
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/content/CalendarWeekView.js +13 -1
- package/dist/browser/content/CalendarWeekView.js.map +1 -1
- package/dist/browser/inputs/ChoiceGroups.js +30 -18
- package/dist/browser/inputs/ChoiceGroups.js.map +1 -1
- package/dist/browser/inputs/IconChoices.js +121 -0
- package/dist/browser/inputs/IconChoices.js.map +1 -0
- package/dist/browser/inputs/Select.js +32 -19
- package/dist/browser/inputs/Select.js.map +1 -1
- package/dist/browser/inputs/SpecialInputs.js +54 -25
- package/dist/browser/inputs/SpecialInputs.js.map +1 -1
- package/dist/browser/inputs/choice.js +4 -1
- package/dist/browser/inputs/choice.js.map +1 -1
- package/dist/browser/inputs/dictation/Dictation.js +546 -0
- package/dist/browser/inputs/dictation/Dictation.js.map +1 -0
- package/dist/browser/inputs/dictation/create-dictation.js +324 -0
- package/dist/browser/inputs/dictation/create-dictation.js.map +1 -0
- package/dist/browser/inputs/dictation/dictation-messages.js +115 -0
- package/dist/browser/inputs/dictation/dictation-messages.js.map +1 -0
- package/dist/browser/inputs/dictation/text-dictation.js +152 -0
- package/dist/browser/inputs/dictation/text-dictation.js.map +1 -0
- package/dist/browser/inputs/dictation/types.js +2 -0
- package/dist/browser/inputs/dictation/types.js.map +1 -0
- package/dist/browser/inputs/icon-messages.js +29 -2
- package/dist/browser/inputs/icon-messages.js.map +1 -1
- package/dist/browser/inputs/icon-texts.js +172 -0
- package/dist/browser/inputs/icon-texts.js.map +1 -0
- package/dist/browser/inputs/index.js +3 -0
- package/dist/browser/inputs/index.js.map +1 -1
- package/dist/browser/intl/messages.js +6 -0
- package/dist/browser/intl/messages.js.map +1 -1
- package/dist/browser/layout/AnchoredPopover.js +1 -1
- package/dist/browser/layout/AnchoredPopover.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +118 -93
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/SettingsModal.js +10 -5
- package/dist/browser/layout/SettingsModal.js.map +1 -1
- package/dist/browser/text-editor/TextEditor.js +74 -25
- package/dist/browser/text-editor/TextEditor.js.map +1 -1
- package/dist/browser/text-editor/dictation.js +166 -0
- package/dist/browser/text-editor/dictation.js.map +1 -0
- package/dist/browser/text-editor/format.js +11 -7
- package/dist/browser/text-editor/format.js.map +1 -1
- package/dist/browser/text-editor/table.js +39 -11
- package/dist/browser/text-editor/table.js.map +1 -1
- package/dist/browser/text-editor.js +2 -1
- package/dist/browser/text-editor.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +118 -40
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/index.js.map +1 -1
- package/dist/ssr/actions/menu-search.js +113 -0
- package/dist/ssr/actions/menu-search.js.map +1 -0
- package/dist/ssr/actions/menu-sheet.js +82 -13
- package/dist/ssr/actions/menu-sheet.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +271 -99
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/content/CalendarWeekView.js +13 -1
- package/dist/ssr/content/CalendarWeekView.js.map +1 -1
- package/dist/ssr/inputs/ChoiceGroups.js +12 -3
- package/dist/ssr/inputs/ChoiceGroups.js.map +1 -1
- package/dist/ssr/inputs/IconChoices.js +59 -0
- package/dist/ssr/inputs/IconChoices.js.map +1 -0
- package/dist/ssr/inputs/Select.js +8 -2
- package/dist/ssr/inputs/Select.js.map +1 -1
- package/dist/ssr/inputs/SpecialInputs.js +54 -25
- package/dist/ssr/inputs/SpecialInputs.js.map +1 -1
- package/dist/ssr/inputs/choice.js +4 -1
- package/dist/ssr/inputs/choice.js.map +1 -1
- package/dist/ssr/inputs/dictation/Dictation.js +386 -0
- package/dist/ssr/inputs/dictation/Dictation.js.map +1 -0
- package/dist/ssr/inputs/dictation/create-dictation.js +324 -0
- package/dist/ssr/inputs/dictation/create-dictation.js.map +1 -0
- package/dist/ssr/inputs/dictation/dictation-messages.js +115 -0
- package/dist/ssr/inputs/dictation/dictation-messages.js.map +1 -0
- package/dist/ssr/inputs/dictation/text-dictation.js +152 -0
- package/dist/ssr/inputs/dictation/text-dictation.js.map +1 -0
- package/dist/ssr/inputs/dictation/types.js +2 -0
- package/dist/ssr/inputs/dictation/types.js.map +1 -0
- package/dist/ssr/inputs/icon-messages.js +29 -2
- package/dist/ssr/inputs/icon-messages.js.map +1 -1
- package/dist/ssr/inputs/icon-texts.js +172 -0
- package/dist/ssr/inputs/icon-texts.js.map +1 -0
- package/dist/ssr/inputs/index.js +3 -0
- package/dist/ssr/inputs/index.js.map +1 -1
- package/dist/ssr/intl/messages.js +6 -0
- package/dist/ssr/intl/messages.js.map +1 -1
- package/dist/ssr/layout/AnchoredPopover.js +1 -1
- package/dist/ssr/layout/AnchoredPopover.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +40 -20
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/SettingsModal.js +10 -5
- package/dist/ssr/layout/SettingsModal.js.map +1 -1
- package/dist/ssr/text-editor/TextEditor.js +74 -25
- package/dist/ssr/text-editor/TextEditor.js.map +1 -1
- package/dist/ssr/text-editor/dictation.js +166 -0
- package/dist/ssr/text-editor/dictation.js.map +1 -0
- package/dist/ssr/text-editor/format.js +11 -7
- package/dist/ssr/text-editor/format.js.map +1 -1
- package/dist/ssr/text-editor/table.js +39 -11
- package/dist/ssr/text-editor/table.js.map +1 -1
- package/dist/ssr/text-editor.js +2 -1
- package/dist/ssr/text-editor.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/Dropdown.d.ts +34 -3
- package/dist/types/actions/index.d.ts +1 -1
- package/dist/types/actions/menu-search.d.ts +27 -0
- package/dist/types/actions/menu-sheet.d.ts +5 -1
- package/dist/types/chat/ChatComposer.d.ts +9 -0
- package/dist/types/inputs/IconChoices.d.ts +19 -0
- package/dist/types/inputs/SpecialInputs.d.ts +8 -0
- package/dist/types/inputs/dictation/Dictation.d.ts +26 -0
- package/dist/types/inputs/dictation/create-dictation.d.ts +77 -0
- package/dist/types/inputs/dictation/dictation-messages.d.ts +54 -0
- package/dist/types/inputs/dictation/text-dictation.d.ts +36 -0
- package/dist/types/inputs/dictation/types.d.ts +74 -0
- package/dist/types/inputs/icon-messages.d.ts +14 -0
- package/dist/types/inputs/icon-texts.d.ts +13 -0
- package/dist/types/inputs/index.d.ts +7 -0
- package/dist/types/intl/messages.d.ts +3 -0
- package/dist/types/layout/AnchoredPopover.d.ts +5 -0
- package/dist/types/layout/AppWorkspace.d.ts +6 -1
- package/dist/types/text-editor/TextEditor.d.ts +10 -1
- package/dist/types/text-editor/dictation.d.ts +20 -0
- package/dist/types/text-editor/table.d.ts +2 -0
- package/dist/types/text-editor.d.ts +2 -1
- package/package.json +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["text-editor/dictation.ts"],"sourcesContent":["import { isolateHistory } from \"@codemirror/commands\";\nimport { type Range, type RangeSet, StateEffect, StateField, Transaction } from \"@codemirror/state\";\nimport { Decoration, type DecorationSet, EditorView, WidgetType } from \"@codemirror/view\";\nimport type { DictationTarget } from \"../inputs/dictation/types\";\n\ntype DictationState = {\n /** Where the next words land; `null` while no dictation is open. */\n mark: number | null;\n /** Every range dictation inserted, mapped through all later edits. */\n dictated: RangeSet<Decoration>;\n /** The newest words, tinted for a moment. */\n fresh: DecorationSet;\n};\n\nconst dictatedMark = Decoration.mark({ class: \"k2b-dictation-dictated\" });\nconst freshMark = (at: number) => Decoration.mark({ class: \"k2b-dictation-fresh\", at });\n\nclass MarkWidget extends WidgetType {\n override eq() {\n return true;\n }\n override toDOM() {\n const mark = document.createElement(\"span\");\n mark.className = \"k2b-dictation-mark\";\n mark.setAttribute(\"aria-hidden\", \"true\");\n return mark;\n }\n override ignoreEvent() {\n return true;\n }\n}\n\nconst open = StateEffect.define<number>();\nconst inserted = StateEffect.define<{ from: number; to: number; mark: number }>();\n/** Removes the tint of words older than the given time. */\nconst settle = StateEffect.define<number>();\nconst close = StateEffect.define<null>();\n\nconst empty: DictationState = { mark: null, dictated: Decoration.none, fresh: Decoration.none };\n\nconst dictationField = StateField.define<DictationState>({\n create: () => empty,\n update(value, tr) {\n let next: DictationState = tr.docChanged\n ? {\n // Edits elsewhere move the mark along; text typed exactly at the mark stays before the next words.\n mark: value.mark === null ? null : tr.changes.mapPos(value.mark, 1),\n dictated: value.dictated.map(tr.changes),\n fresh: value.fresh.map(tr.changes),\n }\n : value;\n for (const effect of tr.effects) {\n if (effect.is(open)) next = { ...next, mark: effect.value };\n else if (effect.is(inserted)) {\n const { from, to, mark } = effect.value;\n next = {\n mark,\n dictated: next.dictated.update({ add: [dictatedMark.range(from, to)] }),\n fresh: next.fresh.update({ add: [freshMark(Date.now()).range(from, to)] }),\n };\n } else if (effect.is(settle)) {\n const before = effect.value;\n next = { ...next, fresh: next.fresh.update({ filter: (_from, _to, value) => (value.spec.at as number) > before }) };\n } else if (effect.is(close)) next = empty;\n }\n return next;\n },\n provide: (field) => [\n EditorView.decorations.from(field, (state) => state.fresh),\n EditorView.decorations.from(field, (state) =>\n state.mark === null ? Decoration.none : Decoration.set([Decoration.widget({ widget: new MarkWidget(), side: 1 }).range(state.mark)]),\n ),\n ],\n});\n\nconst space = /\\s/;\nconst freshMs = 1_500;\n\n/** The editor state dictation needs; add it to the view that `codeMirrorDictationTarget` writes into. */\nexport const dictationExtension = () => dictationField;\n\n/**\n * A dictation target for a CodeMirror view. Words go into the document at once, as typed text does, so a shared\n * document shows them to everyone and they last as long as the host saves typed text. The mark follows local and\n * remote edits; Discard removes exactly the dictated ranges in one step, including what the person typed inside them.\n */\nexport function codeMirrorDictationTarget(editorView: () => EditorView | undefined): DictationTarget {\n /** The first words of each session get one space from earlier text, never two. */\n let sessionStart = false;\n const view = () => {\n const current = editorView();\n return current?.state.field(dictationField, false) ? current : undefined;\n };\n return {\n begin: () => {\n const current = view();\n if (!current) return;\n sessionStart = true;\n // A new session of the same dictation writes on at its mark.\n if (current.state.field(dictationField).mark !== null) return;\n current.dispatch({ effects: open.of(current.state.selection.main.head), annotations: isolateHistory.of(\"before\") });\n },\n insert: (text) => {\n const current = view();\n const mark = current?.state.field(dictationField).mark;\n // A view that turned read-only takes no more words; the host ends the dictation.\n if (!current || mark === null || mark === undefined || current.state.readOnly) return;\n let chunk = text;\n if (sessionStart) {\n const before = current.state.doc.sliceString(Math.max(0, mark - 1), mark);\n if (!before || space.test(before)) chunk = chunk.replace(/^[^\\S\\n]+/, \"\");\n else if (chunk && !space.test(chunk[0]!)) chunk = ` ${chunk}`;\n }\n if (!chunk) return;\n // The first words right before existing text keep one space to it; the mark stays before that space.\n const after = current.state.doc.sliceString(mark, mark + 1);\n const gap = sessionStart && after && !space.test(after) && !space.test(chunk[chunk.length - 1]!) ? \" \" : \"\";\n sessionStart = false;\n current.dispatch({\n changes: { from: mark, insert: chunk + gap },\n effects: inserted.of({ from: mark, to: mark + chunk.length + gap.length, mark: mark + chunk.length }),\n annotations: [Transaction.userEvent.of(\"input.dictate\"), Transaction.addToHistory.of(true)],\n });\n // Each chunk keeps its tint for the same time, also while speech goes on.\n const at = Date.now();\n setTimeout(() => view()?.dispatch({ effects: settle.of(at) }), freshMs);\n },\n discard: () => {\n const current = view();\n if (!current) return;\n const ranges: Range<Decoration>[] = [];\n const cursor = current.state.field(dictationField).dictated.iter();\n for (; cursor.value; cursor.next()) ranges.push(cursor.value.range(cursor.from, cursor.to));\n current.dispatch({\n changes: ranges.filter((range) => range.to > range.from).map((range) => ({ from: range.from, to: range.to })),\n effects: close.of(null),\n annotations: [Transaction.userEvent.of(\"delete.dictate\"), isolateHistory.of(\"full\")],\n });\n },\n end: () => {\n view()?.dispatch({ effects: close.of(null), annotations: isolateHistory.of(\"after\") });\n },\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -81,7 +81,7 @@ const linePrefix = (pattern, prefix) => view => {
|
|
|
81
81
|
const lines = new Set();
|
|
82
82
|
for (const r of state.selection.ranges) for (let n = state.doc.lineAt(r.from).number; n <= state.doc.lineAt(r.to).number; n++) lines.add(n);
|
|
83
83
|
const all = [...lines].every(n => pattern.test(state.doc.line(n).text));
|
|
84
|
-
const changes = [...lines].map(n => {
|
|
84
|
+
const changes = state.changes([...lines].map(n => {
|
|
85
85
|
const line = state.doc.line(n);
|
|
86
86
|
const m = pattern.exec(line.text);
|
|
87
87
|
return all && m ? {
|
|
@@ -91,9 +91,11 @@ const linePrefix = (pattern, prefix) => view => {
|
|
|
91
91
|
from: line.from,
|
|
92
92
|
insert: prefix(state, n)
|
|
93
93
|
};
|
|
94
|
-
});
|
|
94
|
+
}));
|
|
95
|
+
// A caret at the line start follows the new prefix, so the next typed letter lands after it.
|
|
95
96
|
view.dispatch({
|
|
96
97
|
changes,
|
|
98
|
+
selection: state.selection.map(changes, 1),
|
|
97
99
|
userEvent: "input.format"
|
|
98
100
|
});
|
|
99
101
|
view.focus();
|
|
@@ -109,12 +111,14 @@ const heading = level => view => {
|
|
|
109
111
|
const prefix = `${"#".repeat(level)} `;
|
|
110
112
|
const lines = [...numbers].sort((a, b) => a - b).map(number => state.doc.line(number));
|
|
111
113
|
const remove = lines.every(line => line.text.startsWith(prefix));
|
|
114
|
+
const changes = state.changes(lines.map(line => ({
|
|
115
|
+
from: line.from,
|
|
116
|
+
to: line.from + (/^#{1,6} /.exec(line.text)?.[0].length ?? 0),
|
|
117
|
+
insert: remove ? "" : prefix
|
|
118
|
+
})));
|
|
112
119
|
view.dispatch({
|
|
113
|
-
changes
|
|
114
|
-
|
|
115
|
-
to: line.from + (/^#{1,6} /.exec(line.text)?.[0].length ?? 0),
|
|
116
|
-
insert: remove ? "" : prefix
|
|
117
|
-
})),
|
|
120
|
+
changes,
|
|
121
|
+
selection: state.selection.map(changes, 1),
|
|
118
122
|
userEvent: "input.format"
|
|
119
123
|
});
|
|
120
124
|
view.focus();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["text-editor/format.ts"],"sourcesContent":["/** Toolbar and keyboard commands. Each one is a plain Markdown edit of the selection. */\nimport { EditorSelection, type EditorState, Facet, type TransactionSpec } from \"@codemirror/state\";\nimport type { EditorView } from \"@codemirror/view\";\n\n/** Insertion text follows the editor's inherited locale, including keyboard commands. */\nexport const formatLabels = Facet.define<\n { link: string; column: (column: number) => string },\n { link: string; column: (column: number) => string }\n>({\n combine: (values) => values[0] ?? { link: \"Link\", column: (column) => `Column ${column}` },\n});\n\n/** Named Markdown marks or an app's single-line paired delimiter (for example Notebook's `==`). */\nexport type InlineFormat = \"bold\" | \"italic\" | \"code\" | \"strike\" | \"link\" | { marker: string };\n/** Pure transaction spec, also used when a missing table cell must be materialized atomically. */\nexport const inlineFormat = (state: EditorState, name: InlineFormat): TransactionSpec => {\n if (name === \"link\") {\n const { from, to } = state.selection.main;\n const label = state.sliceDoc(from, to) || state.facet(formatLabels).link;\n return {\n changes: { from, to, insert: `[${label}](https://)` },\n selection: { anchor: from + label.length + 3, head: from + label.length + 11 },\n userEvent: \"input.format\",\n };\n }\n const marker = typeof name === \"string\" ? { bold: \"**\", italic: \"*\", code: \"`\", strike: \"~~\" }[name] : name.marker;\n // A host inline delimiter must not split a cell or introduce another row.\n if (!marker || /[|\\r\\n]/.test(marker)) return {};\n return {\n ...state.changeByRange((range) => {\n const text = state.sliceDoc(range.from, range.to);\n const before = state.sliceDoc(Math.max(0, range.from - marker.length), range.from);\n const after = state.sliceDoc(range.to, Math.min(state.doc.length, range.to + marker.length));\n const italicBoundary =\n name !== \"italic\" ||\n ((/\\*+$/.exec(state.sliceDoc(state.doc.lineAt(range.from).from, range.from))?.[0].length ?? 0) % 2 === 1 &&\n (/^\\*+/.exec(state.sliceDoc(range.to, state.doc.lineAt(range.to).to))?.[0].length ?? 0) % 2 === 1);\n if (before === marker && after === marker && italicBoundary)\n return {\n changes: [\n { from: range.from - marker.length, to: range.from },\n { from: range.to, to: range.to + marker.length },\n ],\n range: EditorSelection.range(range.from - marker.length, range.to - marker.length),\n };\n return {\n changes: { from: range.from, to: range.to, insert: `${marker}${text}${marker}` },\n range: EditorSelection.range(range.from + marker.length, range.to + marker.length),\n };\n }),\n userEvent: \"input.format\",\n };\n};\nconst inlineCommand = (name: InlineFormat) => (view: EditorView) => {\n if (view.state.readOnly) return false;\n view.dispatch(inlineFormat(view.state, name));\n view.focus();\n return true;\n};\n\nconst linePrefix = (pattern: RegExp, prefix: (state: EditorState, n: number) => string) => (view: EditorView) => {\n if (view.state.readOnly) return false;\n const { state } = view;\n const lines = new Set<number>();\n for (const r of state.selection.ranges)\n for (let n = state.doc.lineAt(r.from).number; n <= state.doc.lineAt(r.to).number; n++) lines.add(n);\n const all = [...lines].every((n) => pattern.test(state.doc.line(n).text));\n const changes = [...lines].map((n) => {\n const line = state.doc.line(n);\n const m = pattern.exec(line.text);\n return all && m ? { from: line.from, to: line.from + m[0].length } : { from: line.from, insert: prefix(state, n) };\n });\n view.dispatch({ changes, userEvent: \"input.format\" });\n view.focus();\n return true;\n};\n\nconst heading = (level: number) => (view: EditorView) => {\n if (view.state.readOnly) return false;\n const { state } = view;\n const numbers = new Set<number>();\n for (const range of state.selection.ranges)\n for (let n = state.doc.lineAt(range.from).number; n <= state.doc.lineAt(range.to).number; n++) numbers.add(n);\n const prefix = `${\"#\".repeat(level)} `;\n const lines = [...numbers].sort((a, b) => a - b).map((number) => state.doc.line(number));\n const remove = lines.every((line) => line.text.startsWith(prefix));\n view.dispatch({\n changes: lines.map((line) => ({\n from: line.from,\n to: line.from + (/^#{1,6} /.exec(line.text)?.[0].length ?? 0),\n insert: remove ? \"\" : prefix,\n })),\n userEvent: \"input.format\",\n });\n view.focus();\n return true;\n};\n\nexport const commands = {\n bold: inlineCommand(\"bold\"),\n italic: inlineCommand(\"italic\"),\n code: inlineCommand(\"code\"),\n strike: inlineCommand(\"strike\"),\n heading: heading(2),\n heading1: heading(1),\n heading2: heading(2),\n heading3: heading(3),\n codeBlock: (view: EditorView) => {\n if (view.state.readOnly) return false;\n const { state } = view;\n const from = state.doc.lineAt(state.selection.main.from).from;\n const to = state.doc.lineAt(state.selection.main.to).to;\n const text = state.sliceDoc(from, to);\n let fenceLength = 3;\n for (const match of text.matchAll(/`+/g)) fenceLength = Math.max(fenceLength, match[0].length + 1);\n const fence = \"`\".repeat(fenceLength);\n const lead = from > 0 && state.doc.lineAt(from - 1).length ? \"\\n\" : \"\";\n const tail = to < state.doc.length && state.doc.lineAt(to + 1).length ? \"\\n\" : \"\";\n const start = from + lead.length + fence.length + 1;\n view.dispatch({\n changes: { from, to, insert: `${lead}${fence}\\n${text}\\n${fence}${tail}` },\n selection: { anchor: start, head: start + text.length },\n userEvent: \"input.format\",\n });\n view.focus();\n return true;\n },\n bulletList: linePrefix(/^\\s*[-*] /, () => \"- \"),\n orderedList: linePrefix(/^\\s*\\d+\\. /, () => \"1. \"),\n quote: linePrefix(/^> ?/, () => \"> \"),\n link: inlineCommand(\"link\"),\n table: (view: EditorView) => {\n if (view.state.readOnly) return false;\n const { from } = view.state.selection.main;\n const line = view.state.doc.lineAt(from);\n const lead = line.length ? \"\\n\\n\" : \"\";\n const labels = view.state.facet(formatLabels);\n const first = labels.column(1);\n const insert = `${lead}| ${first} | ${labels.column(2)} |\\n| --- | --- |\\n| | |\\n`;\n const anchor = line.to + lead.length + 2;\n view.dispatch({ changes: { from: line.to, insert }, selection: { anchor, head: anchor + first.length }, userEvent: \"input.format\" });\n view.focus();\n queueMicrotask(() => {\n if (!view.dom.isConnected) return;\n const table = [...view.contentDOM.querySelectorAll<HTMLElement>(\".k2b-ste-table\")].find(\n (element) => view.posAtDOM(element) === line.to + lead.length,\n );\n const cell = table?.querySelector<HTMLElement>('.k2b-ste-cell[data-r=\"0\"][data-c=\"0\"]');\n if (!cell) return;\n cell.focus();\n const selection = cell.ownerDocument.getSelection();\n const range = cell.ownerDocument.createRange();\n range.selectNodeContents(cell);\n selection?.removeAllRanges();\n selection?.addRange(range);\n });\n return true;\n },\n rule: (view: EditorView) => {\n if (view.state.readOnly) return false;\n const line = view.state.doc.lineAt(view.state.selection.main.from);\n const previousHasText = line.number > 1 && view.state.doc.line(line.number - 1).text.trim().length > 0;\n const lead = line.length ? \"\\n\\n\" : previousHasText ? \"\\n\" : \"\";\n view.dispatch({ changes: { from: line.to, insert: `${lead}---\\n` }, userEvent: \"input.format\" });\n view.focus();\n return true;\n },\n};\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["text-editor/format.ts"],"sourcesContent":["/** Toolbar and keyboard commands. Each one is a plain Markdown edit of the selection. */\nimport { EditorSelection, type EditorState, Facet, type TransactionSpec } from \"@codemirror/state\";\nimport type { EditorView } from \"@codemirror/view\";\n\n/** Insertion text follows the editor's inherited locale, including keyboard commands. */\nexport const formatLabels = Facet.define<\n { link: string; column: (column: number) => string },\n { link: string; column: (column: number) => string }\n>({\n combine: (values) => values[0] ?? { link: \"Link\", column: (column) => `Column ${column}` },\n});\n\n/** Named Markdown marks or an app's single-line paired delimiter (for example Notebook's `==`). */\nexport type InlineFormat = \"bold\" | \"italic\" | \"code\" | \"strike\" | \"link\" | { marker: string };\n/** Pure transaction spec, also used when a missing table cell must be materialized atomically. */\nexport const inlineFormat = (state: EditorState, name: InlineFormat): TransactionSpec => {\n if (name === \"link\") {\n const { from, to } = state.selection.main;\n const label = state.sliceDoc(from, to) || state.facet(formatLabels).link;\n return {\n changes: { from, to, insert: `[${label}](https://)` },\n selection: { anchor: from + label.length + 3, head: from + label.length + 11 },\n userEvent: \"input.format\",\n };\n }\n const marker = typeof name === \"string\" ? { bold: \"**\", italic: \"*\", code: \"`\", strike: \"~~\" }[name] : name.marker;\n // A host inline delimiter must not split a cell or introduce another row.\n if (!marker || /[|\\r\\n]/.test(marker)) return {};\n return {\n ...state.changeByRange((range) => {\n const text = state.sliceDoc(range.from, range.to);\n const before = state.sliceDoc(Math.max(0, range.from - marker.length), range.from);\n const after = state.sliceDoc(range.to, Math.min(state.doc.length, range.to + marker.length));\n const italicBoundary =\n name !== \"italic\" ||\n ((/\\*+$/.exec(state.sliceDoc(state.doc.lineAt(range.from).from, range.from))?.[0].length ?? 0) % 2 === 1 &&\n (/^\\*+/.exec(state.sliceDoc(range.to, state.doc.lineAt(range.to).to))?.[0].length ?? 0) % 2 === 1);\n if (before === marker && after === marker && italicBoundary)\n return {\n changes: [\n { from: range.from - marker.length, to: range.from },\n { from: range.to, to: range.to + marker.length },\n ],\n range: EditorSelection.range(range.from - marker.length, range.to - marker.length),\n };\n return {\n changes: { from: range.from, to: range.to, insert: `${marker}${text}${marker}` },\n range: EditorSelection.range(range.from + marker.length, range.to + marker.length),\n };\n }),\n userEvent: \"input.format\",\n };\n};\nconst inlineCommand = (name: InlineFormat) => (view: EditorView) => {\n if (view.state.readOnly) return false;\n view.dispatch(inlineFormat(view.state, name));\n view.focus();\n return true;\n};\n\nconst linePrefix = (pattern: RegExp, prefix: (state: EditorState, n: number) => string) => (view: EditorView) => {\n if (view.state.readOnly) return false;\n const { state } = view;\n const lines = new Set<number>();\n for (const r of state.selection.ranges)\n for (let n = state.doc.lineAt(r.from).number; n <= state.doc.lineAt(r.to).number; n++) lines.add(n);\n const all = [...lines].every((n) => pattern.test(state.doc.line(n).text));\n const changes = state.changes(\n [...lines].map((n) => {\n const line = state.doc.line(n);\n const m = pattern.exec(line.text);\n return all && m ? { from: line.from, to: line.from + m[0].length } : { from: line.from, insert: prefix(state, n) };\n }),\n );\n // A caret at the line start follows the new prefix, so the next typed letter lands after it.\n view.dispatch({ changes, selection: state.selection.map(changes, 1), userEvent: \"input.format\" });\n view.focus();\n return true;\n};\n\nconst heading = (level: number) => (view: EditorView) => {\n if (view.state.readOnly) return false;\n const { state } = view;\n const numbers = new Set<number>();\n for (const range of state.selection.ranges)\n for (let n = state.doc.lineAt(range.from).number; n <= state.doc.lineAt(range.to).number; n++) numbers.add(n);\n const prefix = `${\"#\".repeat(level)} `;\n const lines = [...numbers].sort((a, b) => a - b).map((number) => state.doc.line(number));\n const remove = lines.every((line) => line.text.startsWith(prefix));\n const changes = state.changes(\n lines.map((line) => ({\n from: line.from,\n to: line.from + (/^#{1,6} /.exec(line.text)?.[0].length ?? 0),\n insert: remove ? \"\" : prefix,\n })),\n );\n view.dispatch({ changes, selection: state.selection.map(changes, 1), userEvent: \"input.format\" });\n view.focus();\n return true;\n};\n\nexport const commands = {\n bold: inlineCommand(\"bold\"),\n italic: inlineCommand(\"italic\"),\n code: inlineCommand(\"code\"),\n strike: inlineCommand(\"strike\"),\n heading: heading(2),\n heading1: heading(1),\n heading2: heading(2),\n heading3: heading(3),\n codeBlock: (view: EditorView) => {\n if (view.state.readOnly) return false;\n const { state } = view;\n const from = state.doc.lineAt(state.selection.main.from).from;\n const to = state.doc.lineAt(state.selection.main.to).to;\n const text = state.sliceDoc(from, to);\n let fenceLength = 3;\n for (const match of text.matchAll(/`+/g)) fenceLength = Math.max(fenceLength, match[0].length + 1);\n const fence = \"`\".repeat(fenceLength);\n const lead = from > 0 && state.doc.lineAt(from - 1).length ? \"\\n\" : \"\";\n const tail = to < state.doc.length && state.doc.lineAt(to + 1).length ? \"\\n\" : \"\";\n const start = from + lead.length + fence.length + 1;\n view.dispatch({\n changes: { from, to, insert: `${lead}${fence}\\n${text}\\n${fence}${tail}` },\n selection: { anchor: start, head: start + text.length },\n userEvent: \"input.format\",\n });\n view.focus();\n return true;\n },\n bulletList: linePrefix(/^\\s*[-*] /, () => \"- \"),\n orderedList: linePrefix(/^\\s*\\d+\\. /, () => \"1. \"),\n quote: linePrefix(/^> ?/, () => \"> \"),\n link: inlineCommand(\"link\"),\n table: (view: EditorView) => {\n if (view.state.readOnly) return false;\n const { from } = view.state.selection.main;\n const line = view.state.doc.lineAt(from);\n const lead = line.length ? \"\\n\\n\" : \"\";\n const labels = view.state.facet(formatLabels);\n const first = labels.column(1);\n const insert = `${lead}| ${first} | ${labels.column(2)} |\\n| --- | --- |\\n| | |\\n`;\n const anchor = line.to + lead.length + 2;\n view.dispatch({ changes: { from: line.to, insert }, selection: { anchor, head: anchor + first.length }, userEvent: \"input.format\" });\n view.focus();\n queueMicrotask(() => {\n if (!view.dom.isConnected) return;\n const table = [...view.contentDOM.querySelectorAll<HTMLElement>(\".k2b-ste-table\")].find(\n (element) => view.posAtDOM(element) === line.to + lead.length,\n );\n const cell = table?.querySelector<HTMLElement>('.k2b-ste-cell[data-r=\"0\"][data-c=\"0\"]');\n if (!cell) return;\n cell.focus();\n const selection = cell.ownerDocument.getSelection();\n const range = cell.ownerDocument.createRange();\n range.selectNodeContents(cell);\n selection?.removeAllRanges();\n selection?.addRange(range);\n });\n return true;\n },\n rule: (view: EditorView) => {\n if (view.state.readOnly) return false;\n const line = view.state.doc.lineAt(view.state.selection.main.from);\n const previousHasText = line.number > 1 && view.state.doc.line(line.number - 1).text.trim().length > 0;\n const lead = line.length ? \"\\n\\n\" : previousHasText ? \"\\n\" : \"\";\n view.dispatch({ changes: { from: line.to, insert: `${lead}---\\n` }, userEvent: \"input.format\" });\n view.focus();\n return true;\n },\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -123,7 +123,7 @@ const escapeHtml = s => s.replace(/[&<>"]/g, ch => `&${{
|
|
|
123
123
|
'"': "quot"
|
|
124
124
|
}[ch]};`);
|
|
125
125
|
/** Render the same Markdown tokens as prose, keeping code and escaped markers literal. */
|
|
126
|
-
const renderInline = raw => {
|
|
126
|
+
export const renderInline = raw => {
|
|
127
127
|
const text = raw;
|
|
128
128
|
const tree = markdownLanguage.parser.parse(text);
|
|
129
129
|
const render = node => {
|
|
@@ -189,6 +189,9 @@ const hasHeader = t => t.lines[0].cells.some(cell => cell.text.length > 0);
|
|
|
189
189
|
const firstRow = t => hasHeader(t) ? 0 : 1;
|
|
190
190
|
const shapeOf = t => `${T.rowCount(t)}x${width(t)}:${firstRow(t)}`;
|
|
191
191
|
const renderedDocuments = new WeakMap();
|
|
192
|
+
/** The height a table was last drawn with, handed from widget to widget while its shape stays. */
|
|
193
|
+
|
|
194
|
+
const drawnHeights = new WeakMap();
|
|
192
195
|
/**
|
|
193
196
|
* How far the grid may reach left of the text: its grip gutter and the first
|
|
194
197
|
* cell's padding sit there, so cell text lines up with the paragraphs. It
|
|
@@ -213,25 +216,31 @@ const measureScroll = (view, wrap) => view.requestMeasure({
|
|
|
213
216
|
left: wrap.scrollLeft,
|
|
214
217
|
width: wrap.clientWidth,
|
|
215
218
|
total: wrap.scrollWidth,
|
|
216
|
-
bleed: bleed(view, wrap)
|
|
219
|
+
bleed: bleed(view, wrap),
|
|
220
|
+
height: wrap.getBoundingClientRect().height / view.scaleY
|
|
217
221
|
}),
|
|
218
222
|
write: ({
|
|
219
223
|
left,
|
|
220
224
|
width,
|
|
221
225
|
total,
|
|
222
|
-
bleed
|
|
226
|
+
bleed,
|
|
227
|
+
height
|
|
223
228
|
}) => {
|
|
224
229
|
if (!wrap.isConnected) return;
|
|
230
|
+
const drawn = drawnHeights.get(wrap);
|
|
231
|
+
// A hidden editor has no height to remember.
|
|
232
|
+
if (drawn && height > 0) drawn.height = height;
|
|
225
233
|
wrap.toggleAttribute("data-scrolled", left > 0);
|
|
226
234
|
wrap.toggleAttribute("data-more", left + width < total - 1);
|
|
227
235
|
wrap.style.setProperty("--k2b-ste-bleed", `${bleed}px`);
|
|
228
236
|
}
|
|
229
237
|
});
|
|
230
238
|
class GridWidget extends WidgetType {
|
|
231
|
-
constructor(table, readOnly) {
|
|
239
|
+
constructor(table, readOnly, drawn) {
|
|
232
240
|
super();
|
|
233
241
|
this.table = table;
|
|
234
242
|
this.readOnly = readOnly;
|
|
243
|
+
this.drawn = drawn;
|
|
235
244
|
}
|
|
236
245
|
// Always update the existing DOM on document/refresh transactions. A shape
|
|
237
246
|
// deferred during composition must be patched even when the next table value
|
|
@@ -250,12 +259,14 @@ class GridWidget extends WidgetType {
|
|
|
250
259
|
wrap.toggleAttribute("data-more", wrap.scrollLeft + wrap.clientWidth < wrap.scrollWidth - 1);
|
|
251
260
|
});
|
|
252
261
|
renderedDocuments.set(wrap, view.state.doc);
|
|
262
|
+
drawnHeights.set(wrap, this.drawn);
|
|
253
263
|
setEditable(wrap, !this.readOnly, view);
|
|
254
264
|
measureScroll(view, wrap);
|
|
255
265
|
return wrap;
|
|
256
266
|
}
|
|
257
267
|
updateDOM(dom, view) {
|
|
258
268
|
const act = active.get(view);
|
|
269
|
+
drawnHeights.set(dom, this.drawn);
|
|
259
270
|
measureScroll(view, dom);
|
|
260
271
|
if (dom.dataset.shape !== shapeOf(this.table)) {
|
|
261
272
|
const focused = dom.contains(document.activeElement) ? document.activeElement : null;
|
|
@@ -311,8 +322,10 @@ class GridWidget extends WidgetType {
|
|
|
311
322
|
ignoreEvent() {
|
|
312
323
|
return true;
|
|
313
324
|
}
|
|
325
|
+
// Every rebuild replaces the widget, and CodeMirror then takes this height for tables outside the drawn range too.
|
|
326
|
+
// A guess there would shift every line below them, so a table that was drawn keeps its real height.
|
|
314
327
|
get estimatedHeight() {
|
|
315
|
-
return (T.rowCount(this.table) - firstRow(this.table)) * 41 + 16;
|
|
328
|
+
return this.drawn.height ?? (T.rowCount(this.table) - firstRow(this.table)) * 41 + 16;
|
|
316
329
|
}
|
|
317
330
|
}
|
|
318
331
|
const sources = new WeakMap();
|
|
@@ -1756,10 +1769,25 @@ export const htmlTableGrid = html => {
|
|
|
1756
1769
|
const rows = [...table.querySelectorAll("tr")].map(tr => [...tr.querySelectorAll("th,td")].map(cell => (cell.textContent ?? "").replace(/\s+/g, " ").trim()));
|
|
1757
1770
|
return rows.filter(row => row.length).length ? rows.filter(row => row.length) : null;
|
|
1758
1771
|
};
|
|
1759
|
-
const decorate = state
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1772
|
+
const decorate = (state, previous = Decoration.none, changes) => {
|
|
1773
|
+
const drawn = new Map();
|
|
1774
|
+
for (const cursor = previous.iter(); cursor.value; cursor.next()) {
|
|
1775
|
+
const widget = cursor.value.spec.widget;
|
|
1776
|
+
if (widget instanceof GridWidget) drawn.set(changes ? changes.mapPos(cursor.from, 1) : cursor.from, widget.drawn);
|
|
1777
|
+
}
|
|
1778
|
+
return Decoration.set(tablesIn(state).map(t => {
|
|
1779
|
+
const shape = shapeOf(t);
|
|
1780
|
+
const known = drawn.get(t.from);
|
|
1781
|
+
const widget = new GridWidget(t, state.readOnly, known?.shape === shape ? known : {
|
|
1782
|
+
shape,
|
|
1783
|
+
height: null
|
|
1784
|
+
});
|
|
1785
|
+
return Decoration.replace({
|
|
1786
|
+
widget,
|
|
1787
|
+
block: true
|
|
1788
|
+
}).range(t.from, t.to);
|
|
1789
|
+
}), true);
|
|
1790
|
+
};
|
|
1763
1791
|
export const tableGrid = () => [clipboardLoading(view => view.state.facet(tableHost), syncCellSelection), Prec.highest(keymap.of([{
|
|
1764
1792
|
key: "ArrowDown",
|
|
1765
1793
|
run: view => enterTable(view, true)
|
|
@@ -1790,8 +1818,8 @@ export const tableGrid = () => [clipboardLoading(view => view.state.facet(tableH
|
|
|
1790
1818
|
}
|
|
1791
1819
|
};
|
|
1792
1820
|
}), StateField.define({
|
|
1793
|
-
create: decorate,
|
|
1794
|
-
update: (value, tr) => tr.docChanged || tr.effects.some(e => e.is(refreshTables)) || tr.startState.readOnly !== tr.state.readOnly || syntaxTree(tr.startState) !== syntaxTree(tr.state) ? decorate(tr.state) : value,
|
|
1821
|
+
create: state => decorate(state),
|
|
1822
|
+
update: (value, tr) => tr.docChanged || tr.effects.some(e => e.is(refreshTables)) || tr.startState.readOnly !== tr.state.readOnly || syntaxTree(tr.startState) !== syntaxTree(tr.state) ? decorate(tr.state, value, tr.changes) : value,
|
|
1795
1823
|
provide: field => [EditorView.decorations.from(field), EditorView.atomicRanges.of(view => view.state.field(field))]
|
|
1796
1824
|
}), followChanges];
|
|
1797
1825
|
//# sourceMappingURL=table.js.map
|