@k2b/editor 0.0.0 → 0.1.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.
Files changed (83) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +32 -1
  3. package/package.json +116 -4
  4. package/src/BubbleMenu.tsx +126 -0
  5. package/src/Editor.tsx +32 -0
  6. package/src/SlashMenu.tsx +13 -0
  7. package/src/Toolbar.tsx +205 -0
  8. package/src/actions.ts +102 -0
  9. package/src/chart-schema.ts +274 -0
  10. package/src/charts.ts +710 -0
  11. package/src/collab/history.ts +39 -0
  12. package/src/collab/index.ts +32 -0
  13. package/src/collab/relative-cursor.ts +18 -0
  14. package/src/collab/remote-cursors.ts +358 -0
  15. package/src/editor-state.ts +199 -0
  16. package/src/formula.ts +1283 -0
  17. package/src/index.ts +16 -0
  18. package/src/markdown/_lib/cursor-zone-field.ts +338 -0
  19. package/src/markdown/_lib/inline-syntax.ts +9 -0
  20. package/src/markdown/_lib/link-opener.ts +50 -0
  21. package/src/markdown/_lib/list-item-line.ts +34 -0
  22. package/src/markdown/_lib/list-structure.ts +227 -0
  23. package/src/markdown/_lib/math-syntax.ts +3 -0
  24. package/src/markdown/_lib/table-cell.ts +74 -0
  25. package/src/markdown/basic.ts +37 -0
  26. package/src/markdown/block-previews.tsx +453 -0
  27. package/src/markdown/chart-block-messages.ts +5 -0
  28. package/src/markdown/chart-copy.ts +20 -0
  29. package/src/markdown/code-fence-snippets.ts +167 -0
  30. package/src/markdown/code-font.ts +54 -0
  31. package/src/markdown/completion-icon.ts +9 -0
  32. package/src/markdown/data-block-template.ts +11 -0
  33. package/src/markdown/data-blocks.ts +214 -0
  34. package/src/markdown/editor-scope.ts +92 -0
  35. package/src/markdown/fade-scroll-margins.browser-harness.ts +78 -0
  36. package/src/markdown/fade-scroll-margins.ts +25 -0
  37. package/src/markdown/image-syntax.ts +26 -0
  38. package/src/markdown/images.ts +192 -0
  39. package/src/markdown/index.ts +54 -0
  40. package/src/markdown/info-block-snippets.ts +159 -0
  41. package/src/markdown/info-blocks.ts +156 -0
  42. package/src/markdown/katex.ts +303 -0
  43. package/src/markdown/lib/chart-blocks.ts +511 -0
  44. package/src/markdown/lib/heading-anchors.ts +40 -0
  45. package/src/markdown/lib/ligatures.ts +107 -0
  46. package/src/markdown/lib/markdown-context.ts +72 -0
  47. package/src/markdown/lib/markdown-fences.ts +22 -0
  48. package/src/markdown/lib/markdown-image.fixtures.ts +20 -0
  49. package/src/markdown/lib/markdown-image.ts +36 -0
  50. package/src/markdown/lib/named-blocks.ts +403 -0
  51. package/src/markdown/lib/query-blocks.ts +145 -0
  52. package/src/markdown/ligatures.ts +223 -0
  53. package/src/markdown/links.ts +158 -0
  54. package/src/markdown/list-commands.ts +1124 -0
  55. package/src/markdown/lists.ts +290 -0
  56. package/src/markdown/mark.ts +103 -0
  57. package/src/markdown/markdown.ts +78 -0
  58. package/src/markdown/markup.ts +385 -0
  59. package/src/markdown/mermaid-export.ts +78 -0
  60. package/src/markdown/mermaid-preview.tsx +76 -0
  61. package/src/markdown/mermaid-render.ts +22 -0
  62. package/src/markdown/mermaid-viewport.tsx +78 -0
  63. package/src/markdown/mermaid.ts +242 -0
  64. package/src/markdown/messages.ts +17 -0
  65. package/src/markdown/named-blocks.ts +84 -0
  66. package/src/markdown/note-scroller.browser-harness.ts +84 -0
  67. package/src/markdown/note-scroller.ts +57 -0
  68. package/src/markdown/notebook-charts.tsx +142 -0
  69. package/src/markdown/pretty-table-messages.ts +33 -0
  70. package/src/markdown/pretty-table.ts +220 -0
  71. package/src/markdown/search-theme.ts +98 -0
  72. package/src/markdown/shared-tables.ts +286 -0
  73. package/src/markdown/sub-sup.ts +115 -0
  74. package/src/markdown/surface-press.ts +17 -0
  75. package/src/markdown/tab-indent.ts +104 -0
  76. package/src/markdown/table-columns.ts +188 -0
  77. package/src/markdown/table-formulas.ts +178 -0
  78. package/src/markdown/tables.ts +703 -0
  79. package/src/markdown/theme.ts +243 -0
  80. package/src/markdown/urls.ts +29 -0
  81. package/src/messages.ts +45 -0
  82. package/src/slash-menu.ts +220 -0
  83. package/src/styles.css +376 -0
