@stephen-netu/design-system 0.2.0 → 0.2.2
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/b0-app-shell/clarification-overlay/ClarificationOverlay.svelte +10 -2
- package/dist/b0-app-shell/clarification-overlay/ClarificationOverlay.svelte.d.ts.map +1 -1
- package/dist/b0-app-shell/{command-bar/CommandBar.svelte → global-command-bar/GlobalCommandBar.svelte} +75 -75
- package/dist/b0-app-shell/{command-bar/CommandBar.svelte.d.ts → global-command-bar/GlobalCommandBar.svelte.d.ts} +6 -6
- package/dist/b0-app-shell/global-command-bar/GlobalCommandBar.svelte.d.ts.map +1 -0
- package/dist/b0-app-shell/index.d.ts +1 -1
- package/dist/b0-app-shell/index.d.ts.map +1 -1
- package/dist/b0-app-shell/index.js +1 -1
- package/dist/d0-data-viz/CheckpointPill.svelte +7 -2
- package/dist/d0-data-viz/CheckpointPill.svelte.d.ts.map +1 -1
- package/dist/d0-data-viz/theme-integration.d.ts +3 -3
- package/dist/d0-data-viz/theme-integration.js +3 -3
- package/dist/d0-data-viz/theme-integration.test.js +41 -0
- package/dist/demos/BspSizingInfographic.svelte +3 -32
- package/dist/editor/CodeEditor.test.js +38 -0
- package/dist/editor/FindReplaceDialog.svelte +32 -32
- package/dist/editor/MarkdownEditor.svelte +71 -58
- package/dist/editor/MarkdownEditor.svelte.d.ts.map +1 -1
- package/dist/editor/MarkdownEditor.test.js +38 -0
- package/dist/editor/components/CorrectionTooltip.svelte +0 -1
- package/dist/editor/extensions/expansion.d.ts.map +1 -1
- package/dist/editor/extensions/expansion.js +16 -10
- package/dist/entity-graph-view/WorldView.svelte +1 -1
- package/dist/fabric/ai/ChatPanel.svelte +31 -31
- package/dist/fabric/ai/ResearchPanel.svelte +6 -3
- package/dist/fabric/ai/ResearchPanel.svelte.d.ts.map +1 -1
- package/dist/fabric/index.d.ts +4 -5
- package/dist/fabric/index.d.ts.map +1 -1
- package/dist/fabric/index.js +3 -3
- package/dist/fabric/input/{CommandBar.svelte → AppHeaderBar.svelte} +13 -13
- package/dist/fabric/input/{CommandBar.svelte.d.ts → AppHeaderBar.svelte.d.ts} +5 -5
- package/dist/fabric/input/AppHeaderBar.svelte.d.ts.map +1 -0
- package/dist/fabric/input/{CommandBar.test.js → AppHeaderBar.test.js} +9 -9
- package/dist/fabric/input/index.d.ts +2 -2
- package/dist/fabric/input/index.d.ts.map +1 -1
- package/dist/fabric/input/index.js +1 -1
- package/dist/fabric/layout/KanbanBoard.svelte +25 -155
- package/dist/fabric/layout/KanbanBoard.svelte.d.ts +2 -26
- package/dist/fabric/layout/KanbanBoard.svelte.d.ts.map +1 -1
- package/dist/fabric/layout/KanbanBoard.test.js +125 -10
- package/dist/fabric/layout/KanbanCard.svelte +27 -223
- package/dist/fabric/layout/KanbanCard.svelte.d.ts +2 -19
- package/dist/fabric/layout/KanbanCard.svelte.d.ts.map +1 -1
- package/dist/fabric/layout/KanbanColumn.svelte +41 -275
- package/dist/fabric/layout/KanbanColumn.svelte.d.ts +2 -22
- package/dist/fabric/layout/KanbanColumn.svelte.d.ts.map +1 -1
- package/dist/fabric/layout/index.d.ts +2 -5
- package/dist/fabric/layout/index.d.ts.map +1 -1
- package/dist/fabric/layout/index.js +1 -1
- package/dist/g0-generative/renderer/OpenUIRenderer.svelte +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/l0-layout/SectionSplitter.svelte +5 -5
- package/dist/l0-layout/block-writer/BlockItem.svelte +6 -4
- package/dist/l0-layout/card/CompactCard.svelte +4 -3
- package/dist/l0-layout/grant/GrantCard.svelte +15 -5
- package/dist/l0-layout/grant/GrantCard.svelte.d.ts.map +1 -1
- package/dist/l0-layout/index.d.ts +2 -0
- package/dist/l0-layout/index.d.ts.map +1 -1
- package/dist/l0-layout/index.js +1 -0
- package/dist/l0-layout/kanban/KanbanBoard.svelte +246 -29
- package/dist/l0-layout/kanban/KanbanBoard.svelte.d.ts +28 -2
- package/dist/l0-layout/kanban/KanbanBoard.svelte.d.ts.map +1 -1
- package/dist/l0-layout/kanban/KanbanCard.svelte +175 -150
- package/dist/l0-layout/kanban/KanbanCard.svelte.d.ts +16 -18
- package/dist/l0-layout/kanban/KanbanCard.svelte.d.ts.map +1 -1
- package/dist/l0-layout/kanban/KanbanColumn.svelte +152 -78
- package/dist/l0-layout/kanban/KanbanColumn.svelte.d.ts +28 -7
- package/dist/l0-layout/kanban/KanbanColumn.svelte.d.ts.map +1 -1
- package/dist/l0-layout/kanban/index.d.ts +6 -0
- package/dist/l0-layout/kanban/index.d.ts.map +1 -0
- package/dist/l0-layout/kanban/index.js +3 -0
- package/dist/n0-node-graph/Node.svelte +2 -2
- package/dist/n0-node-graph/NodePalette.svelte +2 -2
- package/dist/n1-flow-canvas/graph-state.test.js +69 -0
- package/dist/n1-flow-canvas/utils.test.js +116 -0
- package/dist/n3-force-graph/GraphTooltip.svelte +2 -2
- package/dist/n4-adaptive-manifold/AdaptiveManifold.svelte +12 -11
- package/dist/n4-adaptive-manifold/AdaptiveManifold.svelte.d.ts.map +1 -1
- package/dist/n4-adaptive-manifold/classifier.test.js +104 -0
- package/dist/n4-adaptive-manifold/n4-tokens.css +2 -2
- package/dist/p0-primitives/ThemeProvider.svelte +10 -11
- package/dist/p0-primitives/ThemeProvider.svelte.d.ts +1 -1
- package/dist/p0-primitives/ThemeProvider.svelte.d.ts.map +1 -1
- package/dist/p0-primitives/canvas-theme.d.ts +12 -0
- package/dist/p0-primitives/canvas-theme.d.ts.map +1 -1
- package/dist/p0-primitives/canvas-theme.js +10 -0
- package/dist/p0-primitives/index.d.ts +2 -1
- package/dist/p0-primitives/index.d.ts.map +1 -1
- package/dist/p0-primitives/index.js +1 -0
- package/dist/p0-primitives/theme-context.d.ts +9 -0
- package/dist/p0-primitives/theme-context.d.ts.map +1 -0
- package/dist/p0-primitives/theme-context.js +8 -0
- package/dist/p0-primitives/tokens/tokens.css +22 -11
- package/dist/p0-primitives/utils/index.d.ts +2 -2
- package/dist/p0-primitives/utils/index.d.ts.map +1 -1
- package/dist/s0-state/SyncStatus.svelte +1 -1
- package/dist/s0-state/ThemeStore.svelte.d.ts +3 -2
- package/dist/s0-state/ThemeStore.svelte.d.ts.map +1 -1
- package/dist/s0-state/ThemeStore.svelte.js +20 -1
- package/dist/s0-state/index.d.ts +0 -1
- package/dist/s0-state/index.d.ts.map +1 -1
- package/dist/s0-state/index.js +1 -0
- package/dist/s0-state/modal-stack-store.svelte.d.ts +25 -0
- package/dist/s0-state/modal-stack-store.svelte.d.ts.map +1 -1
- package/dist/s0-state/modal-stack-store.svelte.js +19 -0
- package/dist/showcase/Showcase.svelte +43 -34
- package/dist/showcase/Showcase.svelte.d.ts.map +1 -1
- package/dist/spatial/BspTilingCanvas.svelte +7 -5
- package/dist/spatial/BspTilingCanvas.svelte.d.ts +1 -0
- package/dist/spatial/BspTilingCanvas.svelte.d.ts.map +1 -1
- package/dist/spatial/BspTilingSimulation.test.js +88 -0
- package/dist/spatial/CameraController.test.js +120 -0
- package/dist/spatial/ForceCanvas.svelte +20 -13
- package/dist/spatial/ForceCanvas.svelte.d.ts +1 -0
- package/dist/spatial/ForceCanvas.svelte.d.ts.map +1 -1
- package/dist/spatial/ForceSimulation.svelte.d.ts.map +1 -1
- package/dist/spatial/ForceSimulation.svelte.js +32 -21
- package/dist/spatial/LodRenderer.svelte +16 -1
- package/dist/spatial/LodRenderer.svelte.d.ts +1 -0
- package/dist/spatial/LodRenderer.svelte.d.ts.map +1 -1
- package/dist/spatial/SnapZoomCamera.svelte +25 -13
- package/dist/spatial/SnapZoomCamera.svelte.d.ts +1 -0
- package/dist/spatial/SnapZoomCamera.svelte.d.ts.map +1 -1
- package/dist/spatial/ZoneTiler.svelte +5 -2
- package/dist/spatial/ZoneTiler.svelte.d.ts +1 -0
- package/dist/spatial/ZoneTiler.svelte.d.ts.map +1 -1
- package/dist/spatial/d3-types.d.ts +31 -0
- package/dist/spatial/d3-types.d.ts.map +1 -0
- package/dist/spatial/d3-types.js +19 -0
- package/dist/ssr-import-clean.test.js +37 -0
- package/dist/t0-transport/fs.d.ts +12 -0
- package/dist/t0-transport/fs.d.ts.map +1 -0
- package/dist/t0-transport/fs.js +55 -0
- package/dist/t0-transport/index.d.ts +1 -0
- package/dist/t0-transport/index.d.ts.map +1 -1
- package/dist/t0-transport/index.js +1 -0
- package/dist/t0-transport/invoke.d.ts.map +1 -1
- package/dist/t0-transport/invoke.js +5 -2
- package/dist/t0-transport/quality.d.ts +12 -3
- package/dist/t0-transport/quality.d.ts.map +1 -1
- package/dist/t0-transport/quality.js +17 -4
- package/dist/t0-transport/substrate.svelte.d.ts +27 -0
- package/dist/t0-transport/substrate.svelte.d.ts.map +1 -0
- package/dist/t0-transport/substrate.svelte.js +49 -0
- package/dist/u0-primitives/LockIndicator.svelte +1 -1
- package/dist/u0-primitives/VerticalToolbar.svelte +1 -1
- package/dist/u0-primitives/accordion/Accordion.svelte +10 -9
- package/dist/u0-primitives/accordion/Accordion.svelte.d.ts +0 -7
- package/dist/u0-primitives/accordion/Accordion.svelte.d.ts.map +1 -1
- package/dist/u0-primitives/accordion/Accordion.test.js +5 -5
- package/dist/u0-primitives/badge/Badge.test.js +10 -10
- package/dist/u0-primitives/badge/ValidityBadge.test.js +9 -9
- package/dist/u0-primitives/button/Button.svelte +3 -1
- package/dist/u0-primitives/button/Button.svelte.d.ts +1 -0
- package/dist/u0-primitives/button/Button.svelte.d.ts.map +1 -1
- package/dist/u0-primitives/button/Button.test.js +11 -11
- package/dist/u0-primitives/card/Card.svelte +26 -20
- package/dist/u0-primitives/card/Card.svelte.d.ts.map +1 -1
- package/dist/u0-primitives/command-palette/CommandPalette.svelte +27 -0
- package/dist/u0-primitives/command-palette/CommandPalette.svelte.d.ts.map +1 -1
- package/dist/u0-primitives/command-palette/commandStore.svelte.d.ts.map +1 -1
- package/dist/u0-primitives/command-palette/commandStore.svelte.js +2 -1
- package/dist/u0-primitives/dropdown/Dropdown.test.js +1 -1
- package/dist/u0-primitives/index.d.ts +2 -0
- package/dist/u0-primitives/index.d.ts.map +1 -1
- package/dist/u0-primitives/index.js +1 -0
- package/dist/u0-primitives/input/Input.svelte +9 -0
- package/dist/u0-primitives/input/Input.svelte.d.ts.map +1 -1
- package/dist/u0-primitives/input/Input.test.js +1 -1
- package/dist/u0-primitives/modal/Modal.svelte +46 -23
- package/dist/u0-primitives/modal/Modal.svelte.d.ts.map +1 -1
- package/dist/u0-primitives/modal/Modal.test.js +63 -15
- package/dist/u0-primitives/rsvp/RsvpReader.svelte +8 -8
- package/dist/u0-primitives/rsvp/RsvpReader.svelte.d.ts.map +1 -1
- package/dist/u0-primitives/steps/Steps.svelte +2 -2
- package/dist/u0-primitives/surface-state/SurfaceState.svelte +190 -0
- package/dist/u0-primitives/surface-state/SurfaceState.svelte.d.ts +15 -0
- package/dist/u0-primitives/surface-state/SurfaceState.svelte.d.ts.map +1 -0
- package/dist/u0-primitives/toggle/Toggle.svelte +12 -2
- package/dist/u0-primitives/tooltip/Tooltip.test.js +12 -12
- package/dist/v0-diagrams/MarkmapDiagram.test.js +49 -0
- package/dist/v0-diagrams/MermaidDiagram.svelte +21 -9
- package/dist/v0-diagrams/MermaidDiagram.svelte.d.ts.map +1 -1
- package/dist/v0-diagrams/MermaidDiagram.test.js +40 -0
- package/package.json +51 -24
- package/src/n4-adaptive-manifold/n4-tokens.css +2 -2
- package/src/p0-primitives/tokens/tokens.css +22 -11
- package/src/p0-primitives/tokens/tokens.json +13 -2
- package/dist/b0-app-shell/command-bar/CommandBar.svelte.d.ts.map +0 -1
- package/dist/fabric/input/CommandBar.svelte.d.ts.map +0 -1
- package/dist/stores/vaultStore.svelte +0 -14
- package/dist/stores/vaultStore.svelte.d.ts +0 -24
- package/dist/stores/vaultStore.svelte.d.ts.map +0 -1
- package/dist/tauri/index.d.ts +0 -3
- package/dist/tauri/index.d.ts.map +0 -1
- package/dist/tauri/index.js +0 -11
- package/dist/types/tauri.d.ts +0 -18
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
2
|
+
import { render, cleanup } from '@testing-library/svelte';
|
|
3
|
+
import CodeEditor from './CodeEditor.svelte';
|
|
4
|
+
afterEach(() => {
|
|
5
|
+
cleanup();
|
|
6
|
+
});
|
|
7
|
+
describe('editor/CodeEditor', () => {
|
|
8
|
+
it('exports a valid Svelte component', () => {
|
|
9
|
+
expect(CodeEditor).toBeDefined();
|
|
10
|
+
expect(typeof CodeEditor).toBe('function');
|
|
11
|
+
});
|
|
12
|
+
it('renders editor container', () => {
|
|
13
|
+
const { container } = render(CodeEditor, {
|
|
14
|
+
content: 'const x = 1;',
|
|
15
|
+
source: 'test.ts',
|
|
16
|
+
isActive: true,
|
|
17
|
+
});
|
|
18
|
+
expect(container.querySelector('.code-editor')).not.toBeNull();
|
|
19
|
+
});
|
|
20
|
+
it('renders with text content', () => {
|
|
21
|
+
const { container } = render(CodeEditor, {
|
|
22
|
+
content: 'hello world',
|
|
23
|
+
source: '',
|
|
24
|
+
isActive: false,
|
|
25
|
+
});
|
|
26
|
+
expect(container.querySelector('.code-editor')).not.toBeNull();
|
|
27
|
+
});
|
|
28
|
+
it('calls onContentChange when content changes', async () => {
|
|
29
|
+
const onContentChange = vi.fn();
|
|
30
|
+
const { container } = render(CodeEditor, {
|
|
31
|
+
content: 'initial',
|
|
32
|
+
source: 'test.ts',
|
|
33
|
+
isActive: true,
|
|
34
|
+
onContentChange,
|
|
35
|
+
});
|
|
36
|
+
expect(container.querySelector('.code-editor')).not.toBeNull();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -211,7 +211,7 @@
|
|
|
211
211
|
</script>
|
|
212
212
|
|
|
213
213
|
{#if isOpen}
|
|
214
|
-
<div class="find-replace-dialog" role="dialog" aria-modal="true" aria-label={showReplace ? 'Find and replace' : 'Find'} onkeydown={handleKeyDown}>
|
|
214
|
+
<div class="find-replace-dialog" role="dialog" aria-modal="true" aria-label={showReplace ? 'Find and replace' : 'Find'} tabindex="-1" onkeydown={handleKeyDown}>
|
|
215
215
|
<div class="dialog-header">
|
|
216
216
|
<span class="dialog-title">{showReplace ? 'Find and Replace' : 'Find'}</span>
|
|
217
217
|
<button class="close-btn" onclick={handleClose} aria-label="Close">
|
|
@@ -308,7 +308,7 @@
|
|
|
308
308
|
position: absolute;
|
|
309
309
|
top: 10px;
|
|
310
310
|
right: 10px;
|
|
311
|
-
background: var(--bg-panel, #252525);
|
|
311
|
+
background: var(--color-bg-panel, #252525);
|
|
312
312
|
border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.1));
|
|
313
313
|
border-radius: 8px;
|
|
314
314
|
padding: 0;
|
|
@@ -328,13 +328,13 @@
|
|
|
328
328
|
.dialog-title {
|
|
329
329
|
font-size: 13px;
|
|
330
330
|
font-weight: 500;
|
|
331
|
-
color: var(--text-primary, #e8e6e3);
|
|
331
|
+
color: var(--color-text-primary, #e8e6e3);
|
|
332
332
|
}
|
|
333
333
|
|
|
334
334
|
.close-btn {
|
|
335
335
|
background: none;
|
|
336
336
|
border: none;
|
|
337
|
-
color: var(--text-secondary, #a0a0a0);
|
|
337
|
+
color: var(--color-text-secondary, #a0a0a0);
|
|
338
338
|
cursor: pointer;
|
|
339
339
|
padding: 4px;
|
|
340
340
|
border-radius: 4px;
|
|
@@ -345,8 +345,8 @@
|
|
|
345
345
|
}
|
|
346
346
|
|
|
347
347
|
.close-btn:hover {
|
|
348
|
-
background: var(--bg-canvas, #1a1a1a);
|
|
349
|
-
color: var(--text-primary, #e8e6e3);
|
|
348
|
+
background: var(--color-bg-canvas, #1a1a1a);
|
|
349
|
+
color: var(--color-text-primary, #e8e6e3);
|
|
350
350
|
}
|
|
351
351
|
|
|
352
352
|
.dialog-body {
|
|
@@ -364,18 +364,18 @@
|
|
|
364
364
|
|
|
365
365
|
input {
|
|
366
366
|
flex: 1;
|
|
367
|
-
background: var(--bg-canvas, #1a1a1a);
|
|
367
|
+
background: var(--color-bg-canvas, #1a1a1a);
|
|
368
368
|
border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.1));
|
|
369
369
|
border-radius: 6px;
|
|
370
370
|
padding: 8px 12px;
|
|
371
|
-
color: var(--text-primary, #e8e6e3);
|
|
371
|
+
color: var(--color-text-primary, #e8e6e3);
|
|
372
372
|
font-size: 13px;
|
|
373
373
|
outline: none;
|
|
374
374
|
transition: border-color 0.15s ease;
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
input:focus {
|
|
378
|
-
border-color: var(--
|
|
378
|
+
border-color: var(--color-accent);
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
input.no-match {
|
|
@@ -384,15 +384,15 @@
|
|
|
384
384
|
}
|
|
385
385
|
|
|
386
386
|
input::placeholder {
|
|
387
|
-
color: var(--text-tertiary, #6b6b6b);
|
|
387
|
+
color: var(--color-text-tertiary, #6b6b6b);
|
|
388
388
|
}
|
|
389
389
|
|
|
390
390
|
.case-btn {
|
|
391
|
-
background: var(--bg-canvas, #1a1a1a);
|
|
391
|
+
background: var(--color-bg-canvas, #1a1a1a);
|
|
392
392
|
border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.1));
|
|
393
393
|
border-radius: 6px;
|
|
394
394
|
padding: 8px 10px;
|
|
395
|
-
color: var(--text-secondary, #a0a0a0);
|
|
395
|
+
color: var(--color-text-secondary, #a0a0a0);
|
|
396
396
|
font-size: 12px;
|
|
397
397
|
font-weight: 600;
|
|
398
398
|
cursor: pointer;
|
|
@@ -400,19 +400,19 @@
|
|
|
400
400
|
}
|
|
401
401
|
|
|
402
402
|
.case-btn:hover {
|
|
403
|
-
border-color: var(--
|
|
404
|
-
color: var(--text-primary, #e8e6e3);
|
|
403
|
+
border-color: var(--color-accent);
|
|
404
|
+
color: var(--color-text-primary, #e8e6e3);
|
|
405
405
|
}
|
|
406
406
|
|
|
407
407
|
.case-btn.active {
|
|
408
|
-
background: var(--
|
|
409
|
-
border-color: var(--
|
|
408
|
+
background: var(--color-accent);
|
|
409
|
+
border-color: var(--color-accent);
|
|
410
410
|
color: white;
|
|
411
411
|
}
|
|
412
412
|
|
|
413
413
|
.match-info {
|
|
414
414
|
font-size: 12px;
|
|
415
|
-
color: var(--text-secondary, #a0a0a0);
|
|
415
|
+
color: var(--color-text-secondary, #a0a0a0);
|
|
416
416
|
padding: 0 2px;
|
|
417
417
|
}
|
|
418
418
|
|
|
@@ -434,11 +434,11 @@
|
|
|
434
434
|
}
|
|
435
435
|
|
|
436
436
|
.nav-btn {
|
|
437
|
-
background: var(--bg-canvas, #1a1a1a);
|
|
437
|
+
background: var(--color-bg-canvas, #1a1a1a);
|
|
438
438
|
border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.1));
|
|
439
439
|
border-radius: 6px;
|
|
440
440
|
padding: 6px 8px;
|
|
441
|
-
color: var(--text-secondary, #a0a0a0);
|
|
441
|
+
color: var(--color-text-secondary, #a0a0a0);
|
|
442
442
|
cursor: pointer;
|
|
443
443
|
display: flex;
|
|
444
444
|
align-items: center;
|
|
@@ -447,9 +447,9 @@
|
|
|
447
447
|
}
|
|
448
448
|
|
|
449
449
|
.nav-btn:hover:not(:disabled) {
|
|
450
|
-
background: var(--
|
|
451
|
-
border-color: var(--
|
|
452
|
-
color: var(--
|
|
450
|
+
background: var(--color-accent-subtle);
|
|
451
|
+
border-color: var(--color-accent);
|
|
452
|
+
color: var(--color-accent);
|
|
453
453
|
}
|
|
454
454
|
|
|
455
455
|
.nav-btn:disabled {
|
|
@@ -473,25 +473,25 @@
|
|
|
473
473
|
}
|
|
474
474
|
|
|
475
475
|
.action-btn.secondary {
|
|
476
|
-
background: var(--bg-canvas, #1a1a1a);
|
|
476
|
+
background: var(--color-bg-canvas, #1a1a1a);
|
|
477
477
|
border-color: var(--border-subtle, rgba(255, 255, 255, 0.1));
|
|
478
|
-
color: var(--text-secondary, #a0a0a0);
|
|
478
|
+
color: var(--color-text-secondary, #a0a0a0);
|
|
479
479
|
}
|
|
480
480
|
|
|
481
481
|
.action-btn.secondary:hover:not(:disabled) {
|
|
482
|
-
border-color: var(--
|
|
483
|
-
color: var(--text-primary, #e8e6e3);
|
|
482
|
+
border-color: var(--color-accent);
|
|
483
|
+
color: var(--color-text-primary, #e8e6e3);
|
|
484
484
|
}
|
|
485
485
|
|
|
486
486
|
.action-btn.primary {
|
|
487
|
-
background: var(--
|
|
488
|
-
border-color: var(--
|
|
487
|
+
background: var(--color-accent);
|
|
488
|
+
border-color: var(--color-accent);
|
|
489
489
|
color: white;
|
|
490
490
|
}
|
|
491
491
|
|
|
492
492
|
.action-btn.primary:hover:not(:disabled) {
|
|
493
|
-
background: var(--accent-hover, #c9843d);
|
|
494
|
-
border-color: var(--accent-hover, #c9843d);
|
|
493
|
+
background: var(--color-accent-hover, #c9843d);
|
|
494
|
+
border-color: var(--color-accent-hover, #c9843d);
|
|
495
495
|
}
|
|
496
496
|
|
|
497
497
|
.action-btn:disabled {
|
|
@@ -502,7 +502,7 @@
|
|
|
502
502
|
.mode-toggle {
|
|
503
503
|
background: none;
|
|
504
504
|
border: none;
|
|
505
|
-
color: var(--
|
|
505
|
+
color: var(--color-accent);
|
|
506
506
|
font-size: 12px;
|
|
507
507
|
cursor: pointer;
|
|
508
508
|
padding: 4px 8px;
|
|
@@ -511,6 +511,6 @@
|
|
|
511
511
|
}
|
|
512
512
|
|
|
513
513
|
.mode-toggle:hover {
|
|
514
|
-
background: var(--
|
|
514
|
+
background: var(--color-accent-subtle);
|
|
515
515
|
}
|
|
516
516
|
</style>
|
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
import { markdown } from '@codemirror/lang-markdown';
|
|
19
19
|
import { defaultKeymap, history, historyKeymap } from '@codemirror/commands';
|
|
20
20
|
import { search } from '@codemirror/search';
|
|
21
|
-
import {
|
|
22
|
-
import { vaultStore } from '../stores/vaultStore.svelte';
|
|
21
|
+
import { writeTextFile, readTextFile, getMtimeMs, isTauri } from '../t0-transport/fs';
|
|
23
22
|
import FindReplaceDialog from './FindReplaceDialog.svelte';
|
|
24
23
|
import { autoFormat } from './extensions/autoformat';
|
|
25
24
|
import { expansion } from './extensions/expansion';
|
|
@@ -50,10 +49,15 @@
|
|
|
50
49
|
// Auto-save
|
|
51
50
|
let autoSaveTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
52
51
|
|
|
52
|
+
// Persistence backend (T0 transport). Static per session: without a Tauri
|
|
53
|
+
// host there is no file backend, and the UI must say so instead of "Saved".
|
|
54
|
+
const persistenceAvailable = isTauri();
|
|
55
|
+
|
|
53
56
|
// External change detection
|
|
54
57
|
let showExternalChangeDialog = $state(false);
|
|
55
58
|
let externalChangeCheckInterval: ReturnType<typeof setInterval> | null = null;
|
|
56
59
|
let isCheckingExternalChanges = $state(false);
|
|
60
|
+
let lastKnownMtimeMs: number | null = null;
|
|
57
61
|
|
|
58
62
|
// CodeMirror instance
|
|
59
63
|
let editorContainer: HTMLDivElement;
|
|
@@ -65,8 +69,9 @@
|
|
|
65
69
|
// Computed
|
|
66
70
|
let fileName = $derived(filePath?.split('/').pop() || filePath || 'Untitled');
|
|
67
71
|
let saveStatus = $derived(
|
|
68
|
-
isSaving ? 'Saving...' :
|
|
69
|
-
saveError ? 'Error!' :
|
|
72
|
+
isSaving ? 'Saving...' :
|
|
73
|
+
saveError ? 'Error!' :
|
|
74
|
+
filePath && !persistenceAvailable ? 'Not persisted' :
|
|
70
75
|
isDirty ? 'Unsaved' : 'Saved'
|
|
71
76
|
);
|
|
72
77
|
|
|
@@ -111,43 +116,43 @@
|
|
|
111
116
|
// Custom dark theme matching Atelier - uses CSS variables via style injection
|
|
112
117
|
const atelierTheme = EditorView.theme({
|
|
113
118
|
'&': {
|
|
114
|
-
backgroundColor: 'var(--bg-canvas)',
|
|
115
|
-
color: 'var(--text-primary)',
|
|
119
|
+
backgroundColor: 'var(--color-bg-canvas)',
|
|
120
|
+
color: 'var(--color-text-primary)',
|
|
116
121
|
fontSize: '14px',
|
|
117
122
|
fontFamily: "var(--font-mono)"
|
|
118
123
|
},
|
|
119
124
|
'.cm-content': {
|
|
120
|
-
caretColor: 'var(--accent
|
|
125
|
+
caretColor: 'var(--color-accent)',
|
|
121
126
|
padding: '16px'
|
|
122
127
|
},
|
|
123
128
|
'.cm-cursor': {
|
|
124
|
-
borderLeftColor: 'var(--accent
|
|
129
|
+
borderLeftColor: 'var(--color-accent)'
|
|
125
130
|
},
|
|
126
131
|
'.cm-activeLine': {
|
|
127
|
-
backgroundColor: 'var(--accent-subtle)'
|
|
132
|
+
backgroundColor: 'var(--color-accent-subtle)'
|
|
128
133
|
},
|
|
129
134
|
'.cm-gutters': {
|
|
130
|
-
backgroundColor: 'var(--bg-app)',
|
|
135
|
+
backgroundColor: 'var(--color-bg-app)',
|
|
131
136
|
borderRight: '1px solid var(--border-subtle)',
|
|
132
|
-
color: 'var(--text-tertiary)'
|
|
137
|
+
color: 'var(--color-text-tertiary)'
|
|
133
138
|
},
|
|
134
139
|
'.cm-activeLineGutter': {
|
|
135
|
-
backgroundColor: 'var(--accent-subtle)',
|
|
136
|
-
color: 'var(--accent
|
|
140
|
+
backgroundColor: 'var(--color-accent-subtle)',
|
|
141
|
+
color: 'var(--color-accent)'
|
|
137
142
|
},
|
|
138
143
|
'.cm-selectionBackground': {
|
|
139
|
-
backgroundColor: 'var(--accent-subtle)'
|
|
144
|
+
backgroundColor: 'var(--color-accent-subtle)'
|
|
140
145
|
}
|
|
141
146
|
}, { dark: true });
|
|
142
147
|
|
|
143
|
-
// Check for external file changes
|
|
148
|
+
// Check for external file changes (mtime-based via T0 transport)
|
|
144
149
|
async function checkExternalChanges() {
|
|
145
|
-
if (!filePath || isCheckingExternalChanges || showExternalChangeDialog || !isDirty) return;
|
|
146
|
-
|
|
150
|
+
if (!filePath || !persistenceAvailable || isCheckingExternalChanges || showExternalChangeDialog || !isDirty) return;
|
|
151
|
+
|
|
147
152
|
isCheckingExternalChanges = true;
|
|
148
153
|
try {
|
|
149
|
-
const
|
|
150
|
-
if (
|
|
154
|
+
const mtime = await getMtimeMs(filePath);
|
|
155
|
+
if (mtime !== null && lastKnownMtimeMs !== null && mtime > lastKnownMtimeMs) {
|
|
151
156
|
showExternalChangeDialog = true;
|
|
152
157
|
}
|
|
153
158
|
} catch (err) {
|
|
@@ -163,8 +168,8 @@
|
|
|
163
168
|
if (!filePath) return;
|
|
164
169
|
|
|
165
170
|
try {
|
|
166
|
-
const newContent = await
|
|
167
|
-
|
|
171
|
+
const newContent = await readTextFile(filePath);
|
|
172
|
+
|
|
168
173
|
// Update editor content
|
|
169
174
|
if (editorView) {
|
|
170
175
|
editorView.dispatch({
|
|
@@ -175,18 +180,17 @@
|
|
|
175
180
|
}
|
|
176
181
|
});
|
|
177
182
|
}
|
|
178
|
-
|
|
183
|
+
|
|
179
184
|
content = newContent;
|
|
180
185
|
isDirty = false;
|
|
181
186
|
saveError = null;
|
|
182
|
-
|
|
187
|
+
|
|
183
188
|
// Notify parent
|
|
184
189
|
onExternalChange?.(newContent);
|
|
185
190
|
onChange?.(newContent);
|
|
186
|
-
|
|
187
|
-
// Update tracked
|
|
188
|
-
|
|
189
|
-
vaultStore.updateFileState(filePath, newContent, modifiedAt);
|
|
191
|
+
|
|
192
|
+
// Update tracked modification time
|
|
193
|
+
try { lastKnownMtimeMs = await getMtimeMs(filePath); } catch { /* keep prior value */ }
|
|
190
194
|
} catch (err) {
|
|
191
195
|
console.error('Failed to reload file:', err);
|
|
192
196
|
saveError = err instanceof Error ? err.message : 'Failed to reload file';
|
|
@@ -253,7 +257,13 @@
|
|
|
253
257
|
parent: editorContainer
|
|
254
258
|
});
|
|
255
259
|
|
|
256
|
-
//
|
|
260
|
+
// Seed the tracked modification time, then start external change
|
|
261
|
+
// detection polling (every 2 seconds). Skipped without a backend.
|
|
262
|
+
if (filePath && persistenceAvailable) {
|
|
263
|
+
getMtimeMs(filePath)
|
|
264
|
+
.then((m) => { lastKnownMtimeMs = m; })
|
|
265
|
+
.catch(() => { /* file may not exist yet */ });
|
|
266
|
+
}
|
|
257
267
|
externalChangeCheckInterval = setInterval(checkExternalChanges, 2000);
|
|
258
268
|
|
|
259
269
|
// Also check when window regains focus
|
|
@@ -300,18 +310,21 @@
|
|
|
300
310
|
// Save file
|
|
301
311
|
async function saveContent() {
|
|
302
312
|
if (!isDirty || isSaving || !filePath) return;
|
|
303
|
-
|
|
313
|
+
|
|
314
|
+
// No backend → no write. The status chip reads "Not persisted"; do not
|
|
315
|
+
// mark clean or fire onSave, and never pretend the save succeeded.
|
|
316
|
+
if (!persistenceAvailable) return;
|
|
317
|
+
|
|
304
318
|
isSaving = true;
|
|
305
319
|
saveError = null;
|
|
306
|
-
|
|
320
|
+
|
|
307
321
|
try {
|
|
308
|
-
await
|
|
322
|
+
await writeTextFile(filePath, content);
|
|
309
323
|
isDirty = false;
|
|
310
324
|
onSave?.();
|
|
311
|
-
|
|
325
|
+
|
|
312
326
|
// Update tracked modification time after save
|
|
313
|
-
|
|
314
|
-
vaultStore.updateFileState(filePath, content, modifiedAt);
|
|
327
|
+
try { lastKnownMtimeMs = await getMtimeMs(filePath); } catch { /* keep prior value */ }
|
|
315
328
|
} catch (err) {
|
|
316
329
|
saveError = err instanceof Error ? err.message : String(err);
|
|
317
330
|
console.error('Failed to save file:', err);
|
|
@@ -364,7 +377,7 @@
|
|
|
364
377
|
Close
|
|
365
378
|
</button>
|
|
366
379
|
{/if}
|
|
367
|
-
{#if
|
|
380
|
+
{#if filePath && persistenceAvailable}
|
|
368
381
|
<button
|
|
369
382
|
class="action-btn primary"
|
|
370
383
|
onclick={saveContent}
|
|
@@ -437,8 +450,8 @@
|
|
|
437
450
|
display: flex;
|
|
438
451
|
flex-direction: column;
|
|
439
452
|
height: 100%;
|
|
440
|
-
background: var(--bg-canvas, #141414);
|
|
441
|
-
color: var(--text-primary, #f5f2eb);
|
|
453
|
+
background: var(--color-bg-canvas, #141414);
|
|
454
|
+
color: var(--color-text-primary, #f5f2eb);
|
|
442
455
|
}
|
|
443
456
|
|
|
444
457
|
.editor-header {
|
|
@@ -447,7 +460,7 @@
|
|
|
447
460
|
justify-content: space-between;
|
|
448
461
|
padding: 12px 16px;
|
|
449
462
|
border-bottom: 1px solid var(--border-subtle, #2a2a2a);
|
|
450
|
-
background: var(--bg-panel, #1a1a1a);
|
|
463
|
+
background: var(--color-bg-panel, #1a1a1a);
|
|
451
464
|
}
|
|
452
465
|
|
|
453
466
|
.file-info {
|
|
@@ -463,11 +476,11 @@
|
|
|
463
476
|
|
|
464
477
|
.save-status {
|
|
465
478
|
font-size: 12px;
|
|
466
|
-
color: var(--text-tertiary, #6b6b6b);
|
|
479
|
+
color: var(--color-text-tertiary, #6b6b6b);
|
|
467
480
|
}
|
|
468
481
|
|
|
469
482
|
.save-status.dirty {
|
|
470
|
-
color: var(--
|
|
483
|
+
color: var(--color-accent);
|
|
471
484
|
}
|
|
472
485
|
|
|
473
486
|
.save-status.error {
|
|
@@ -482,8 +495,8 @@
|
|
|
482
495
|
.action-btn {
|
|
483
496
|
padding: 6px 12px;
|
|
484
497
|
border: 1px solid var(--border-subtle, #2a2a2a);
|
|
485
|
-
background: var(--bg-panel-elevated, #252525);
|
|
486
|
-
color: var(--text-secondary, #a0a0a0);
|
|
498
|
+
background: var(--color-bg-panel-elevated, #252525);
|
|
499
|
+
color: var(--color-text-secondary, #a0a0a0);
|
|
487
500
|
border-radius: var(--radius-sm, 4px);
|
|
488
501
|
cursor: pointer;
|
|
489
502
|
font-size: 13px;
|
|
@@ -492,23 +505,23 @@
|
|
|
492
505
|
|
|
493
506
|
.action-btn:hover {
|
|
494
507
|
background: var(--border-subtle);
|
|
495
|
-
color: var(--text-primary, #f5f2eb);
|
|
508
|
+
color: var(--color-text-primary, #f5f2eb);
|
|
496
509
|
}
|
|
497
510
|
|
|
498
511
|
.action-btn.active {
|
|
499
|
-
background: var(--
|
|
500
|
-
color: var(--
|
|
501
|
-
border-color: var(--
|
|
512
|
+
background: var(--color-accent-subtle);
|
|
513
|
+
color: var(--color-accent);
|
|
514
|
+
border-color: var(--color-accent);
|
|
502
515
|
}
|
|
503
516
|
|
|
504
517
|
.action-btn.primary {
|
|
505
|
-
background: var(--
|
|
518
|
+
background: var(--color-accent);
|
|
506
519
|
color: white;
|
|
507
|
-
border-color: var(--
|
|
520
|
+
border-color: var(--color-accent);
|
|
508
521
|
}
|
|
509
522
|
|
|
510
523
|
.action-btn.primary:hover {
|
|
511
|
-
background: var(--accent-hover, #c9843d);
|
|
524
|
+
background: var(--color-accent-hover, #c9843d);
|
|
512
525
|
}
|
|
513
526
|
|
|
514
527
|
.action-btn:disabled {
|
|
@@ -543,7 +556,7 @@
|
|
|
543
556
|
.preview-pane {
|
|
544
557
|
border-left: 1px solid var(--border-subtle, #2a2a2a);
|
|
545
558
|
overflow-y: auto;
|
|
546
|
-
background: var(--bg-panel, #1a1a1a);
|
|
559
|
+
background: var(--color-bg-panel, #1a1a1a);
|
|
547
560
|
}
|
|
548
561
|
|
|
549
562
|
.preview-content {
|
|
@@ -564,7 +577,7 @@
|
|
|
564
577
|
}
|
|
565
578
|
|
|
566
579
|
.preview-content :global(code) {
|
|
567
|
-
background: var(--bg-panel-elevated, #252525);
|
|
580
|
+
background: var(--color-bg-panel-elevated, #252525);
|
|
568
581
|
padding: 2px 6px;
|
|
569
582
|
border-radius: var(--radius-sm, 3px);
|
|
570
583
|
font-family: var(--font-mono, 'JetBrains Mono', monospace);
|
|
@@ -572,7 +585,7 @@
|
|
|
572
585
|
}
|
|
573
586
|
|
|
574
587
|
.preview-content :global(pre) {
|
|
575
|
-
background: var(--bg-panel-elevated, #252525);
|
|
588
|
+
background: var(--color-bg-panel-elevated, #252525);
|
|
576
589
|
padding: 12px;
|
|
577
590
|
border-radius: var(--radius-md, 6px);
|
|
578
591
|
overflow-x: auto;
|
|
@@ -595,15 +608,15 @@
|
|
|
595
608
|
}
|
|
596
609
|
|
|
597
610
|
.preview-content :global(blockquote) {
|
|
598
|
-
border-left: 3px solid var(--accent
|
|
611
|
+
border-left: 3px solid var(--color-accent);
|
|
599
612
|
padding-left: 12px;
|
|
600
613
|
margin-left: 0;
|
|
601
614
|
margin-bottom: 12px;
|
|
602
|
-
color: var(--text-secondary);
|
|
615
|
+
color: var(--color-text-secondary);
|
|
603
616
|
}
|
|
604
617
|
|
|
605
618
|
.preview-content :global(a) {
|
|
606
|
-
color: var(--accent
|
|
619
|
+
color: var(--color-accent);
|
|
607
620
|
text-decoration: none;
|
|
608
621
|
}
|
|
609
622
|
|
|
@@ -630,7 +643,7 @@
|
|
|
630
643
|
}
|
|
631
644
|
|
|
632
645
|
.dialog {
|
|
633
|
-
background: var(--bg-panel, #1a1a1a);
|
|
646
|
+
background: var(--color-bg-panel, #1a1a1a);
|
|
634
647
|
border: 1px solid var(--border-subtle, #2a2a2a);
|
|
635
648
|
border-radius: var(--radius-lg, 8px);
|
|
636
649
|
min-width: 400px;
|
|
@@ -647,7 +660,7 @@
|
|
|
647
660
|
margin: 0;
|
|
648
661
|
font-size: 16px;
|
|
649
662
|
font-weight: 600;
|
|
650
|
-
color: var(--text-primary, #f5f2eb);
|
|
663
|
+
color: var(--color-text-primary, #f5f2eb);
|
|
651
664
|
}
|
|
652
665
|
|
|
653
666
|
.dialog-body {
|
|
@@ -656,7 +669,7 @@
|
|
|
656
669
|
|
|
657
670
|
.dialog-body p {
|
|
658
671
|
margin: 0 0 12px 0;
|
|
659
|
-
color: var(--text-secondary, #a0a0a0);
|
|
672
|
+
color: var(--color-text-secondary, #a0a0a0);
|
|
660
673
|
font-size: 14px;
|
|
661
674
|
line-height: 1.5;
|
|
662
675
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkdownEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/editor/MarkdownEditor.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MarkdownEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/editor/MarkdownEditor.svelte.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAGlE,UAAU,KAAK;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AA0ZH,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
2
|
+
import { render, cleanup } from '@testing-library/svelte';
|
|
3
|
+
import EditorMarkdown from './MarkdownEditor.svelte';
|
|
4
|
+
afterEach(() => {
|
|
5
|
+
cleanup();
|
|
6
|
+
});
|
|
7
|
+
describe('editor/MarkdownEditor', () => {
|
|
8
|
+
it('exports a valid Svelte component', () => {
|
|
9
|
+
expect(EditorMarkdown).toBeDefined();
|
|
10
|
+
expect(typeof EditorMarkdown).toBe('function');
|
|
11
|
+
});
|
|
12
|
+
it('renders editor container', () => {
|
|
13
|
+
const { container } = render(EditorMarkdown, {
|
|
14
|
+
filePath: null,
|
|
15
|
+
initialContent: '# Hello',
|
|
16
|
+
});
|
|
17
|
+
expect(container.querySelector('.markdown-editor')).not.toBeNull();
|
|
18
|
+
});
|
|
19
|
+
it('renders with initial content', () => {
|
|
20
|
+
const { container } = render(EditorMarkdown, {
|
|
21
|
+
filePath: null,
|
|
22
|
+
initialContent: '# Test Content',
|
|
23
|
+
});
|
|
24
|
+
// The editor mounts a CodeMirror view inside .markdown-editor
|
|
25
|
+
expect(container.querySelector('.markdown-editor')).not.toBeNull();
|
|
26
|
+
});
|
|
27
|
+
it('calls onChange when content changes', async () => {
|
|
28
|
+
const onChange = vi.fn();
|
|
29
|
+
const { container } = render(EditorMarkdown, {
|
|
30
|
+
filePath: null,
|
|
31
|
+
initialContent: 'initial',
|
|
32
|
+
onChange,
|
|
33
|
+
});
|
|
34
|
+
// The component mounts CodeMirror - onChange fires on content changes
|
|
35
|
+
// In jsdom, the CM view syncs content; at minimum the component renders
|
|
36
|
+
expect(container.querySelector('.markdown-editor')).not.toBeNull();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expansion.d.ts","sourceRoot":"","sources":["../../../src/editor/extensions/expansion.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAChC,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;CAClC;
|
|
1
|
+
{"version":3,"file":"expansion.d.ts","sourceRoot":"","sources":["../../../src/editor/extensions/expansion.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAChC,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;CAClC;AAoDD,wBAAgB,SAAS,CAAC,UAAU,CAAC,EAAE,mBAAmB,yCAqBzD"}
|
|
@@ -11,34 +11,40 @@ function buildExpansionChanges(tr, dictionary) {
|
|
|
11
11
|
return null;
|
|
12
12
|
const newDoc = tr.newDoc;
|
|
13
13
|
const changes = [];
|
|
14
|
-
tr.changes.iterChanges((_fromA, _toA,
|
|
14
|
+
tr.changes.iterChanges((_fromA, _toA, _fromB, toB, inserted) => {
|
|
15
15
|
const insertedStr = inserted.toString();
|
|
16
|
-
if (insertedStr
|
|
16
|
+
if (insertedStr.length === 0)
|
|
17
17
|
return;
|
|
18
|
-
const
|
|
19
|
-
|
|
18
|
+
const lastIdx = insertedStr.length - 1;
|
|
19
|
+
const trigger = insertedStr[lastIdx];
|
|
20
|
+
if (trigger !== ' ' && trigger !== '\t')
|
|
21
|
+
return;
|
|
22
|
+
if (insertedStr.length > 1 && /\s/.test(insertedStr[0]))
|
|
23
|
+
return;
|
|
24
|
+
const triggerPos = toB - 1;
|
|
25
|
+
const line = newDoc.lineAt(triggerPos);
|
|
26
|
+
let wordStart = triggerPos;
|
|
20
27
|
while (wordStart > line.from) {
|
|
21
28
|
const ch = newDoc.sliceString(wordStart - 1, wordStart);
|
|
22
29
|
if (/\s/.test(ch))
|
|
23
30
|
break;
|
|
24
31
|
wordStart--;
|
|
25
32
|
}
|
|
26
|
-
const precedingWord = newDoc.sliceString(wordStart,
|
|
27
|
-
const
|
|
28
|
-
if (!
|
|
33
|
+
const precedingWord = newDoc.sliceString(wordStart, triggerPos);
|
|
34
|
+
const exp = dictionary[precedingWord];
|
|
35
|
+
if (!exp)
|
|
29
36
|
return;
|
|
30
|
-
const trailingSpace = insertedStr === ' ' ? ' ' : '\t';
|
|
31
37
|
changes.push({
|
|
32
38
|
from: wordStart,
|
|
33
39
|
to: toB,
|
|
34
|
-
insert:
|
|
40
|
+
insert: exp + trigger,
|
|
35
41
|
});
|
|
36
42
|
});
|
|
37
43
|
return changes.length > 0 ? changes : null;
|
|
38
44
|
}
|
|
39
45
|
export function expansion(dictionary) {
|
|
40
46
|
const table = dictionary
|
|
41
|
-
? { ...
|
|
47
|
+
? { ...BUILT_IN_EXPANSIONS, ...dictionary }
|
|
42
48
|
: BUILT_IN_EXPANSIONS;
|
|
43
49
|
return EditorState.transactionFilter.of((tr) => {
|
|
44
50
|
const expansionChanges = buildExpansionChanges(tr, table);
|