package/src/styles.css ADDED
@@ -0,0 +1,376 @@
1
+ /* Generate utility classes for the source package in the consuming Tailwind build. */
2
+ @source "./**/*.{ts,tsx}";
3
+
4
+ /* ── Slash-command autocomplete palette ─────────────────────────────────
5
+ The CodeMirror autocomplete tooltip is portaled outside the editor
6
+ surface AND its theme is injected as a runtime `<style>` after this file
7
+ loads. Equal-specificity rules lose to CM's defaults (filled `aria-selected`
8
+ background, hardcoded option padding, section dividers) — so the overrides
9
+ below use `!important` for the bits that fight CM directly.
10
+
11
+ Visual baseline = the platform `Select` component (see
12
+ `@k2b/ui` Select): popup-style container, no
13
+ filled-background selected state — just `text-primary` + underline. */
14
+
15
+ .cm-tooltip.cm-tooltip-autocomplete {
16
+ /* `popup` utility: rounded-lg, white/zinc-900 bg, zinc-200/800 border,
17
+ shadow-lg. Sized to feel like the platform Select dropdown — but
18
+ compact-density per-row so a dozen suggestions fit in the
19
+ viewport without scrolling. */
20
+ border-radius: 0.5rem !important;
21
+ background-color: white !important;
22
+ border: 1px solid rgb(228 228 231) !important;
23
+ box-shadow: var(--ui-shadow-float) !important;
24
+ padding: 0.1875rem !important;
25
+ min-width: 22rem;
26
+ font-family: inherit !important;
27
+ font-size: 0.75rem !important;
28
+ overflow: hidden;
29
+ }
30
+ .dark .cm-tooltip.cm-tooltip-autocomplete {
31
+ background-color: rgb(24 24 27) !important;
32
+ border-color: rgb(39 39 42) !important;
33
+ }
34
+
35
+ .cm-tooltip-autocomplete > ul {
36
+ font-family: inherit !important;
37
+ max-height: 28rem;
38
+ padding: 0 !important;
39
+ margin: 0;
40
+ list-style: none;
41
+ }
42
+
43
+ .cm-tooltip-autocomplete > ul > li {
44
+ display: flex !important;
45
+ align-items: center;
46
+ gap: 0.5rem;
47
+ padding: 0.1875rem 0.375rem !important;
48
+ border-radius: 0.25rem;
49
+ /* Default colour. Hover paints a soft grey bg WITHOUT touching the
50
+ text — pure pointer affordance. Keyboard selection paints the
51
+ LABEL blue WITHOUT a bg — pure focus indicator. The two channels
52
+ (bg vs. text) don't fight, so the keyboard-selected row stays
53
+ unambiguous even when the mouse happens to hover a different
54
+ option in the list. */
55
+ color: rgb(113 113 122) !important;
56
+ cursor: pointer;
57
+ user-select: none;
58
+ border: 0 !important;
59
+ background: transparent !important;
60
+ text-decoration: none !important;
61
+ line-height: 1.3;
62
+ }
63
+ .dark .cm-tooltip-autocomplete > ul > li {
64
+ color: rgb(161 161 170) !important;
65
+ }
66
+
67
+ /* Hover = soft grey background, text colour unchanged. */
68
+ .cm-tooltip-autocomplete > ul > li:hover {
69
+ background: var(--ui-hover) !important;
70
+ text-decoration: none !important;
71
+ }
72
+
73
+ /* Keyboard-selected = platform action-blue text, no background: it is a
74
+ control option, not a picked object. Pairs cleanly with hover (which
75
+ only paints bg) so a row that's both selected AND hovered shows blue
76
+ text on the hover bg. */
77
+ .cm-tooltip-autocomplete > ul > li[aria-selected] {
78
+ color: var(--k2b-action) !important;
79
+ background: transparent !important;
80
+ text-decoration: none !important;
81
+ }
82
+
83
+ /* Selected + hovered = blue text on the hover-bg (so the user can
84
+ still see "this row is also under my cursor" without losing the
85
+ selection indicator). */
86
+ .cm-tooltip-autocomplete > ul > li[aria-selected]:hover {
87
+ background: var(--ui-hover) !important;
88
+ }
89
+
90
+ .cm-tooltip-autocomplete .cm-slash-icon {
91
+ flex-shrink: 0;
92
+ width: 0.875rem;
93
+ font-size: 0.8125rem;
94
+ color: inherit; /* picks up the row's color */
95
+ }
96
+
97
+ .cm-tooltip-autocomplete .cm-completionLabel {
98
+ flex: 0 0 auto;
99
+ }
100
+
101
+ /* Our custom completion detail renderer — short signature or one-line
102
+ description shown inline next to the label. Dimmed so the label
103
+ reads as primary. Truncates with ellipsis at the popup edge. */
104
+ .cm-tooltip-autocomplete .cm-completion-detail {
105
+ flex: 1 1 auto;
106
+ min-width: 0;
107
+ margin-left: 0.375rem;
108
+ font-size: 0.625rem;
109
+ color: rgb(161 161 170); /* zinc-400 */
110
+ white-space: nowrap;
111
+ overflow: hidden;
112
+ text-overflow: ellipsis;
113
+ }
114
+ .cm-tooltip-autocomplete > ul > li[aria-selected] .cm-completion-detail {
115
+ /* Selected row turns blue; keep the detail subtler — still
116
+ readable but visually secondary. Hover does NOT tint the detail
117
+ (hover is just a soft bg, see the rule above). */
118
+ color: rgb(96 165 250 / 0.85); /* blue-400 / 85% */
119
+ }
120
+ .dark .cm-tooltip-autocomplete .cm-completion-detail {
121
+ color: rgb(113 113 122); /* zinc-500 */
122
+ }
123
+
124
+ /* Hide every "extra" element CM emits — descriptions, section dividers,
125
+ section headings, AND the per-option info side panel. KISS palette:
126
+ just `[icon] Label detail` rows, in registry order.
127
+
128
+ Why hide `.cm-tooltip.cm-completionInfo` too: CM renders it as a
129
+ floating panel on the selected option (the long-form `info` text).
130
+ When there's no room to the right of the popup it falls back to
131
+ rendering INSIDE the option list — observed as a "subbox" cutting
132
+ off the description mid-sentence. We already surface a one-liner
133
+ inline via `cm-completion-detail`, so the verbose info panel is dead
134
+ weight; killing it removes the cutoff bug and keeps the popup
135
+ compact + consistent. */
136
+ .cm-tooltip-autocomplete .cm-completionDetail,
137
+ .cm-tooltip-autocomplete .cm-completionSectionLabel,
138
+ .cm-tooltip-autocomplete completion-section,
139
+ .cm-tooltip-autocomplete .cm-completionListIncompleteTop,
140
+ .cm-tooltip-autocomplete .cm-completionListIncompleteBottom,
141
+ .cm-tooltip.cm-completionInfo {
142
+ display: none !important;
143
+ }
144
+
145
+ .md-block-handle {
146
+ display: inline-flex;
147
+ align-items: center;
148
+ width: fit-content;
149
+ max-width: 100%;
150
+ margin: 0.35rem 0 0.15rem;
151
+ padding: 0.125rem 0.375rem;
152
+ border-radius: 0.25rem;
153
+ background: rgb(239 246 255);
154
+ color: rgb(37 99 235);
155
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
156
+ font-size: 0.6875rem;
157
+ font-weight: 600;
158
+ line-height: 1.3;
159
+ }
160
+
161
+ .dark .md-block-handle {
162
+ background: rgb(30 58 138 / 0.25);
163
+ color: rgb(147 197 253);
164
+ }
165
+
166
+ .md-data-handle-row {
167
+ display: flex;
168
+ align-items: baseline;
169
+ gap: 0.375rem;
170
+ width: fit-content;
171
+ max-width: 100%;
172
+ }
173
+
174
+ .md-data-block {
175
+ display: block;
176
+ margin: 0.5rem 0;
177
+ }
178
+
179
+ .md-data-grid {
180
+ display: grid;
181
+ grid-template-columns: minmax(7rem, max-content) minmax(0, 1fr);
182
+ overflow-x: auto;
183
+ border: 1px solid var(--ui-border);
184
+ border-radius: var(--ui-radius-surface);
185
+ background: var(--ui-surface);
186
+ box-shadow: var(--ui-shadow-surface);
187
+ }
188
+
189
+ .md-data-row {
190
+ display: contents;
191
+ }
192
+
193
+ .md-data-row:not(:last-child) > .md-data-key,
194
+ .md-data-row:not(:last-child) > .md-data-value {
195
+ border-bottom: 1px solid var(--ui-data-row-divider);
196
+ }
197
+
198
+ .md-data-key,
199
+ .md-data-value,
200
+ .md-data-empty {
201
+ --md-data-cell-base: transparent;
202
+ --md-data-column-highlight: transparent;
203
+ --md-data-row-highlight: transparent;
204
+
205
+ display: block;
206
+ min-height: 2rem;
207
+ box-sizing: border-box;
208
+ border: 0;
209
+ border-radius: 0;
210
+ padding: 0.5rem 0.75rem;
211
+ background:
212
+ linear-gradient(var(--md-data-row-highlight), var(--md-data-row-highlight)),
213
+ linear-gradient(var(--md-data-column-highlight), var(--md-data-column-highlight)), var(--md-data-cell-base);
214
+ box-shadow: none;
215
+ font-size: 0.75rem;
216
+ line-height: 1rem;
217
+ }
218
+
219
+ .md-data-key {
220
+ --md-data-cell-base: var(--ui-data-header);
221
+
222
+ font-weight: 600;
223
+ white-space: nowrap;
224
+ }
225
+
226
+ .md-data-value,
227
+ .md-data-empty {
228
+ min-width: 12rem;
229
+ overflow-wrap: anywhere;
230
+ }
231
+
232
+ .md-data-empty {
233
+ grid-column: 1 / -1;
234
+ min-width: 0;
235
+ color: rgb(113 113 122);
236
+ }
237
+
238
+ .md-data-chip {
239
+ display: inline-flex;
240
+ align-items: center;
241
+ margin-right: 0.25rem;
242
+ margin-bottom: 0.125rem;
243
+ padding: 0.125rem 0.375rem;
244
+ border-radius: 0.25rem;
245
+ background: rgb(239 246 255);
246
+ color: rgb(29 78 216);
247
+ font-weight: 500;
248
+ }
249
+
250
+ .dark .md-data-empty {
251
+ color: rgb(161 161 170);
252
+ }
253
+
254
+ .dark .md-data-chip {
255
+ background: rgb(30 58 138 / 0.35);
256
+ color: rgb(147 197 253);
257
+ }
258
+
259
+ @media (hover: hover) {
260
+ .md-data-row:hover > :is(.md-data-key, .md-data-value) {
261
+ --md-data-row-highlight: var(--ui-data-row-hover);
262
+ }
263
+
264
+ .md-data-grid:has(.md-data-key:hover) .md-data-key,
265
+ .md-data-grid:has(.md-data-value:hover) .md-data-value {
266
+ --md-data-column-highlight: var(--ui-data-column-hover);
267
+ }
268
+ }
269
+
270
+ /* A rendered block in the editor, and the box the note's server preview reserves for a chart in its place. */
271
+ .cm-query-block-widget {
272
+ display: block;
273
+ margin: 0.5rem 0;
274
+ padding: 0.5rem;
275
+ border: 1px solid var(--ui-border);
276
+ border-radius: var(--k2b-radius-control);
277
+ }
278
+ .cm-query-block-preview.notebook-book-content {
279
+ max-width: none;
280
+ margin: 0;
281
+ padding: 0;
282
+ font-size: inherit;
283
+ line-height: inherit;
284
+ }
285
+ /* A chart block, flat in the text like the chart in an Assistant chat: title and subtitle as text, then a frame whose
286
+ height comes from the kind and never from the data. The editor's placeholder, the drawn chart and every redraw take
287
+ the same room, and a legend scrolls inside the frame instead of growing it. The SVG stretches to the column's width
288
+ through the shared `.k2b-chart` rules, which keep its text and marks at their pixel size. */
289
+ .notebook-book-content .notebook-book-chart {
290
+ display: grid;
291
+ grid-template-columns: minmax(0, 1fr) auto;
292
+ align-items: start;
293
+ gap: 0.5rem;
294
+ min-width: 0;
295
+ margin: 1.25rem 0;
296
+ }
297
+ .notebook-book-chart__header {
298
+ display: flex;
299
+ flex-direction: column;
300
+ min-width: 0;
301
+ }
302
+ /* Copy data and the table switch: two small icon buttons, as on a chart in an Assistant chat. The server reserves
303
+ this box empty, so the controls appear in place when the browser enhancement mounts them. */
304
+ .notebook-book-chart__actions {
305
+ display: flex;
306
+ gap: 0.25rem;
307
+ width: 3.75rem;
308
+ height: 1.75rem;
309
+ }
310
+ /* The table takes the drawing's place inside the same fixed frame and scrolls there. */
311
+ .notebook-book-chart[data-view="table"] .notebook-book-chart__viewport > :not(.notebook-book-chart__table) {
312
+ display: none;
313
+ }
314
+ /* Like every note table, it bleeds past the text on both sides so its cell text lines up with the title. */
315
+ .notebook-book-content .notebook-book-chart__table {
316
+ flex: 1 1 0;
317
+ min-height: 0;
318
+ margin-block: 0;
319
+ overflow: auto;
320
+ }
321
+ .notebook-book-chart__title {
322
+ font-size: 1rem;
323
+ font-weight: 600;
324
+ line-height: 1.5;
325
+ }
326
+ .notebook-book-chart__subtitle {
327
+ color: var(--k2b-text-muted);
328
+ font-size: 0.875rem;
329
+ line-height: 1.25rem;
330
+ }
331
+ /* The server writes `--notebook-chart-height` where the drawing needs more than the frame: bar rows grow with their
332
+ categories instead of hiding labels. Placeholder, drawing and table view keep that one height in every engine. */
333
+ .notebook-book-chart__viewport {
334
+ grid-column: 1 / -1;
335
+ display: flex;
336
+ flex-direction: column;
337
+ gap: 0.5rem;
338
+ min-width: 0;
339
+ height: max(18rem, var(--notebook-chart-height, 0px));
340
+ }
341
+ .notebook-book-chart[data-kind="stat"] .notebook-book-chart__viewport {
342
+ height: 10rem;
343
+ }
344
+ .notebook-book-chart__viewport > .k2b-chart {
345
+ flex: 1 1 0;
346
+ min-height: 60%;
347
+ }
348
+ .notebook-book-chart .k2b-chart__svg {
349
+ height: var(--notebook-chart-height, 100%);
350
+ }
351
+ /* Loading and failure messages stand inside the frame they wait for. */
352
+ .notebook-book-content .notebook-book-chart__status {
353
+ margin: auto;
354
+ text-align: center;
355
+ }
356
+ /* Book images keep their aspect ratio; the chart's SVG fills its frame instead. */
357
+ .notebook-book-content .notebook-book-chart svg {
358
+ max-width: none;
359
+ height: 100%;
360
+ }
361
+
362
+ @media print {
363
+ /* Chart controls stay on screen. A chart switched to its table prints every row: the frame grows with it. */
364
+ .notebook-book-chart__actions {
365
+ display: none;
366
+ }
367
+ .notebook-book-content .notebook-book-chart {
368
+ grid-template-columns: minmax(0, 1fr);
369
+ }
370
+ .notebook-book-chart[data-view="table"] .notebook-book-chart__viewport {
371
+ height: auto;
372
+ }
373
+ .notebook-book-content .notebook-book-chart__table {
374
+ flex: none;
375
+ }
376
+ }